在数组与对象中传播未定义
Spreading undefined in array vs object
为什么在对象 return 中展开未定义的空对象? {...undefined} // equals {}
:
console.log({...undefined})
以及为什么在数组中散布 undefined 会给您带来错误?
[...undefined] // type error
:
console.log([...undefined])
如评论中所述,并由来自 #687, object spread is equivalent1 to Object.assign() (issues #687, #45 的@ftor 总结),而数组文字上下文中的传播是可迭代的传播。
引用 Ecma-262 6.0, Object.assign() 定义为:
19.1.2.1 Object.assign ( target, ...sources )
The assign function is used to copy the values of all of the enumerable own properties from one or more source objects to a target object. When the assign function is called, the following steps are taken:
- Let to be ToObject(target).
- ReturnIfAbrupt(to).
- If only one argument was passed, return to.
- Let sources be the List of argument values starting with the second argument.
- For each element nextSource of sources, in ascending index order, do
- If nextSource is undefined or null, let keys be an empty List.
- Else, ...
...后面是复制自身属性的说明。对象 Rest/Spread 属性的草案是 here。它不是 Ecma-262 6.0 的一部分。
数组文字表达式中的SpreadElement定义为如下开头:
SpreadElement : ... AssignmentExpression
- Let spreadRef be the result of evaluating AssignmentExpression.
- Let spreadObj be GetValue(spreadRef).
- Let iterator be GetIterator(spreadObj).
- ReturnIfAbrupt(iterator).
并且自 undefined
does not have a property with the key @@iterator, a TypeError is thrown, based on the steps of GetIterator. The standard is not an easy read, but if I'm not mistaken, the path to error is GetIterator -> GetMethod -> GetV -> ToObject 以来,它会针对未定义和 null 抛出 TypeError。
在数组初始化中使用可能未定义值的变量的一个简单补救方法是使用默认值:
const maybeArray = undefined;
const newArray = [ ...(maybeArray || []) ];
1:有区别how setters are handled.
通常,...x
的使用要求 x
是 可迭代的 因为 ...
的要点通常是将一个可迭代对象展开为它的组件。 for (const item of x)
同样需要一个可迭代对象。数组是可迭代对象的主要示例。
但是,{...x}
要求 x
是 可枚举的 ,因为我们不仅需要值,还需要键。 for (const item in x)
同样需要一个可枚举的。对象是可枚举的主要示例。
关于null
的注释
此问题已关闭,因为它与询问 null
作为 ...
的操作数的行为的问题重复。
null
不是 可迭代的 。它没有组件,因此迭代 null
没有意义。 (for (const item of null)
同样会失败。)
然而,null
是 可枚举的 。 null
有时被视为对象,这是其中一种情况,对象是可枚举的,因为它们可以具有属性。 (for (const prop in null)
同样会成功。)
您可以使用此表达式 [...(this.options || [])],其中选项是数组
为什么在对象 return 中展开未定义的空对象? {...undefined} // equals {}
:
console.log({...undefined})
以及为什么在数组中散布 undefined 会给您带来错误?
[...undefined] // type error
:
console.log([...undefined])
如评论中所述,并由来自 #687, object spread is equivalent1 to Object.assign() (issues #687, #45 的@ftor 总结),而数组文字上下文中的传播是可迭代的传播。
引用 Ecma-262 6.0, Object.assign() 定义为:
19.1.2.1 Object.assign ( target, ...sources )
The assign function is used to copy the values of all of the enumerable own properties from one or more source objects to a target object. When the assign function is called, the following steps are taken:
- Let to be ToObject(target).
- ReturnIfAbrupt(to).
- If only one argument was passed, return to.
- Let sources be the List of argument values starting with the second argument.
- For each element nextSource of sources, in ascending index order, do
- If nextSource is undefined or null, let keys be an empty List.
- Else, ...
...后面是复制自身属性的说明。对象 Rest/Spread 属性的草案是 here。它不是 Ecma-262 6.0 的一部分。
数组文字表达式中的SpreadElement定义为如下开头:
SpreadElement : ... AssignmentExpression
- Let spreadRef be the result of evaluating AssignmentExpression.
- Let spreadObj be GetValue(spreadRef).
- Let iterator be GetIterator(spreadObj).
- ReturnIfAbrupt(iterator).
并且自 undefined
does not have a property with the key @@iterator, a TypeError is thrown, based on the steps of GetIterator. The standard is not an easy read, but if I'm not mistaken, the path to error is GetIterator -> GetMethod -> GetV -> ToObject 以来,它会针对未定义和 null 抛出 TypeError。
在数组初始化中使用可能未定义值的变量的一个简单补救方法是使用默认值:
const maybeArray = undefined;
const newArray = [ ...(maybeArray || []) ];
1:有区别how setters are handled.
通常,...x
的使用要求 x
是 可迭代的 因为 ...
的要点通常是将一个可迭代对象展开为它的组件。 for (const item of x)
同样需要一个可迭代对象。数组是可迭代对象的主要示例。
但是,{...x}
要求 x
是 可枚举的 ,因为我们不仅需要值,还需要键。 for (const item in x)
同样需要一个可枚举的。对象是可枚举的主要示例。
关于null
此问题已关闭,因为它与询问 null
作为 ...
的操作数的行为的问题重复。
null
不是 可迭代的 。它没有组件,因此迭代 null
没有意义。 (for (const item of null)
同样会失败。)
然而,null
是 可枚举的 。 null
有时被视为对象,这是其中一种情况,对象是可枚举的,因为它们可以具有属性。 (for (const prop in null)
同样会成功。)
您可以使用此表达式 [...(this.options || [])],其中选项是数组