From f4ce061d564bc34f5b9fc013fbe5e26ef5f62ea9 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sat, 7 Dec 2019 17:42:05 +0800 Subject: [PATCH] =?UTF-8?q?docs(object):=20=E9=93=BE=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E8=BF=90=E7=AE=97=E7=AC=A6=E7=A7=BB=E5=85=A5=20Object?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/object.md | 133 ++++++++++++++++++++++++++++++++++++++++++++++ docs/proposals.md | 133 ---------------------------------------------- 2 files changed, 133 insertions(+), 133 deletions(-) diff --git a/docs/object.md b/docs/object.md index 74748c0..f3f4c6c 100644 --- a/docs/object.md +++ b/docs/object.md @@ -698,6 +698,139 @@ let runtimeError = { }; ``` +## 链判断运算符 + +编程实务中,如果读取对象内部的某个属性,往往需要判断一下该对象是否存在。比如,要读取`message.body.user.firstName`,安全的写法是写成下面这样。 + +```javascript +const firstName = (message + && message.body + && message.body.user + && message.body.user.firstName) || 'default'; +``` + +或者使用三元运算符`?:`,判断一个对象是否存在。 + +```javascript +const fooInput = myForm.querySelector('input[name=foo]') +const fooValue = fooInput ? fooInput.value : undefined +``` + +这样的层层判断非常麻烦,因此 [ECMAScript2020](https://github.com/tc39/proposal-optional-chaining) 引入了“链判断运算符”(optional chaining operator)`?.`,简化上面的写法。 + +```javascript +const firstName = message?.body?.user?.firstName || 'default'; +const fooValue = myForm.querySelector('input[name=foo]')?.value +``` + +上面代码使用了`?.`运算符,直接在链式调用的时候判断,左侧的对象是否为`null`或`undefined`。如果是的,就不再往下运算,而是返回`undefined`。 + +链判断运算符有三种用法。 + +- `obj?.prop` // 对象属性 +- `obj?.[expr]` // 同上 +- `func?.(...args)` // 函数或对象方法的调用 + +下面是判断对象方法是否存在,如果存在就立即执行的例子。 + +```javascript +iterator.return?.() +``` + +上面代码中,`iterator.return`如果有定义,就会调用该方法,否则直接返回`undefined`。 + +对于那些可能没有实现的方法,这个运算符尤其有用。 + +```javascript +if (myForm.checkValidity?.() === false) { + // 表单校验失败 + return; +} +``` + +上面代码中,老式浏览器的表单可能没有`checkValidity`这个方法,这时`?.`运算符就会返回`undefined`,判断语句就变成了`undefined === false`,所以就会跳过下面的代码。 + +下面是这个运算符常见的使用形式,以及不使用该运算符时的等价形式。 + +```javascript +a?.b +// 等同于 +a == null ? undefined : a.b + +a?.[x] +// 等同于 +a == null ? undefined : a[x] + +a?.b() +// 等同于 +a == null ? undefined : a.b() + +a?.() +// 等同于 +a == null ? undefined : a() +``` + +上面代码中,特别注意后两种形式,如果`a?.b()`里面的`a.b`不是函数,不可调用,那么`a?.b()`是会报错的。`a?.()`也是如此,如果`a`不是`null`或`undefined`,但也不是函数,那么`a?.()`会报错。 + +使用这个运算符,有几个注意点。 + +(1)短路机制 + +```javascript +a?.[++x] +// 等同于 +a == null ? undefined : a[++x] +``` + +上面代码中,如果`a`是`undefined`或`null`,那么`x`不会进行递增运算。也就是说,链判断运算符一旦为真,右侧的表达式就不再求值。 + +(2)delete 运算符 + +```javascript +delete a?.b +// 等同于 +a == null ? undefined : delete a.b +``` + +上面代码中,如果`a`是`undefined`或`null`,会直接返回`undefined`,而不会进行`delete`运算。 + +(3)括号不改变运算顺序 + +```javascript +(a?.b).c +// 等价于 +(a == null ? undefined : a.b).c +``` + +上面代码中,`?.`对圆括号没有影响,不管`a`对象是否存在,圆括号后面的`.c`总是会执行。 + +一般来说,使用`?.`运算符的场合,不应该使用圆括号。 + +(4)报错场合 + +以下写法是禁止的,会报错。 + +```javascript +// 构造函数 +new a?.() +new a?.b() + +// 链判断运算符的右侧有模板字符串 +a?.`{b}` +a?.b`{c}` + +// 链判断运算符的左侧是 super +super?.() +super?.foo + +// 链运算符用于赋值运算符左侧 +a?.b = c +``` + +(5)右侧不得为十进制数值 + +为了保证兼容以前的代码,允许`foo?.3:0`被解析成`foo ? .3 : 0`,因此规定如果`?.`后面紧跟一个十进制数字,那么`?.`不再被看成是一个完整的运算符,而会按照三元运算符进行处理,也就是说,那个小数点会归属于后面的十进制数字,形成一个小数。 + ## Null 判断运算符 读取对象属性的时候,如果某个属性的值是`null`或`undefined`,有时候需要为它们指定默认值。常见做法是通过`||`运算符指定默认值。 diff --git a/docs/proposals.md b/docs/proposals.md index a8d40af..50097f3 100644 --- a/docs/proposals.md +++ b/docs/proposals.md @@ -118,139 +118,6 @@ class Product { 语法上,`throw`表达式里面的`throw`不再是一个命令,而是一个运算符。为了避免与`throw`命令混淆,规定`throw`出现在行首,一律解释为`throw`语句,而不是`throw`表达式。 -## 链判断运算符 - -编程实务中,如果读取对象内部的某个属性,往往需要判断一下该对象是否存在。比如,要读取`message.body.user.firstName`,安全的写法是写成下面这样。 - -```javascript -const firstName = (message - && message.body - && message.body.user - && message.body.user.firstName) || 'default'; -``` - -或者使用三元运算符`?:`,判断一个对象是否存在。 - -```javascript -const fooInput = myForm.querySelector('input[name=foo]') -const fooValue = fooInput ? fooInput.value : undefined -``` - -这样的层层判断非常麻烦,因此现在有一个[提案](https://github.com/tc39/proposal-optional-chaining),引入了“链判断运算符”(optional chaining operator)`?.`,简化上面的写法。 - -```javascript -const firstName = message?.body?.user?.firstName || 'default'; -const fooValue = myForm.querySelector('input[name=foo]')?.value -``` - -上面代码使用了`?.`运算符,直接在链式调用的时候判断,左侧的对象是否为`null`或`undefined`。如果是的,就不再往下运算,而是返回`undefined`。 - -链判断运算符有三种用法。 - -- `obj?.prop` // 对象属性 -- `obj?.[expr]` // 同上 -- `func?.(...args)` // 函数或对象方法的调用 - -下面是判断对象方法是否存在,如果存在就立即执行的例子。 - -```javascript -iterator.return?.() -``` - -上面代码中,`iterator.return`如果有定义,就会调用该方法,否则直接返回`undefined`。 - -对于那些可能没有实现的方法,这个运算符尤其有用。 - -```javascript -if (myForm.checkValidity?.() === false) { - // 表单校验失败 - return; -} -``` - -上面代码中,老式浏览器的表单可能没有`checkValidity`这个方法,这时`?.`运算符就会返回`undefined`,判断语句就变成了`undefined === false`,所以就会跳过下面的代码。 - -下面是这个运算符常见的使用形式,以及不使用该运算符时的等价形式。 - -```javascript -a?.b -// 等同于 -a == null ? undefined : a.b - -a?.[x] -// 等同于 -a == null ? undefined : a[x] - -a?.b() -// 等同于 -a == null ? undefined : a.b() - -a?.() -// 等同于 -a == null ? undefined : a() -``` - -上面代码中,特别注意后两种形式,如果`a?.b()`里面的`a.b`不是函数,不可调用,那么`a?.b()`是会报错的。`a?.()`也是如此,如果`a`不是`null`或`undefined`,但也不是函数,那么`a?.()`会报错。 - -使用这个运算符,有几个注意点。 - -(1)短路机制 - -```javascript -a?.[++x] -// 等同于 -a == null ? undefined : a[++x] -``` - -上面代码中,如果`a`是`undefined`或`null`,那么`x`不会进行递增运算。也就是说,链判断运算符一旦为真,右侧的表达式就不再求值。 - -(2)delete 运算符 - -```javascript -delete a?.b -// 等同于 -a == null ? undefined : delete a.b -``` - -上面代码中,如果`a`是`undefined`或`null`,会直接返回`undefined`,而不会进行`delete`运算。 - -(3)括号不改变运算顺序 - -```javascript -(a?.b).c -// 等价于 -(a == null ? undefined : a.b).c -``` - -上面代码中,`?.`对圆括号没有影响,不管`a`对象是否存在,圆括号后面的`.c`总是会执行。 - -一般来说,使用`?.`运算符的场合,不应该使用圆括号。 - -(4)报错场合 - -以下写法是禁止的,会报错。 - -```javascript -// 构造函数 -new a?.() -new a?.b() - -// 链判断运算符的右侧有模板字符串 -a?.`{b}` -a?.b`{c}` - -// 链判断运算符的左侧是 super -super?.() -super?.foo - -// 链运算符用于赋值运算符左侧 -a?.b = c -``` - -(5)右侧不得为十进制数值 - -为了保证兼容以前的代码,允许`foo?.3:0`被解析成`foo ? .3 : 0`,因此规定如果`?.`后面紧跟一个十进制数字,那么`?.`不再被看成是一个完整的运算符,而会按照三元运算符进行处理,也就是说,那个小数点会归属于后面的十进制数字,形成一个小数。 - ## 函数的部分执行 ### 语法