一些很甜的 JS 语法糖。
Nullish Coalescing Operator (??)
当值为 nullish 时使用默认值。注意,nullish 和 truthy 不一样。
nullish: null or undefined.
const foo = null ?? 'default string';
console.log(foo);
// Expected output: "default string"
const baz = 0 ?? 42;
console.log(baz);
// Expected output: 0
Nullish coalescing assignment (??=)
当变量为 nullish 时则赋值,否则无变化。
const a = { duration: 50 };
a.speed ??= 25;
console.log(a.speed);
// Expected output: 25
a.duration ??= 10;
console.log(a.duration);
// Expected output: 50
Logical OR/AND assignment (||= &&=)
使用场景比较少。
const a = { duration: 50, title: '' };
a.duration ||= 10;
console.log(a.duration);
// Expected output: 50
a.title ||= 'title is empty.';
console.log(a.title);
// Expected output: "title is empty."
// &&= 使用场景比较少
let a = 1;
let b = 0;
a &&= 2;
console.log(a);
// Expected output: 2
b &&= 2;
console.log(b);
// Expected output: 0
Optional chaining (?.)
kotlin 笑而不语。超级有用的语法糖。
既可以访问对象的属性也可以访问 function。
注意如果变量是 undefined/null 时返回的是 undefined 而不是 null。
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah',
},
};
const dogName = adventurer.dog?.name;
console.log(dogName);
// Expected output: undefined
// call a function
console.log(adventurer.someNonExistentMethod?.());
// Expected output: undefined
Dynamic Import
import() 不是 function call,只是语法相似。所以不能使用 apply/call 等语法。
import 不需要指定<script type=“module”.>
<script>
async function load() {
let say = await import('./say.js');
say.hi(); // Hello!
say.bye(); // Bye!
say.default(); // Module loaded (export default)!
}
</script>
Private properties
变量名不能是 #constructor
;
在 chrome devtool 中可以在外部访问 private properties,只是一个 chrome 开发特性,不是语法问题。
MDN doc:private properties
class ClassWithPrivate {
#privateField;
#privateFieldWithInitializer = 42;
#privateMethod() {
// …
}
static #privateStaticField;
static #privateStaticFieldWithInitializer = 42;
static #privateStaticMethod() {
// …
}
}
const instance = new ClassWithPrivateField();
instance.#privateField; // Syntax error
error.cause
error 新增的属性,用来在 error 中传递原始错误信息。
try {
conn = getDbConnection();
} catch (err) {
throw new Error('Connecting to database failed.', { cause: err });
}
Array functions
arr.toSorted
const values = [1, 10, 21, 2];
const sortedValues = values.toSorted((a, b) => a - b);
arr.findLast
const found = array1.findLast((element) => element > 45);
arr.toReversed()
arr.toSpliced
arr.with()
arr.fromAsync()
apply,call, bind
三个方法都是用于修改函数本身的的 context。
call(this,arg1,arg2,arg3)
// 将一个 array like(有元素,length 方法但是没其他方法)对象变成 array
const slice = Array.prototype.slice;
slice.call(arguments);
apply(this,argsArray)
// e.g. const max = Math.max.apply(null, numbers);
// 和 rest parameters 语法非常相似:
function wrapper(...args) {
return anotherFn(...args);
}
// 使用场景:将一个 array append 到另一个 array,
// array.push 方法只能接收一个元素,如果使用 concat 得到的是一个新的 array
const array = ["a", "b"];
const elements = [0, 1, 2];
array.push.apply(array, elements);
//等价于 array.push(...elements);
bind(this,arg1,arg2,arg3) like call but return the new function.
// 将上面的 slice.call 优化成 slice() 函数
// Same as "slice" in the previous example
// 给 call 方法设置一个 this 对象并返回新的 call 函数,
// 这个 call 函数的 this 是 Array.prototype.slice;
const slice = Function.prototype.call.bind(Array.prototype.slice);
slice(arguments);
// 为什么不是 Array.prototype.slice.call.bind(Array.prototype.slice) ?