腦圖學習 JavaScript 之犀牛書【三 · 一】資料型別

ZxBing0066發表於2019-10-24

介紹

犀牛書第三章主要講了型別、值還有變數,本篇主要講 資料型別

需要注意引用型別和非引用型別的區別、-0、NaN、八進位制、字串編碼等問題。

型別轉換部分檢視:

自我提問

  • 資料型別怎麼區分?
  • 什麼時候會觸發隱式型別轉換?
  • 浮點計算為何會丟失精度?
    0.1 + 0.2 === 0.3;
    複製程式碼
  • 字串中有什麼坑?
    var e = '?';
    console.log(e.length);
    複製程式碼
  • 0 和 -0 是否完全一樣?
    0 === -0;
    1/0 === 1/-0;
    複製程式碼

腦圖

腦圖

關鍵知識點

資料型別

資料型別主要分為兩類:

  • 原始型別(也稱為 值型別基本型別不可變型別非引用型別),原始型別包括 數字字串布林值nullundefined(以及 es6 中的 Symbol )。
  • 物件型別(也稱為 可變型別引用型別),非原始型別的所有型別均為物件型別(普通物件、陣列、函式、正則、日期等等)。

隱式型別轉化

JavaScript 會在 程式期待使用對應資料型別 的地方 自動進行型別轉換(常說的 隱式型別轉換,如將非 Boolean 型的資料放在 if 判斷條件中、使用非字串和數字進行 + 運算等)。

弱型別

JavaScript 變數是 無型別的,變數 可以賦予任何型別的值,並且 可以重新賦予不同型別的值(也就是第一章所說的 弱型別 概念)。

詞法作用域

JavaScript 採用 詞法作用域(也稱 靜態作用域,正是因為詞法作用域的緣故,才會出現閉包,在變數定義的時候,它的作用域就已經確定好了)。

IEEE 754 標準

JavaScript 中的數字採用 IEEE 754 標準,整數範圍為 -(2**53) ~ 2**53Number.MAX_SAFE_INTEGER 的值為 2**53 - 1,和這裡相差了 1,因為 超出(安全)範圍的值無法保證精度,故而最大值本身是不安全的,可能由某個失去精度的值轉換而來️)。

下面是 MDN 中的例子。

var x = Number.MAX_SAFE_INTEGER + 1;
var y = Number.MAX_SAFE_INTEGER + 2;

// 9007199254740991 9007199254740992 9007199254740992
console.log(Number.MAX_SAFE_INTEGER, x, y);
// true
console.log(x === y);
複製程式碼

實際操作基於 32 位整數

JavaScript 中的實際操作如陣列索引等 是基於 32 位整數 的。

// 4294967296
console.log(2**32);
// 安全
new Array(2**32 - 1);
// 報錯:RangeError: Invalid array length
new Array(2**32);
複製程式碼

特殊的 NaN

NaN 的意思是 Not a Number,不過 typeof NaN 是 number,所以它是一個不是(有效)數字的數字值。

由於 NaN 不等於任何值包括自身,可以使用 a !== a 來判斷 a 是不是一個 NaN 值。

八進位制

八進位制雖然大部分瀏覽器支援,但是它本身是 非標準的,在嚴格模式下 明令禁止(八進位制使用 0 作為前置標識,這會在某些地方引起歧義)。

// 9
console.log(09);
// 15
console.log(017);
// 上述都是前導 0 但是卻按照兩種進位制去進行了解析

(function() {
    'use strict';
    // 嚴格模式下會報錯:SyntaxError: Octal literals are not allowed in strict mode.
    console.log(09);
    console.log(017);
})();
複製程式碼

浮點數計算精度

JavaScript 中的浮點數計算精度問題是由於採用了 IEEE 754 浮點數表示法(大部分程式語言都是採用這個標準,所以這個問題真不是 JavaScript 的設計缺陷之類的),二進位制表示法 導致十進位制的小數無法精確的標識,所以導致一系列浮點計算的精度問題。

var a = 0.3 - 0.2;
var b = 0.2 - 0.1;
// false
console.log(a === b);
// 0.09999999999999998 0.1
console.log(a, b);
複製程式碼

這種時候建議使用整數來進行計算:

var a = (0.3 * 10 - 0.2 * 10) / 10;
var b = (0.2 * 10 - 0.1 * 10) / 10;
// true
console.log(a === b);
// 0.1 0.1
console.log(a, b);
複製程式碼

特殊的 -0

0 和 -0 並不完全對等

var a = 0, b = -0;
// 全等號會認為他們相等
console.log(a === b);
// 但是進行除法計算時將會影響計算結果 
// Infinity -Infinity false
console.log(1/a, 1/b, 1/a === 1/b);
複製程式碼

字串編碼導致的奇怪問題

JavaScript 字串是由無符號的 16 位值 組成的序列,常見的 Unicode 字元都是通過 16 位內碼錶示的,如果出現 超出範圍 的字元,將會遵循 UTF-16 編碼規則,使用 兩個 16 位值 標識,然而 JavaScript 中對字串的操作都是 基於 16 位值

// ? 遵循 UTF-16 規則,實際編碼為 '\ud83d\udc4b',在 JavaScript 中佔用兩個字元長度
var e = '?';
// 2 d83d dc4b
console.log(e.length, e.charCodeAt(0).toString(16), e.charCodeAt(1).toString(16));
// true ? ?
console.log(e === '\ud83d\udc4b', e, '\ud83d\udc4b');
複製程式碼

null 和 undefined

從語義上,null 代表 空值,undefined 代表 未定義、不存在,正常而言 null 可用來給變數賦值(清空變數等),而 很少使用 undefined 去給變數賦值

全域性變數

宣告全域性變數時變數會 成為全域性物件的一個屬性

// 定義全域性變數時 a 會直接掛載到 全域性物件下
var a = {};
//  {} {} true
console.log(a, window.a, a === window.a);
複製程式碼

系列文章目錄

  1. 腦圖學習 JavaScript 之犀牛書【一】
  2. 腦圖學習 JavaScript 之犀牛書【二】詞法結構
  3. 腦圖學習 JavaScript 之犀牛書【三 · 一】資料型別
  4. 腦圖學習 JavaScript 之犀牛書【三 · 二】型別轉換、變數
  5. 腦圖學習 JavaScript 之犀牛書【四 · 一】運算子、型別轉換
  6. 腦圖學習 JavaScript 之犀牛書【四 · 二】表示式
  7. 腦圖學習 JavaScript 之犀牛書【五】語句

相關文章