本文用以记录工作或学习中碰到的ES6中的一些特殊运算符,持续更新…
提案中,尚未进入标准的运算符可能在当前的浏览器版本中还并未受到支持
- ?.
链式运算符
- 链式调用的时候判断左侧的对象是否为null或者undefined。如果是,就不再往下运算,直接返回undefined。
obj?.prop // 对象属性
obj?.[expr] // 同上 [expr]是对象属性表达式
obj?.func?.(...args) // 函数或对象方法的调用
- ||
判断运算符
- 左侧为真值则取左侧,否则取右侧。
- ??
判空运算符
- 只有左侧为null或undefined时,才取右侧。
- ::
函数绑定运算符 – 提案中,尚未进入标准
- 函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。
- 如果双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定在该对象上面。
obj::foo // ==> foo.bind(obj)
obj::foo(...args) // ==> foo.apply(obj, args)
let fn = ::obj.foo // ==> let fn = obj::obj.foo
import { map, takeWhile, forEach } from "iterlib";
getPlayers()
::map(x => x.character())
::takeWhile(x => x.strength > 100)
::forEach(x => console.log(x));
- …
扩展运算符
- @fn
装饰器
@testable
class Person {
@readonly
@nonenumerable
name() { return `${this.first} ${this.last}` }
}
- #prop / #fn
class内部私有属性或私有方法,只能在class内部访问。
- get fn / set fn
class get 或 set 方法
- static prop / static fn
class静态属性或静态方法,只能用class类名访问,不能用实例访问,静态方法中的this指向当前class。
- function* / yield
generate函数
- async function / await
异步函数
- new.target
- Class 内部调用new.target,返回当前 Class。用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令或Reflect.construct()调用的,new.target会返回undefined。
- 在函数外部,使用new.target会报错。
function Person(name) {
if (new.target !== undefined) {
this.name = name;
} else {
throw new Error('必须使用 new 命令生成实例');
}
}
// 另一种写法
function Person(name) {
if (new.target === Person) {
this.name = name;
} else {
throw new Error('必须使用 new 命令生成实例');
}
}
子类继承父类时,new.target会返回子类,利用这个特点,可以写出不能独立使用、必须继承后才能使用的类。
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error('本类不能实例化');
}
}
}
class Rectangle extends Shape {
constructor(length, width) {
super();
// ...
}
}
var x = new Shape(); // 报错
var y = new Rectangle(3, 4); // 正确
- ,
逗号运算符
- 逗号运算符的特性及作用:逗号运算符的作用是将若干表达式连接起来。它的优先级是所有运算符中最低的,结合方向是自左至右。
- 逗号表达式:
- 一般形式:表达式1,表达式2,表达式3,…表达式n
求解过程:先计算表达式1的值,再计算表达式2的值,…一直计算到表达式n的值。最后整个表达式的值是表达式n的值。
- do
do表达式 – 提案中,尚未进入标准
- 在块级作用域之前加上do,使它变为do表达式,然后就会返回内部最后执行的表达式的值。
// x = t * t + 1
let x = do {
let t = f();
t * t + 1;
};
- throw
throw表达式 – 提案中,尚未进入标准
- throw出现在行首,一律解释为throw语句,反之则为throw表达式。
// 参数的默认值
function save(filename = throw new TypeError("Argument required")) {
}
// 箭头函数的返回值
lint(ast, {
with: () => throw new Error("avoid using 'with' statements.")
});
- 函数部分执行
函数部分执行 – 提案中,尚未进入标准
- ?是单个参数的占位符,…是多个参数的占位符。?和…只能出现在函数的调用之中,并且会返回一个新函数。
const add = (x, y) => x + y;
const addOne = add(1, ?);
const g = f(?, 1, ...);
// 等同于
const g = (x, ...y) => f(x, 1, ...y);
let obj = {
f(x, y) { return x + y; },
};
const g = obj.f(?, 3);
g(1) // 4
- > |
管道运算符 – 提案中,尚未进入标准
- 它的左边是一个表达式,右边是一个函数。管道运算符把左边表达式的值,传入右边的函数进行求值。管道运算符最大的好处,就是可以把嵌套的函数,写成从左到右的链式表达式。
// 传统的写法
exclaim(capitalize(doubleSay('hello')))
// "Hello, hello!"
// 管道的写法
'hello'
|> doubleSay
|> capitalize
|> exclaim
// "Hello, hello!"
x |> await f
// 等同于
await f(x)
const userAge = userId |> await fetchUserById |> getAgeFromUser;
// 等同于
const userAge = getAgeFromUser(await fetchUserById(userId));