重學前端學習筆記(六)--JavaScript類型有哪些你不知道的細節?

筆記說明

重學前端是程劭非(winter)【前手機淘寶前端負責人】在極客時間開的一個專欄, 天天10分鐘,重構你的前端知識體系,筆者主要整理學習過程的一些要點筆記以及感悟,完整的能夠加入winter的專欄學習【原文有winter的語音】,若有侵權請聯繫我,郵箱:kaimo313@foxmail.com。

JavaScript類型有哪些你不知道的細節?

winter提了幾個問題測試:能回答對幾個?

  • 一、爲何有的編程規範要求用 void 0 代替 undefined?
  • 二、字符串有最大長度嗎?
  • 三、0.1 + 0.2 不是等於 0.3 麼?爲何 JavaScript 裏不是這樣的?
  • 四、ES6 新加入的 Symbol 是個什麼東西?
  • 五、爲何給對象添加的方法能用在基本類型上?
若是有點猶豫,不妨看看下面的介紹,或者找找資料溫習一下。

類型

  1. Undefined
  2. Null
  3. Boolean
  4. String
  5. Number
  6. Symbol
  7. Object

一、Undefined、Null

Undefined:前端

  • Undefined 類型表示未定義,它的類型只有一個值,就是 undefined
  • 任何變量在賦值前是 Undefined 類型、值爲 undefined
  • JavaScript 的代碼 undefined 是一個變量,而並不是是一個關鍵字,這是 JavaScript 語言公認的設計失誤之一
  • 爲了不無心中被篡改,可使用 void 0 來獲取 undefined 值。

Null:java

  • Null 類型也只有一個值,就是 null,它的語義表示空值
  • 與 undefined 不一樣,null 是 JavaScript 關鍵字
  • 在任何代碼中,均可以用 null 關鍵字來獲取null值

二、String

  • String 用於表示文本數據
  • String 有最大長度是 2^53 - 1
  • 字符串的最大長度,其實是受字符串的編碼長度影響的。
Note: 現行的字符集國際標準,字符是以 Unicode 的方式表示的,每個 Unicode 的碼點表示一個字符,理論上,Unicode 的範圍是無限的。UTF 是 Unicode 的編碼方式,規定了碼點在計算機中的表示方法,常見的有 UTF16 和 UTF8。Unicode 的碼點一般用 U+??? 來表示,其中 ??? 是十六進制的碼點值。0-65536(U+0000 - U+FFFF)的碼點被稱爲基本字符區域(BMP)。

三、Number

  • JavaScript 中的 Number 類型有 18437736874454810627(即 2^64-2^53+3) 個值
  • NaN,佔用了 9007199254740990,這本來是符合 IEEE 規則的數字
  • Infinity,無窮大
  • -Infinity,負無窮大
  • 根據雙精度浮點數的定義,Number 類型中有效的整數範圍是-0x1fffffffffffff 至 0x1fffffffffffff,因此 Number 沒法精確表示此範圍外的整數
  • 根據浮點數的定義,非整數的 Number 類型沒法用 ==(=== 也不行)來比較

關於javaScript中 0.1 + 0.2 == 0.3 ? 這個問題的解釋:git

console.log( 0.1 + 0.2 == 0.3);
>> false

輸出結果爲false,說明兩邊不相等,這是浮點運算特色致使的,實際上,這裏錯誤的不是結論,而是比較的方法,正確的比較方法是使用javaScript提供的最小精度值:es6

咱們能夠查找MDN文檔的Number能夠找到屬性EPSILONgithub

Number.EPSILON:兩個可表示數字之間的最小間隔
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
>> true

這樣的比較輸出結果爲true檢查等式左右兩邊差的絕對值是否小於最小精度,纔是正確的比較浮點數的方法編程

四、Symbol

關於Symbol的介紹,我準備用ES6文檔-阮一峯來作一些介紹,具體的能夠參考文檔函數

