介紹
犀牛書第四章主要講解了關於 JavaScript 中的 表示式 和 運算子。
本篇主要說以下 運算子 和 運算子相關的型別轉換 部分。
資料型別和型別之間的轉換規則請檢視:
自我提問
- ==、+、關係運算子等運算時怎麼進行型別轉換的?
- eval 使用的幾種方式?
eval('some code'); var geval = eval; geval('some code'); 'use strict'; eval('some code'); 複製程式碼
- 運算子的優先順序和結合性?
- 什麼是左值?
腦圖
關鍵知識點
關係運算子
關係運算子 總是會返回一個布林值。
== 運算子的型別轉換規則
== 運算子在進行判斷時會對運算元進行隱式型別轉換,按照以下步驟進行判斷
- 運算元型別相同時,不進行型別轉換,套用 === 運算子的結果
- 運算元為 null 和 undefined 時,返回 true
- 運算元為數字和字串時,將字串轉換為數字後進行比較
- 其中一個運算元為布林值時,將布林值轉換為數字後進行比較
- 其中一個運算元為物件時,按照之前說過的物件到原始值的轉換規則
- 都不滿足,返回 false
1 == 2 // false
null == undefined // true
123 == '123' // true
true == '1' // true
({
valueOf: () => {
console.log('valueOf');
return {};
},
toString: () => {
console.log('toString');
return '123';
}
}) == 123; // valueOf toString true
({
valueOf: () => {
console.log('valueOf');
return 123;
},
toString: () => {
console.log('toString');
return '123';
}
}) == '123'; // valueOf true
NaN == NaN; // false
複製程式碼
比較運算子的轉換規則
比較運算子(>, <, >=, <=)在進行運算時會按照以下規則進行判斷:
- 運算元為物件時,物件會按照之前說過的物件到原始值的轉換規則進行轉換
- 其中一個運算元為 NaN 時,總是返回 false
- 運算元均為字串時,進行字母表比較(編碼比較)
- 有一個非字串時,運算元會轉換為數字進行比較
<= 實際為 不大於(a >= b ==> !(a < b),排除 NaN)、>= 實際為 不小於(a <= b ==> !(a > b),排除 NaN),不依賴與相等運算子的比較規則。
+ 運算子
+ 運算子 依賴於運算元,如果一個運算元為字串或者轉換為原始值後為字串,會將另一個運算元作為字串進行拼接。否則將進行數值加法計算。
++ --
++ -- 運算子依賴於運算元的位置,運算子在運算元前時為 前增量,返回計算後的值,運算子在運算元後是為 後增量,返回計算前的值。
++ -- 運算子的運算元 只會被轉換為數字。
位運算子
位運算子會 將運算元轉換為數字,NaN、Infinity、-Infinity 會被轉換為 0。
位運算子針對 32 位整形,會 忽略小數點和超出 32 位的二進位制位。
eval
直接 eval 會在呼叫它的上下文作用域下執行,會 影響到呼叫的作用域。
間接 eval 會在 全域性上下文進行執行,不會影響呼叫的作用域。
嚴格模式下 eval 可以讀寫區域性變數,但是不能新增區域性變數、函式。
&& || ?:
&& 和 || 可用來進行 程式碼短路。
?: 可 實現類似 if 的作用。
true && console.log(123); // 123
false && console.log(123); //
true || console.log(123); //
false || console.log(123); // 123
true ? console.log(123) : console.log(456); // 123
false ? console.log(123) : console.log(456); // 456
複製程式碼
運算子優先順序
這裡套用一下 MDN 上的運算子優先順序表格
運算子的 優先順序決定了在複雜表示式運算過程中,運算的先後順序。
從上往下優先順序越低,最高的是括號,然後是屬性訪問、物件建立等,最後是賦值運算子、yield、逗號運算子。
a = 1 * 2 - 1
// 按照運算子的優先順序,會先計算 1 * 2 得出 2,然後計算 2 - 1 得出 1,然後將 1 賦值給 a
複製程式碼
運算子結合性
表格的第三行定義了列出了各運算子的結合性,可以看看 MDN 上關於結合性的定義,結合性決定了相同的運算子之間的計算順序。
Associativity determines the way in which operators of the same precedence are parsed.
1 / 2 / 3
// 按照 / 的結合性從左往右,等價於
(1 / 2) / 3
a = b = c
// 按照 = 的結合性從右往左,等價於
a = (b = c)
複製程式碼
運算子運算元個數
每個運算子所需要的的運算元個數不同,+ 運算子需要 1 個或 2 個運算元,?: 需要三個運算元,根據運算元的數量,可以將運算子分類成 一元運算子、二元運算子、三元運算子。
運算順序
一個 複雜表示式的運算順序和運算子的優先順序、結合性相關。 而子表示式在計算中總是按照從左往右的順序計算表示式的。 具體看最下方。
運算元型別、結果型別
運算子對運算元進行計算時會 將運算元轉換為想要的型別(隱式型別轉換)。
左值
左值 指表示式 只能出現在賦值運算子的左側,包括變數、物件屬性、陣列元素。
關於左值概念提及的較少,具體解釋一下,左值和右值的區別,當一個變數、物件屬性、陣列元素出現在賦值運算子的左邊時,取的是他的左值,可以認為取出的是他的記憶體地址,而出現在右邊是取的是他的右值也就是他的實際值,可以使用 getter 試試,左值出現在左邊時,getter 不會被觸發,因為左值不關心他的實際值,只關心他的地址。
var a = {
get b() {
console.log('get');
return 123;
}
};
// get 被列印,取出右值
var c = a.b;
// get 未被列印,取出左值
a.b = 1;
複製程式碼
除了賦值運算子,還有 delete 運算子的運算元也是左值。
運算子的副作用
部分運算子帶有 副作用,如 delete、賦值運算子、++、--。