为什么扩展语法会将我的字符串转换为数组?
var v = 'hello';
var [, ...w] = v; // ["e", "l", "l", "o"]
为什么w
不是字符串?
答案 0 :(得分:17)
Spread syntax(实际上是RobG所指出的标点符号)允许迭代次数扩展成更小的位。由于字符串是可迭代的(它们是内部的字符数组,更具体地是有序的整数表示字符的序列),因此它们可以扩展为单个字符。
接下来,对阵列执行destructuring assignment以解压缩并对扩展值进行分组。由于您使用,
省略了字符数组的第一个元素并且未分配引用,因此它将丢失,并且可迭代对象的 rest 将保存到w
中,传播到它的各个部分,字符数组的单个字符。
此操作的特定语义由{em> ArrayAssignmentPattern在ECMAScript 2015 Specification中定义:[Elision opt AssignmentRestElement] 生产:
12.14.5.2运行时语义:DestructuringAssignmentEvaluation
参数 value
[...]
ArrayAssignmentPattern:[Elision opt AssignmentRestElement]
- 让迭代器为GetIterator( value )。
- ReturnIfAbrupt(迭代)。
- 让 iteratorRecord 为Record {[[iterator]]: iterator ,[[done]]: false }。
- 如果存在 Elision ,则为 一个。让状态是以 iteratorRecord 作为参数执行 Elision 的IteratorDestructuringAssignmentEvaluation的结果。
湾如果状态是abrupt completion,则为 一世。如果 iteratorRecord 。[[done]]为 false ,则返回IteratorClose(迭代器,状态) 。
II。返回Completion(状态)。- 让结果成为执行 AssignmentRestElement 的IteratorDestructuringAssignmentEvaluation并将 iteratorRecord 作为参数的结果。
- 如果 iteratorRecord 。[[done]]为 false ,则返回IteratorClose(迭代器,结果)。
- 返回结果。
醇>
这里, Elision 在使用一个或多个逗号(,
)传播时引用省略的元素,与名称所暗示的省略音节相比, AssignmentRestElement 指的是接收传播和结构化值的目标,在这种情况下为w
。
这样做首先从内部@@iterator
方法获取对象的迭代器并逐步完成迭代器,跳过由 Elision 生成的省略宽度指示的许多元素在IteratorDestructuringAssignmentEvaluation。完成后,它将逐步执行 AssignmentRestElement 生成的迭代器,并分配一个包含所有扩展值的新数组 - 这就是w
。它接收展开的单字符数组,解压缩以排除第一个字符。
获取迭代的@@iterator
方法是well-known Symbol,并且为对象更改它可以改变它的迭代方式,如Emissary's answer中所示。具体来说,@@iterator
method for String的默认实现如下:
21.1.3.27 String.prototype [@@ iterator]()
当调用@@ iterator方法时,它返回一个Iterator对象(25.1.1.2),它迭代String值的代码点,并将每个代码点作为String值返回。
因此,迭代器允许通过单个代码点或字符串的字符进行迭代 - 因此传播字符串将导致其字符数组。
答案 1 :(得分:6)
在ES2015中,扩展语法专门针对内部String @@iterator
属性 - 通过将自己的iterator或generator / function*
分配给{{1},可以通过这种方式迭代任何对象属性。
例如,您可以更改新阵列的默认行为......
obj[Symbol.iterator]

您也可以更改字符串迭代器,但您必须明确创建const a = [...'hello'];
a[Symbol.iterator] = function* (){
for(let i=0; i<this.length; ++i)
yield `${this[i]}!`;
};
console.log([...a]);
对象。
答案 2 :(得分:5)
Spread syntax只能应用于可迭代对象。由于String是可迭代的,因此Spread运算符可正常工作,并将char
数组(String)拆分为char
。
您可以使用下面的示例检查,证明String默认是可迭代的。
var s = 'test';
for (k in s) {
console.log(k);
}
ECMAScript6规范甚至提到了这个特定的String案例。
点差操作员
将可迭代集合的元素(如数组
or even a string
)传播到文字元素和单个函数参数中。
http://es6-features.org/#SpreadOperator
var str = "foo";
var chars = [ ...str ]; // [ "f", "o", "o" ]
值得一提的是,这是一个特定情况,只有在使用带扩展运算符的直接String时才会发生。当你在一个数组中给出一个String时,整个数组将被视为可迭代对象,而不是内部的字符串。
var str = [ "hello" ,2 ];
var other = [ ...str ]; // [ "hello" ,2 ]
我知道上面的例子并没有多大意义,但只是为了表达在这种情况下字符串将被区别对待的事实。
答案 3 :(得分:0)
因为javascript中的字符串被视为一个字符数组。
例如,当你为一个字符串上的每个循环执行a(假设hello
)时,使用lodash:
_.forEach('hello', function(i) {
console.log(i)
})
输出:
h
e
l
l
o
像slice()
这样的函数也适用于字符串和数组。
答案 4 :(得分:0)
这里有两件事情。
首先,您正在使用数组解构。这允许您获取可迭代的值并将其中的值分配给各个变量。
其次,您正在使用rest参数。这会将迭代的任何剩余输出转换为数组。
因此,您的字符串'hello'
会迭代到其各个字符中,第一个字符将被忽略(因为您省略了目标),然后其余字符将转换为数组并分配给w
。< / p>