容易被忽视的JavaScript超实用新特性
这是我参与新手入门的第1篇文章
一.可选链操作符( ?. )
你可能碰到过这样的情形:当需要访问嵌套在对象内部好几层的属性时,可能会得到这种错误Cannot read property 'xx' of undefined,然后你就要修改你的代码来处理属性链中每一个可能的undefined对象,比如:
let nestedProp = obj.first && obj.first.second;
为了避免报错,在访问obj.first.second之前,要保证 obj.first 的值既不是 null,也不是 undefined。如果只是直接访问 obj.first.second,而不对 obj.first 进行校验,则有可能抛出错误。
有了可选链操作符(?.),在访问 obj.first.second 之前,不再需要明确地校验 obj.first 的状态,再并用短路计算获取最终结果:
let nestedProp = obj.first?.second;
通过使用 ?. 操作符取代 . 操作符,JavaScript 会在尝试访问 obj.first.second 之前,先隐式地检查并确定 obj.first 既不是 null 也不是 undefined。如果obj.first 是 null 或者 undefined,表达式将会短路计算直接返回 undefined
二.空值合并操作符(??)
我们在开发过程中,经常会遇到这样场景:变量如果是空值,则就使用默认值,我们是这样实现的:
let c = a ? a : b // 方式1
let c = a || b // 方式2
这两种方式有个明显的弊端,由于 || 是一个布尔逻辑运算符,左侧的操作数会被强制转换成布尔值用于求值。任何假值(0, '', NaN, null, undefined)都不会被返回。这导致如果你使用0,''或NaN作为有效值,就会出现不可预料的后果。比如:
let count = 0;
let text = "";
let qty = count || 42;
let message = text || "hi!";
console.log(qty); // 42,而不是 0
console.log(message); // "hi!",而不是 ""
空值合并操作符可以避免这种陷阱,其只在第一个操作数为null 或 undefined 时(而不是其它假值)返回第二个操作数:
let c = a ?? b;
// 等价于let c = a !== undefined && a !== null ? a : b;
const x = null;
const y = x ?? 500;
console.log(y); // 500
const n = 0
const m = n ?? 9000;
console.log(m) // 0
三.类的私有属性(#)
最新提案之一是在类中添加私有属性的方法。我们将使用 # 符号表示类的私有属性。这样就不需要使用闭包来隐藏不想暴露给外界的私有属性。
class Counter {
#x = 0;
#increment() {
this.#x++;
}
onClick() {
this.#increment();
}
}
const c = new Counter();
c.onClick(); // 正常
c.#increment(); // 报错
为什么引用属性时需要符号#?
1.我们需要允许公有属性和私有属性同名,因此不能采用过去的传统方式去访问一个私有属性。
2.在 JavaScript 中可以采用 this.field 或者 this['field'] 的方式引用公有属性。而由于私有属性是静态的(不能动态添加),它不能支持第二种引用方式。这可能会导致语法上的混乱。
3.会承担额外的检查“代价”。
总之,我们需要使用符号#来标识私有属性,而使用其它方式会造成不可预期的行为和结果,并带来巨大的性能问题。
私有属性对语言来说是一个非常好的补充。