4.一、ES6 引入Symbol的緣由

ES5 的對象屬性名都是字符串,這容易形成屬性名的衝突。ES6引入了一種新的原始數據類型Symbol,表示獨一無二的值。從根本上防止屬性名的衝突。

4.二、介紹

凡是屬性名屬於 Symbol 類型,就都是獨一無二的,能夠保證不會與其餘屬性名產生衝突。

4.2.一、Symbol 值經過Symbol函數生成,先來一段代碼:學習

let s = Symbol();
typeof s
>> "symbol"

上面代碼中,變量s就是一個獨一無二的值。sSymbol數據類型。測試

4.2.二、Symbol函數能夠接受一個字符串做爲參數,表示對 Symbol 實例的描述this

let s1 = Symbol('foo');
let s2 = Symbol('bar');

s1
>> Symbol(foo)
s2
>> Symbol(bar)

s1.toString()
>> "Symbol(foo)"

s2.toString()
>> "Symbol(bar)"

上面代碼中,s1s2是兩個 Symbol 值。若是不加參數,它們在控制檯的輸出都是Symbol(),不利於區分。有了參數之後,就等於爲它們加上了描述,輸出的時候就可以分清,究竟是哪個值。

4.2.三、若是 Symbol 的參數是一個對象,就會調用該對象的toString方法,將其轉爲字符串,而後才生成一個 Symbol 值。

const obj = {
    a: '123123',
    toString() {
        return 'iuoisigud';
    }
};
const sym = Symbol(obj);

sym // Symbol(iuoisigud)

4.2.四、Symbol函數的參數只是表示對當前 Symbol 值的描述,所以相同參數的Symbol函數的返回值是不相等的。

// 沒有參數的狀況
let s1 = Symbol();
let s2 = Symbol();

s1 === s2 // false

// 有參數的狀況
let s1 = Symbol('foo');
let s2 = Symbol('foo');

s1 === s2 // false

4.2.五、Symbol 值不能與其餘類型的值進行運算,會報錯。

let sym = Symbol('My symbol');

"your symbol is " + sym
// TypeError: can't convert symbol to string
`your symbol is ${sym}`
// TypeError: can't convert symbol to string

4.2.六、Symbol 值能夠顯式轉爲字符串,也能夠轉爲布爾值,可是不能轉爲數值。

let sym = Symbol('My symbol');

String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'

let sym = Symbol();
Boolean(sym) // true
!sym  // false

Number(sym) // TypeError
sym + 2 // TypeError

4.2.七、其餘的一些屬性能夠去看ES6文檔-阮一峯

4.三、注意

Symbol函數前不能使用 new命令,不然會報錯。這是由於生成的 Symbol 是一個原始類型的值,不是對象。也就是說,因爲 Symbol 值不是對象,因此不能添加屬性。基本上,它是一種相似於 字符串的數據類型

五、Object

Object 是 JavaScript 中最複雜的類型,也是 JavaScript 的核心機制之一。

爲何給對象添加的方法能用在基本類型上?

回答:「運算符提供了裝箱操做,它會根據基礎類型構造一個臨時對象,使得咱們能在基礎類型上調用對應對象的方法。」

好比原型上添加方法,也能夠應用於基本類型:

Symbol.prototype.hello = () => console.log("hello");

var a = Symbol("a");
console.log(typeof a); //symbol,a 並不是對象
a.hello(); //hello,有效

六、類型轉換

6.一、臭名昭著的「 == 」運算

  • 由於 JS 是弱類型語言,因此類型轉換髮生很是頻繁
  • 「 == 」試圖實現跨類型的比較,它的規則複雜到幾乎沒人能夠記住。

6.二、轉換規則

轉換規則

6.三、StringToNumber

字符串到數字的類型轉換,存在一個語法結構,類型轉換支持十進制、二進制、八進制和十六進制

好比:

Number('0xFF')
>> 255

