ES2020 可选链:a?.().b 和 a()?.b 和 a?.()?.b 有什么区别
ES2020 optional chaining: what's the difference between a?.().b and a()?.b and a?.()?.b
假设我们有这个对象:
let obj = {};
这些表达式的具体作用是什么?
obj.a?.().b
obj.a()?.b
obj.a?.()?.b
obj.a?.().b
- 如果 obj.a
是 null
或 undefined
那么表达式是 undefined
否则表达式的计算结果是 obj.a().b
.
obj.a()?.b
- 如果 obj.a()
是 null
或 undefined
那么表达式是 undefined
否则表达式的计算结果是 obj.a().b
obj.a?.()?.b
如果 obj.a
或 obj.a()
是 null
或 undefined
则表达式为 undefined
否则表达式计算为 obj.a().b
.
阅读更多关于可选链的信息here。
obj.a?.().b
直接取消引用 obj
。
以空安全方式取消引用 obj.a
- 如果 属性 不存在,它将在此时停止,它是 undefined
或 null
。如果发生这种情况,计算表达式的结果将是 undefined
.
直接执行那个值。
收到 return 结果并继续。
直接从结果中得到属性b
const tryIt = obj => {
console.log("------start------");
console.log("trying with", obj );
try {
console.log( "result", obj.a?.().b );
} catch (e) {
console.error("problem", e.message);
}
console.log("-------end-------");
}
tryIt( null ); // ERROR
tryIt( {} ); // undefined
tryIt( { a: undefined } ); // undefined
tryIt( { a: null } ); // undefined
tryIt( { a: false } ); // ERROR
tryIt( { a: "hello" } ); // ERROR
tryIt( { a: function() {} } ); // ERROR
tryIt( { // ERROR
a: function() {
return null;
}
});
tryIt( { // 42
a: function() {
return { b: 42 };
}
});
obj.a()?.b
直接取消引用 obj
。
直接取消引用 obj.a
。
直接执行那个值。
以空安全方式处理值 - 如果 return 值为 null
或 [=16=,它将在此时停止].如果发生这种情况,计算表达式的结果将是 undefined
.
直接从结果中得到属性b
const tryIt = obj => {
console.log("------start------");
console.log("trying with", obj );
try {
console.log( "result", obj.a()?.b );
} catch (e) {
console.error("problem", e.message);
}
console.log("-------end-------");
}
tryIt( null ); // ERROR
tryIt( {} ); // ERROR
tryIt( { a: undefined } ); // ERROR
tryIt( { a: null } ); // ERROR
tryIt( { a: false } ); // ERROR
tryIt( { a: "hello" } ); // ERROR
tryIt( { a: function() {} } ); // undefined
tryIt( { // undefined
a: function() {
return null;
}
});
tryIt( { // 42
a: function() {
return { b: 42 };
}
});
obj.a?.()?.b
直接取消引用 obj
。
以空安全方式取消引用 obj.a
- 如果 属性 不存在,它将在此时停止,它是 undefined
或 null
。如果发生这种情况,计算表达式的结果将是 undefined
.
直接执行那个值。
以空安全方式处理值 - 如果 return 值为 null
或 [=16=,它将在此时停止].如果发生这种情况,计算表达式的结果将是 undefined
.
直接从结果中得到属性b
const tryIt = obj => {
console.log("------start------");
console.log("trying with", obj );
try {
console.log( "result", obj.a?.()?.b );
} catch (e) {
console.error("problem", e.message);
}
console.log("-------end-------");
}
tryIt( null ); // ERROR
tryIt( {} ); // undefined
tryIt( { a: undefined } ); // undefined
tryIt( { a: null } ); // undefined
tryIt( { a: false } ); // ERROR
tryIt( { a: "hello" } ); // ERROR
tryIt( { a: function() {} } ); // undefined
tryIt( { // undefined
a: function() {
return null;
}
});
tryIt( { // 42
a: function() {
return { b: 42 };
}
});
optional chaining operator可用于三个位置:
- 代替 属性 访问的点运算符 (
obj?.a
)
- 紧接 属性 访问的括号语法之前 (
obj?.['a']
)
- 紧接函数调用之前 (
obj.a?.()
)
在属性访问位置,如果属性值为空值(即null
或undefined
) , 然后它立即短路整个表达式, returns undefined
.
在函数调用位置,如果函数为nullish,则立即短路整个表达式,returns undefined
(从而避免 "undefined is not a function" 异常)。
所以:
obj.a?.().b
将 return undefined
如果 obj.a
为空。
如果 obj.a().b
的结果为空,obj.a()?.b
将 return undefined
。
obj.a?.()?.b
将 return undefined
如果 a
为空,或者如果 obj.a()
的结果为空。
TL;TR
检查表达式的 non-undefined
、not-null
值和 ?
并且在任何时候,如果发现值是其中之一,链就会断开并 returns undefined
.
需要注意的一个非常重要的一点是它只保护 对抗 undefined
和 null
值而不是对抗 falsy 值,即它仍然会传递其他虚假值,如 NaN 或 "".
详细说明
让我们从引用开始 MDN
The optional chaining operator provides a way to simplify accessing
values through connected objects when it's possible that a reference
or function may be undefined or null.
考虑这样一个对象:
var obj = {
a: {
b: 1
},
}
现在验证 obj
、obj
的属性 a
然后 a
的 属性 b
不是 undefined
和 null
,你可能需要做这样的事情:
obj && obj.a && obj.a.b
可选链接为您提供了替代方法。你可以简单地这样做:
obj?.a?.b
现在,假设 a
恰好是一个函数,它 return 是一个具有 属性 b
的对象,其值 1
。像这样:
var obj = {
a: function{
return {b:1}
},
}
那么,对于深度嵌套的 b
,您现在将如何验证 obj
及其字段?那么,你可以这样做:
obj && obj.a && typeof obj.a === 'function' && obj.a() && obj.a().b
或者你可以简单地做
obj?.a()?.b
这只是意味着检查 obj
是否为非未定义和非空,(如果是)然后检查 obj?.a()
是否相同,(如果是则)执行方法 a()
的对象。如果执行后方法 return 有一个值(不是 undefined
或 null
),则从中获取 属性 b
的值。
在此 检查 期间的任何时候,如果发现值是 undefined
或 null
只需断开链并 return undefined
但是,如果 a
恰好不是在前面的表达式中用 typeof obj.a === 'function'
检查的函数,这将失败。
另外,请注意,此时如果 obj.a()
恰好出现在 return 上,比如“baz”,它将被执行为
"baz".b
这会给你 undefined
.
有了这些知识,我们可以轻松破译这个表达式:
obj.a?.().b
检查obj.a
是否为non-undefined
、not-null
。如果是,则执行 obj.a() (注意,如果 obj.a
不是一个函数,而是 returns 说,数字 5
,它将抛出一个错误)
如果 obj.a()
碰巧执行成功,那么 .b
的返回值将被检查。
现在剩下这个
obj.a?.()?.b
嗯,这也像我们之前的执行一样执行:
如果是 not-null
和 non-undefined
,请检查 obj.a
。如果是,执行obj.a
。如果那也是non-null
和non-undefined
,执行obj.a()
等等。
如果在检查时的任何时候发现值是 null
或 undefined
,链就会中断。
需要注意的非常重要的一点是,我们的运算符 ?
仅防范未定义和 null 而不是其他 falsy 值。
考虑一下
var a = undefined
var myVal = a?.details.b;
alert(a) //will return undefined
var a = ""
var myVal = a?.details.b;
alert(a) //Our guard fails us here and simply throws an error
假设我们有这个对象:
let obj = {};
这些表达式的具体作用是什么?
obj.a?.().b
obj.a()?.b
obj.a?.()?.b
obj.a?.().b
- 如果 obj.a
是 null
或 undefined
那么表达式是 undefined
否则表达式的计算结果是 obj.a().b
.
obj.a()?.b
- 如果 obj.a()
是 null
或 undefined
那么表达式是 undefined
否则表达式的计算结果是 obj.a().b
obj.a?.()?.b
如果 obj.a
或 obj.a()
是 null
或 undefined
则表达式为 undefined
否则表达式计算为 obj.a().b
.
阅读更多关于可选链的信息here。
obj.a?.().b
直接取消引用
obj
。以空安全方式取消引用
obj.a
- 如果 属性 不存在,它将在此时停止,它是undefined
或null
。如果发生这种情况,计算表达式的结果将是undefined
.直接执行那个值。
收到 return 结果并继续。
直接从结果中得到属性
b
const tryIt = obj => {
console.log("------start------");
console.log("trying with", obj );
try {
console.log( "result", obj.a?.().b );
} catch (e) {
console.error("problem", e.message);
}
console.log("-------end-------");
}
tryIt( null ); // ERROR
tryIt( {} ); // undefined
tryIt( { a: undefined } ); // undefined
tryIt( { a: null } ); // undefined
tryIt( { a: false } ); // ERROR
tryIt( { a: "hello" } ); // ERROR
tryIt( { a: function() {} } ); // ERROR
tryIt( { // ERROR
a: function() {
return null;
}
});
tryIt( { // 42
a: function() {
return { b: 42 };
}
});
obj.a()?.b
直接取消引用
obj
。直接取消引用
obj.a
。直接执行那个值。
以空安全方式处理值 - 如果 return 值为
null
或 [=16=,它将在此时停止].如果发生这种情况,计算表达式的结果将是undefined
.直接从结果中得到属性
b
const tryIt = obj => {
console.log("------start------");
console.log("trying with", obj );
try {
console.log( "result", obj.a()?.b );
} catch (e) {
console.error("problem", e.message);
}
console.log("-------end-------");
}
tryIt( null ); // ERROR
tryIt( {} ); // ERROR
tryIt( { a: undefined } ); // ERROR
tryIt( { a: null } ); // ERROR
tryIt( { a: false } ); // ERROR
tryIt( { a: "hello" } ); // ERROR
tryIt( { a: function() {} } ); // undefined
tryIt( { // undefined
a: function() {
return null;
}
});
tryIt( { // 42
a: function() {
return { b: 42 };
}
});
obj.a?.()?.b
直接取消引用
obj
。以空安全方式取消引用
obj.a
- 如果 属性 不存在,它将在此时停止,它是undefined
或null
。如果发生这种情况,计算表达式的结果将是undefined
.直接执行那个值。
以空安全方式处理值 - 如果 return 值为
null
或 [=16=,它将在此时停止].如果发生这种情况,计算表达式的结果将是undefined
.直接从结果中得到属性
b
const tryIt = obj => {
console.log("------start------");
console.log("trying with", obj );
try {
console.log( "result", obj.a?.()?.b );
} catch (e) {
console.error("problem", e.message);
}
console.log("-------end-------");
}
tryIt( null ); // ERROR
tryIt( {} ); // undefined
tryIt( { a: undefined } ); // undefined
tryIt( { a: null } ); // undefined
tryIt( { a: false } ); // ERROR
tryIt( { a: "hello" } ); // ERROR
tryIt( { a: function() {} } ); // undefined
tryIt( { // undefined
a: function() {
return null;
}
});
tryIt( { // 42
a: function() {
return { b: 42 };
}
});
optional chaining operator可用于三个位置:
- 代替 属性 访问的点运算符 (
obj?.a
) - 紧接 属性 访问的括号语法之前 (
obj?.['a']
) - 紧接函数调用之前 (
obj.a?.()
)
在属性访问位置,如果属性值为空值(即null
或undefined
) , 然后它立即短路整个表达式, returns undefined
.
在函数调用位置,如果函数为nullish,则立即短路整个表达式,returns undefined
(从而避免 "undefined is not a function" 异常)。
所以:
obj.a?.().b
将 returnundefined
如果obj.a
为空。
如果 obj.a()?.b
将 returnundefined
。obj.a?.()?.b
将 returnundefined
如果a
为空,或者如果obj.a()
的结果为空。
obj.a().b
的结果为空,TL;TR
检查表达式的 non-undefined
、not-null
值和 ?
并且在任何时候,如果发现值是其中之一,链就会断开并 returns undefined
.
需要注意的一个非常重要的一点是它只保护 对抗 undefined
和 null
值而不是对抗 falsy 值,即它仍然会传递其他虚假值,如 NaN 或 "".
详细说明
让我们从引用开始 MDN
The optional chaining operator provides a way to simplify accessing values through connected objects when it's possible that a reference or function may be undefined or null.
考虑这样一个对象:
var obj = {
a: {
b: 1
},
}
现在验证 obj
、obj
的属性 a
然后 a
的 属性 b
不是 undefined
和 null
,你可能需要做这样的事情:
obj && obj.a && obj.a.b
可选链接为您提供了替代方法。你可以简单地这样做:
obj?.a?.b
现在,假设 a
恰好是一个函数,它 return 是一个具有 属性 b
的对象,其值 1
。像这样:
var obj = {
a: function{
return {b:1}
},
}
那么,对于深度嵌套的 b
,您现在将如何验证 obj
及其字段?那么,你可以这样做:
obj && obj.a && typeof obj.a === 'function' && obj.a() && obj.a().b
或者你可以简单地做
obj?.a()?.b
这只是意味着检查 obj
是否为非未定义和非空,(如果是)然后检查 obj?.a()
是否相同,(如果是则)执行方法 a()
的对象。如果执行后方法 return 有一个值(不是 undefined
或 null
),则从中获取 属性 b
的值。
在此 检查 期间的任何时候,如果发现值是 undefined
或 null
只需断开链并 return undefined
但是,如果 a
恰好不是在前面的表达式中用 typeof obj.a === 'function'
检查的函数,这将失败。
另外,请注意,此时如果 obj.a()
恰好出现在 return 上,比如“baz”,它将被执行为
"baz".b
这会给你 undefined
.
有了这些知识,我们可以轻松破译这个表达式:
obj.a?.().b
检查obj.a
是否为non-undefined
、not-null
。如果是,则执行 obj.a() (注意,如果 obj.a
不是一个函数,而是 returns 说,数字 5
,它将抛出一个错误)
如果 obj.a()
碰巧执行成功,那么 .b
的返回值将被检查。
现在剩下这个
obj.a?.()?.b
嗯,这也像我们之前的执行一样执行:
如果是 not-null
和 non-undefined
,请检查 obj.a
。如果是,执行obj.a
。如果那也是non-null
和non-undefined
,执行obj.a()
等等。
如果在检查时的任何时候发现值是 null
或 undefined
,链就会中断。
需要注意的非常重要的一点是,我们的运算符 ?
仅防范未定义和 null 而不是其他 falsy 值。
考虑一下
var a = undefined
var myVal = a?.details.b;
alert(a) //will return undefined
var a = ""
var myVal = a?.details.b;
alert(a) //Our guard fails us here and simply throws an error