链判断运算符
ES2020 引入了“链判断运算符”(optional chaining
operator) ?.
1. const firstName = message?.body?.user?.firstName || 'default'; 2. const fooValue = myForm.querySelector('input[name=foo]')?.value
链判断运算符有三种用法。
obj?.prop // 对象属性
obj?.[expr] // 同上
func?.(...args) // 函数或对象方法的调用
下面是判断对象方法是否存在,如果存在就立即执行的例子。
1. iterator.return?.()
上面代码中, iterator.return 如果有定义,就会调用该方法,否则直接返回 undefined 。
Null 判断运算符
ES2020 引入了一个新的 Null 判断运算符 ?? 。它的行为类似 || ,但是只
有运算符左侧的值为 null 或 undefined 时,才会返回右侧的值。
1. const headerText = response.settings.headerText ?? 'Hello, world!'; 2. const animationDuration = response.settings.animationDuration ?? 300; 3. const showSplashScreen = response.settings.showSplashScreen ?? true;
上面代码中,默认值只有在属性值为 null 或 undefined 时,才会生效。
这个运算符的一个目的,就是跟链判断运算符 ?. 配合使用,为 null 或 undefined 的值设置默
认值。
1. const animationDuration = response.settings?.animationDuration ?? 300;
上面代码中, response.settings 如果是 null 或 undefined ,就会返回默认值300。
?? 有一个运算优先级问题,它与 && 和 || 的优先级孰高孰低。现在的规则是,如果多个逻辑运
算符一起使用,必须用括号表明优先级,否则会报错。
1. // 报错 2. lhs && middle ?? rhs 3. lhs ?? middle && rhs 4. lhs || middle ?? rhs 5. lhs ?? middle || rhs
上面四个表达式都会报错,必须加入表明优先级的括号。
1. (lhs && middle) ?? rhs; 2. lhs && (middle ?? rhs); 3. 4. (lhs ?? middle) && rhs; 5. lhs ?? (middle && rhs); 6. 7. (lhs || middle) ?? rhs; 8. lhs || (middle ?? rhs); 9. 10. (lhs ?? middle) || rhs; 11. lhs ?? (middle || rhs);
Object.is()
ES5 比较两个值是否相等,只有两个运算符:相等运算符( == )和严格相等运算符( === )。
它们都有缺点,前者会自动转换数据类型,后者的 NaN 不等于自身,以及 +0 等于 -0 。
JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。
ES6 提出“Same-value equality”(同值相等)算法,用来解决这个问题。 Object.is 就是部
署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
1. Object.is('foo', 'foo') 2. // true 3. Object.is({}, {}) 4. // false
不同之处只有两个:一是 +0 不等于 -0 ,二是 NaN 等于自身。
1. +0 === -0 //true 2. NaN === NaN // false 3. 4. Object.is(+0, -0) // false 5. Object.is(NaN, NaN) // true
ES5 可以通过下面的代码,部署 Object.is 。
1. Object.defineProperty(Object, 'is', { 2. value: function(x, y) { 3. if (x === y) { 4. // 针对+0 不等于 -0的情况 5. return x !== 0 || 1 / x === 1 / y; 6. } 7. // 针对NaN的情况 8. return x !== x && y !== y; 9. }, 10. configurable: true, 11. enumerable: false, 12. writable: true 13. });
Object.assign()
Object.assign 方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象
(target)。
1. const target = { a: 1 }; 2. 3. const source1 = { b: 2 }; 4. const source2 = { c: 3 }; 5. 6. Object.assign(target, source1, source2); 7. target // {a:1, b:2, c:3}
Object.assign 方法的第一个参数是目标对象,后面的参数都是源对象。
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属
性。
1. const target = { a: 1, b: 1 }; 2. 3. const source1 = { b: 2, c: 2 }; 4. const source2 = { c: 3 }; 5. 6. Object.assign(target, source1, source2); 7. target // {a:1, b:2, c:3}
如果只有一个参数, Object.assign 会直接返回该参数。
1. const obj = {a: 1}; 2. Object.assign(obj) === obj // true
如果该参数不是对象,则会先转成对象,然后返回。
1. typeof Object.assign(2) // "object"
由于 undefined 和 null 无法转成对象,所以如果它们作为参数,就会报错。
1. Object.assign(undefined) // 报错 2. Object.assign(null) // 报错
如果非对象参数出现在源对象的位置(即非首参数),那么处理规则有所不同。首先,这些参数都会转
成对象,如果无法转成对象,就会跳过。这意味着,如果 undefined 和 null 不在首参数,就不会
报错。
1. let obj = {a: 1}; 2. Object.assign(obj, undefined) === obj // true 3. Object.assign(obj, null) === obj // true
其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了字符串会以数组形
式,拷贝入目标对象,其他值都不会产生效果。
数组的处理
Object.assign 可以用来处理数组,但是会把数组视为对象。
1. Object.assign([1, 2, 3], [4, 5]) 2. // [4, 5, 3]
上面代码中, Object.assign 把数组视为属性名为 0、1、2 的对象,因此源数组的 0 号属
性 4 覆盖了目标数组的 0 号属性 1 。
2021-04-28 10:07:24