??
:空值合并運算符es2020
??
是一個邏輯操作符虎谢,當(dāng)左側(cè)的操作數(shù)為null
或者undefined
時酬诀,返回其右側(cè)操作數(shù),否則返回左側(cè)操作數(shù)瞒御。
與邏輯或操作符||
不同,邏輯或操作符會在左側(cè)操作數(shù)為假值
時返回右側(cè)操作數(shù)肴裙。也就是說,如果使用 ||
來為某些變量設(shè)置默認(rèn)值蜻懦,可能會遇到意料之外的行為。
比如為假值(例如宛乃,''
或 0
)時带欢。見下面的例子:
const foo = null ?? 'default string'
console.log(foo) // "default string"
const baz = 0 ?? 42
console.log(baz) // 0
const bar = false ?? true
console.log(bar) // false
注意
:??
不能與 &&
或 ||
操作符共用
null || undefined ?? "foo" // 拋出 SyntaxError
true || undefined ?? "foo" // 拋出 SyntaxError
但是
乔煞,如果使用括號來顯式表明運算優(yōu)先級,是沒有問題的:
(null || undefined ) ?? "foo" // 返回 "foo"
?.
:可選鏈操作符es2020
可選鏈操作符
?.
允許讀取位于連接對象鏈深處的屬性的值渡贾,而不必明確驗證鏈中的每個引用是否有效。
?.
操作符的功能類似于.
鏈?zhǔn)讲僮鞣塾遥煌幵谟冢谝脼榭罩狄词?null
要么是undefined
的情況下不會引起錯誤擂仍,該表達式短路返回值是undefined
。與函數(shù)調(diào)用一起使用時逢渔,如果給定的函數(shù)不存在,則返回undefined
。
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
}
const dogName = adventurer.dog?.name
console.log(dogName) // undefined
console.log(adventurer.someNonExistentMethod?.()) // undefined
console.log(adventurer.list?.forEach(() => {})) // undefined
對比一下代碼
const obj = {}
let nestedProp = obj.first?.second
這等價于以下表達式诲泌,但實際上沒有創(chuàng)建臨時變量:
const obj = {}
let temp = obj.first
let nestedProp = ((temp === null || temp === undefined) ? undefined : temp.second)
可選鏈與函數(shù)調(diào)用
當(dāng)嘗試調(diào)用一個可能不存在的方法時也可以使用可選鏈。
- 函數(shù)調(diào)用時如果被調(diào)用的方法不存在铣鹏,使用可選鏈可以使表達式自動返回
undefined
而不是拋出一個TypeError
。
const someInterface = {}
let result = someInterface.customMethod?.()
可選鏈和表達式
當(dāng)使用方括號與屬性名的形式來訪問屬性時诚卸,你也可以使用可選鏈操作符:
let list = null
console.log(list?.[1]) // undefined
注意
- 如果存在一個屬性名且不是函數(shù), 使用
?.
仍然會產(chǎn)生一個TypeError
異常
const someInterface = { customMethod: 'Not Method' } let result = someInterface.customMethod?.(); // Uncaught TypeError: someInterface.customMethod is not a function
- 如果
someInterface
自身是null
或者undefined
, 仍然會產(chǎn)生一個TypeError
異常合溺,如果你希望允許someInterface
也為null
或者undefined
,那么你需要像這樣寫:
let someInterface = null someInterface?.customMethod?.() // undefined
逗號運算符間接函數(shù)調(diào)用
先介紹一下逗號運算符
逗號運算符
對它的每個操作數(shù)求值(從左到右)辫愉,并返回最后一個操作數(shù)的值将硝。
let x = 1
x = (x++, x)
console.log(x) // 2
x = (2, 3)
console.log(x) // 3
(0, alert)('ByePast')
逗號運算符衍生出來的間接函數(shù)調(diào)用
使用間接函數(shù)調(diào)用可以把該作用域內(nèi)倍的
this
指向全局對象中的this
在調(diào)用函數(shù)的上下文中,對操作數(shù)的評估只會得到一個值依疼,而不是引用痰腮,這會導(dǎo)致this
被調(diào)用函數(shù)內(nèi)部的值指向全局對象(或者它將undefined
處于新的 ECMAScript 5 嚴(yán)格模式
)例如:
var foo = 'global.foo'
var obj = {
foo: 'obj.foo',
method: function () {
return this.foo
}
};
obj.method() // 'obj.foo'
(1, obj.method)() // 'global.foo'
如您所見膀值,第一次調(diào)用,即直接調(diào)用误辑,this
內(nèi)部的值method
將正確引用obj
(返回'obj.foo'
),第二次調(diào)用巾钉,逗號運算符所做的評估將使this
值指向全局對象
(產(chǎn)生'global.foo'
)。
這種模式很流行砰苍,要間接調(diào)用eval
,這在 ES5 嚴(yán)格模式
下很有用赚导,例如茬缩,獲取對全局對象的引用(假設(shè)您在非瀏覽器環(huán)境中吼旧,window
不是可用的)
(function () {
'use strict';
var global = (function () { return this || (1, eval)('this') })();
})();
在上面的代碼中,內(nèi)部匿名函數(shù)將在嚴(yán)格模式代碼單元內(nèi)執(zhí)行,這將導(dǎo)致this
值為undefined
該||
運營商現(xiàn)在就第二個操作數(shù)的eval
調(diào)用处面,這是一個間接調(diào)用,它將評估對全球詞法和環(huán)境變量的代碼菩掏。
但就我個人而言,在這種情況下智绸,在嚴(yán)格模式下,我更喜歡使用Function
構(gòu)造函數(shù)來獲取全局對象:
(function () {
'use strict'
var global = Function('return this')()
})()
使用Function
構(gòu)造函數(shù)創(chuàng)建的函數(shù)只有在以 use strict
指令開頭時才是嚴(yán)格的瞧栗,它們不像函數(shù)聲明或函數(shù)表達式那樣“繼承”當(dāng)前上下文的嚴(yán)格性