文章目錄
關於類型的細節
關於Javascript的類型,各種文檔介紹的已經很全面了,也是前端開發人員最熟悉的概念之一,但如果對下面的幾個問題還有猶豫,說明對於類型這部分知識點,還是有遺漏部分的。
爲什麼有的編程規範要求用 void 0 代替 undefined?
字符串有最大長度嗎?
String有最大長度2^53-1
,但是這個所謂的最大長度並不是字符數。
String的意義並非“字符串”,而是字符串的UTF16編碼,字符串操作charAt
, charCodeAt
, length
等方法針對的都是UTF16編碼,所以字符串的最大長度,實際上是受字符串的編碼長度影響的。
JavaScript 中的字符串是永遠無法變更的,一旦字符串構造出來,無法用任何方式改變字符串的內容,所以字符串具有值類型的特徵。
0.1 + 0.2 ≠ 0.3 ?
Javascript的Number類型表示通常意義上的“數字”。大致對應數學中的有理數,但是計算機有精度限制。
avaScript 中的 Number 類型基本符合 IEEE 754-2008 規定的雙精度浮點數規則。(Javascript並未定義不同類型的數字數據類型,而是始終將數字存儲爲雙精度浮點值)
根據雙精度浮點數的定義,Number 類型中有效的整數範圍是 -0x1fffffffffffff 至 0x1fffffffffffff,所以 Number 無法精確表示此範圍外的整數。
同樣根據浮點數的定義,非整數的 Number 類型無法用 ==
(===
也不行) 來比較。
console.log( 0.1 + 0.2 == 0.3); //false
對於計算機而言,兩個數字在相加時是以二進制形式進行的,在呈現結果時才轉換成十進制。所以在計算0.1+0.2
時,會先把兩個數字轉換爲二進制數字,轉二進制的時候如果尾數的52位不能完全滿足,只會達到要求的精度。
// 0.1 轉化爲二進制
0.0 0011 0011 0011 0011...(0011無限循環)
// 0.2 轉化爲二進制
0.0011 0011 0011 0011 0011...(0011無限循環)
//由於雙精度表示法的尾數只有52位,0.1和0.2轉換後的值爲
e = -4; m =1.1001100110011001100110011001100110011001100110011010 (52位)
e = -3; m =1.1001100110011001100110011001100110011001100110011010 (52位)
兩個二進制相加的結果爲:
//相加時如果指數不一致,需要對齊,一般情況下是向右移,因爲最右邊的即使溢出了,損失的精度遠遠小於左邊溢出。
(e = -3; m = 0.1100110011001100110011001100110011001100110011001101)
+ (e = -3; m = 1.1001100110011001100110011001100110011001100110011010)
= (e = -3; m = 10.0110011001100110011001100110011001100110011001100111)
= (e = -2; m = 1.0011001100110011001100110011001100110011001100110100)
= 0.010011001100110011001100110011001100110011001100110100
= 0.30000000000000004 //(十進制)
浮點數運算的精度問題導致等式左右的結果並不是嚴格相等,而是相差了個微小的值0.30000000000000004
與0.3
。
用Javascript提供的最小精度值比較可得到結果爲true
:
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
ES6 新加入的 Symbol 是個什麼東西?
Symbol 是 ES6 中引入的新類型,它是一切非字符串的對象 key 的集合,在 ES6 規範中,整個對象系統被用 Symbol 重塑。Symbol 可以創建一個獨一無二的值(但並不是字符串)。
Symbol 可以具有字符串類型的描述,但是即使描述相同,Symbol 也不相等。
創建Symbol的方式是使用全局的Symbol函數。
var mySymbol = Symbol("my symbol");
爲什麼給對象添加的方法能用在基本類型上?
在Javascript中,對象的定義是“屬性的集合”,屬性分爲數據屬性和訪問器屬性,二者都是key-value結構,key可以是字符串或Symbol類型。
Javascript的基本類型,都在對象類型中有一個“親戚”,分別是Number,String,Boolean,Symbol,所以3
與new Number(3)
是完全不同的值,一個是Number類型,一個時對象類型。
Javascript的.
運算符提供了裝箱操作,會根據基礎類型構造一個臨時的對象,使得我們能在基礎類型上調用對應對象的方法。
所謂裝箱轉換,就是把基本類型轉換爲對應的對象,它是類型轉換中相當重要的種類。
Javascript對象
對 JavaScript 來說,屬性並非只是簡單的名稱和值,JavaScript 用一組特徵(attribute)來描述屬性(property)。
數據屬性:
它比較接近於其它語言的屬性概念。數據屬性具有四個特徵。
- value:就是屬性的值。
- writable:決定屬性能否被賦值。
- enumerable:決定 for in 能否枚舉該屬性
- configurable:決定該屬性能否被刪除或者改變特徵值。在大多數情況下,我們只關心數據屬性的值即可。第
訪問器(getter/setter)屬性,它也有四個特徵: - getter:函數或 undefined,在取屬性值時被調用
- setter:函數或 undefined,在設置屬性值時被調用
- enumerable:決定 for in 能否枚舉該屬性
- configurable:決定該屬性能否被刪除或者改變特徵值。
Javascript的對象分爲幾類: - 宿主對象(host Objects):由 JavaScript 宿主環境提供的對象,它們的行爲完全由宿主環境決定。(如window對象)
- 內置對象(Built-in Objects):由 JavaScript 語言提供的對象。
- 固有對象(Intrinsic Objects ):由標準規定,隨着 JavaScript 運行時創建而自動創建的對象實例。
- 原生對象(Native Objects):可以由用戶通過 Array、RegExp 等內置構造器或者特殊語法創建的對象。
- 普通對象(Ordinary Objects):由{}語法、Object 構造器或者 class 關鍵字定義類創建的對象,它能夠被原型繼承。
Javascript執行
異步執行的順序:
- 首先我們分析有多少個宏任務;
- 在每個宏任務中,分析有多少個微任務;
- 根據調用次序,確定宏任務中的微任務執行次序;
- 根據宏任務的觸發規則和調用次序,確定宏任務的執行次序;
- 確定整個順序。