讀書筆記: JavaScript技術手冊2 - 基本語法(型別、變數、運算)
REPL
node -e "console.log('Hello World')";
> node -e "1 + 1" > node -p "1 + 1" 2
- Read-Eval-Print-Loop
.editor
.help
console.log(_);
// CMD > node > 'Hello World' Hello World > console.log(_) Hello World undefined
Data Type 資料型態與變數
- JavaScript 屬於動態定型語言
- 靜態定型(statically-typed):型態資訊記錄在變數
- 動態定型(dynamically-typed):型態資訊要從執行時期的物件取得
- Duck typing 鴨子定型
- 變數宣告:
let
、const
、var
- Primitive type:變數儲存被指定的值
- Composite type:變數永遠只是個參考至物件的名稱
- 所以以下情況成立
// const 只是不能重新指定陣列變數名稱,陣列本身是mutable const arr=[1, 2, 3]; arr[1] = 10; // [10, 2, 3];
- 所以以下情況成立
- Hoisting
var
變數在未被宣告前使用會被賦值undefined
let
也會有 Hoisting 行為,但不會被賦值undefined
,所以變數在完全沒有值的情況下存取就會出錯。
- strict mode (嚴格模式)
.js
檔案開頭寫use strict
- 避免一些模糊不清的奇怪部分跑出來
- 例如
- 沒有用關鍵字宣告的變數,不管在哪裡被賦值都會變成全域變數
- 保留字不能當變數名稱
Primitive
- number
- string
- boolean
- undefined
- null
- Symbol
number
- \ 64bit float only
- 執行時期都是以浮點數表示
- 不同進位的 10 表示法
10 0xA 0o12 0b1010
- 字串剖析為數字
Number('10');
parseInt()
,parseFloat()
(※無法處理0b
,0o
,0x
)
最大值、最小值與安全範圍
Number.MIN_VALUE Number.MAX_VALUE Number.MIN_SAFE_INTEGER Number.MAX_SAFE_INTEGER Number.isInteger() Number.isSafeInteger(9007199254740991) // true Number.isSafeInteger(9007199254740992) // false
- 運算
1 / 0 // Infinity 1 / 0 === Infinity // true Infinity === Number.POSITIVE_INFINITY // true -Infinity === Number.NEGATIVE_INFINITY // true
NaN
- 開發避免
NaN
的解決方法之一就是避免JS的自動型別轉換0 / 0 // NaN NaN === NaN // false NaN === Number.NaN // false
- 開發避免
string
- Immutable
- empty string:
''
,\0
,\x00
- 字串字元數計算問題
- 碼點(code point):
\uD834\uDD1E
、u{1D11E}
- 碼元(code unit):
\uD834
- 字串元素單位:UTF-16碼元
- 要注意字元碼點是否超出[U+0000, U+FFFF],若字元碼點
- 在[U+0000, U+FFFF]內:
.length
===字元數量(因為UCS-2系統是2bytes為一個碼元) - 超出[U+0000, U+FFFF]:
.length
===碼元數量 \u{1D22E}
: 𝄞 (1字元)\u{1D22E}.length
=== 2
- 在[U+0000, U+FFFF]內:
- 正確取得某個字元的方法
// '\uD834\uDD1E'==='u{1D11E}' '\u{1D11E}'.charAt(0) // '\uD834' '\u{1D11E}'.codePointAt(0) // 119070 String.fromCodePoint(119070) // 'u{1D11E}'
- 字元超出[U+0000, U+FFFF]取得字元數的方法
Array.from('\u{1D11E}').length // 1
- 碼點(code point):
undefined
typeof undefined
// 'undefined'- 不是保留字,可以用
void
避免這種狀況let undefined = 10; console.log(undefined); // ok
null
- 表示沒有物件
- 例如參考至某物件的變數沒有參考對象,就可以賦值
null
達成這個目的。
- 例如參考至某物件的變數沒有參考對象,就可以賦值
typeof null
// object
Composite 複合型態
Object
- Object individuation:
delete
in
operator 可檢查物件是否有此屬性名稱- 存取物件沒有的屬性 →
return undefined;
但要避免將物件的屬性值設定為
undefined
let obj = {x: undefined}; console.log(x); // undefined console.log('x' in obj); // true
-
this
關鍵字最基本用法:參考至
.
operator 左邊的物件function forEach(callback){ for(let i = 0; i < this.length; ++i){ callback(this[i]); } } let arrayLikeObj = { '0': 100, '1': 200, '2': 300, length: 3, forEach: forEach } obj.forEach(function(elem){ console.log(elem); });
this
參考對象其實會以呼叫方式而定,並非以是否附屬於某個物件而定。
Array
typeof [];
// object- JavaScript的陣列產生方式不是預先在記憶體佔據連續的線性空間
- 比較像是以數字作為key的物件
let array = [10, 20, 30]; console.log(array['1']); // 10
- 比較像是以數字作為key的物件
- 類陣列物件:所以其實可以用物件模擬陣列(※這是用Object instance創建的陣列,並非真正的Array)
// array-like consecutive objects let arrayLikeObject = { '0': 10, '1': 20, '2': 30, length: 3 };
Array.from();
可以把類陣列物件(e.g., string)轉換成真正的ArrayArray.from(arrayLikeObject); // [10, 20, 30] Array.from("lun"); // ['l', 'u', 'n']
- 改變
Array.length
的值不會擴充 Array,只有改變length
的值同時產生 empty items (空項目) 要避免陣列產生 empty items (容易有 bug),因為多出來的
empty items
不會有索引:let arr1 = [undefined, undefined]; let arr2 = []; arr2.length = 2; console.log('0' in arr1); // true console.log('0' in arr2); // false
forEach()
、filter()
也會跳過 empty items 且不會顯示結果;map()
雖然也會跳過 empty items 卻會顯示在結果:[,,].forEach(elem => console.log(elem)); // [,,].filter(elem=>true); // [,,].map(elem=>1); // [<2 empty items>]
運算
- +、-、*、/、** 不要用在number和string以外的型態
[] + []; // '' [] + {}; // '[object Object]' {} + []; // 0 {} + {}; // NaN
===
、!==
===
- Primitive type: 比較兩個變數儲存的值和型態
- Composite type: 比較兩個變數是否參考至同一物件
- 不要再用
==
和!=
'' == 0; // true null == undefined; // true 1 == true; // true
- ECMAScript 6 相等性
- Falsy value
- false
- ''
- 0、'0'
- NaN
- null
- undefined
捷徑運算
'left' && 'right' // 'right' 0 && 'right' // 0 'left' && 0 // 0 // 常用範例: 預設值 let name = ''; alert(name || 'Guest'); // 'Guest' 為預設值
(逐)位元運算
// 2's component 0b10010001 & 0b01000001 // 00000001 -> 十進位: 1 0b0011 // 3 ~0b0011 // -4 0b1111 // 15 ~0b1111 // -16
- others
- 指定運算子
- 遞增/遞減運算子
in
確認物件是否包含某個屬性(不考慮可否列舉且也會列出繼承的屬性)// length, toString are non-enumerable 'length' in []; // true 'toString' in {} // true
hasOwnProperty()
只會列出物件本身擁有的屬性[].hasOwnProperty('length'); // true {}.hasOwnProperty('toString'); // false
instanceof
References