6.四、裝箱轉換

裝箱(boxing):值類型實例到對象的轉換,它暗示在運行時實例將攜帶完整的類型信息,並在堆中分配。

每一種基本類型 NumberStringBooleanSymbol 在對象中都有對應的類,所謂裝箱轉換,正是把基本類型轉換爲對應的對象,它是類型轉換中一種至關重要的種類。

例子:利用一個函數的 call 方法來強迫產生 Symbol裝箱
var symbolObject = (function() {
    return this;
}).call(Symbol("a"));

console.log(typeof symbolObject); //object
console.log(symbolObject instanceof Symbol); //true
console.log(symbolObject.constructor == Symbol); //true
例子:使用內置的 Object 函數,咱們能夠在 JavaScript 代碼中顯式調用裝箱能力。
var symbolObject = Object(Symbol("a"));

console.log(typeof symbolObject); //object
console.log(symbolObject instanceof Symbol); //true
console.log(symbolObject.constructor == Symbol); //true
每一類裝箱對象皆有私有的 Class 屬性,這些屬性能夠用 Object.prototype.toString 獲取:
var symbolObject = Object(Symbol("a"));

console.log(Object.prototype.toString.call(symbolObject));
>> [object Symbol]

6.五、拆箱轉換

拆箱(unboxing):是將引用類型轉換爲值類型

6.5.一、在 JavaScript 標準中,規定了 ToPrimitive 函數,它是對象類型到基本類型的轉換

toPrimitive(input, preferedType)

input是輸入的值,preferedType是指望轉換的類型,它能夠是字符串,也能夠是數字。

inputType Result
Undefined input argument
Null input argument
Boolean input argument
Number input argument
String input argument
Object 忽略 第二個參數 hint PreferredType 直接調用內置方法 [[DefaultValue]]

6.5.二、若是轉換的類型是number,會執行如下步驟:參考博客

  1. 若是input是原始值,直接返回這個值;
  2. 不然,若是input是對象,調用input.valueOf(),若是結果是原始值,返回結果;
  3. 不然,調用input.toString()。若是結果是原始值,返回結果;
  4. 不然,拋出錯誤。

6.5.三、若是轉換的類型是String,2和3會交換執行,即先執行toString()方法。

例子1:先將兩個操做數轉換爲string,而後進行拼接

[] + []
>> ""

[] -----> ''
[] -----> ''

[] + [] = ''

例子2:先將兩個操做數轉換爲string,而後進行拼接

[] + {}
>> "[object Object]"

// 解釋
[] -----> ''
{} -----> '[object Object]'

[] + {} = '[object Object]'

例子3:js解釋器會將開頭的 {} 看做一個代碼塊,而不是一個js對象

{} + []
>> 0

// 真正參與運算的是 + []
// {} + [] 等價於 + []

七、規範類型

  • List 和 Record: 用於描述函數傳參過程。
  • Set:主要用於解釋字符集等。
  • Completion Record:用於描述異常、跳出等語句執行過程。
  • Reference:用於描述對象屬性訪問、delete 等。
  • Property Descriptor:用於描述對象的屬性。
  • Lexical Environment 和 Environment Record:用於描述變量和做用域。
  • Data Block:用於描述二進制數據。

八、補充閱讀

typeof 的運算結果,與運行時類型的規定有不少不一致的地方(typeof 的設計是有缺陷的)

補充閱讀

我的總結

在整理知識點的時候,我就發現,我多是真的划水醬_(:3」∠)_,裏面大部分的東西很模糊,有點都不清不楚的,還有的沒有聽過,看來要好好打打基礎了,如今前端的發展過於太快了,而本身的基礎又不牢固,能跟着winter學習是個人幸運,不過在這裏要感謝一個大佬的推薦,stormzhang,公衆號也是這個,個人學習榜樣來的,哈哈哈哈哈。

相關文章
相關標籤/搜索