先來看一個範例
4 / 2 * 2 + 2 //6
這段程式碼執行下來答案是 6 ,很符合我們對數學先乘除後加減的概念。
但在 JavaScript 中還有其他運算子,扣掉我們較熟悉的算數使用的算數運算子,如何知道其他運算子的使用順序呢?
在 MDN 文件中就有提供相關的表格。
在文件中我們可以看到 +
號算數運算子優先性是 13 ,*
跟 /
除,是 14 ,因此也會是我們熟知的先乘除後加減,但 JS 是怎麼判斷範例中先 /
後 *
呢?
這時就要介紹運算子另一個特性,『相依性』,而相依性的特性就是,如果運算子是相同優先性,那麼 JavaScript 會根據設定,從指定方向開始執行,從文件上也可以看到 *
跟 /
的算數運算子是 『從左至右』。
再來看看一個滿常見的前端面試問題:
1 < 2 < 3 // true
答案是 true
跟我理解一般理解的一樣,那麼稍微調整一下順序:
3 > 2 > 1 //false
這時就變成 false 了,這是因為相依性的特性,會讓上面範例在執行整段程式碼是分開的,會先執行 3 > 2
接者才會執行 2 > 1
。
但上面的說法其實不太正確, 3 > 2
這段是表達式,而表達式的特性就是會回傳值。3 > 2
這段表達式回傳的會是 true
,因此實際上會是 true > 1
,而不是我們原先認為的 2 > 1
。
所以上面這一段在 JavaScript 中是這樣的:
3 > 2
true > 1
( true 會隱含轉型變成 1 , 1 > 1
因此最後回傳 false
)
再來根據表達式特性再提一個賦值狀況:
var a = 1;
var b = 2;
a = b = 3;
結果我們查詢 a 、 b 值都會是 3
在我們看來會是他的執行順序會是:
var a = 1;
var b = 2;
b = 3;
a = b
但要注意這個執行順序並不正確,這邊實際上的情況是:
b = 1
時,因為這段是表達式,所以會回傳 1
,接者才是 a
被賦予回傳的 1
所以 a
被賦予的實際上是 b = 1
回傳的值。
我們可以使用 Object.defineProperty()
鎖定物件屬性中的值 來驗證這個觀念:
var obj = {};
Object.defineProperty(obj, 'test', {
value: 0,
writable: false,
})
這個寫法會綁定物件 obj
中 test
屬性的值,接者新增一個變數來替換 obj
中的 test
:
var obj = {};
Object.defineProperty(obj, 'test', {
value: 0,
writable: false,
})
var num = 1
obj.test = num
obj.test //0
確認 obj.test
是無法被更改的,接著使用連續賦值的動作看看結果如何:
var obj = {};
Object.defineProperty(obj, 'test', {
value: 0,
writable: false,
})
var num = 1
num = obj.test = 5566
console.log(num,obj.test) // ???
結果回傳的是 5566
和 0
,這是因為 5566
雖然沒有成功賦予到 obj.test
上,但是 obj.test = 5566
這段表達式會回傳 5566
,因此 num
最後是獲得這個回傳的 5566
。