为什么扩展语法将我的字符串转换为数组?

时间:2017-07-04 07:58:09

标签: javascript ecmascript-6

为什么扩展语法会将我的字符串转换为数组?

var v = 'hello';
var [, ...w] = v; // ["e", "l", "l", "o"]

为什么w不是字符串?

5 个答案:

答案 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]

     
      
  1. 迭代器GetIterator value )。
  2.   
  3. ReturnIfAbrupt迭代)。
  4.   
  5. iteratorRecord 为Record {[[iterator]]: iterator ,[[done]]: false }。
  6.   
  7. 如果存在 Elision ,则为   一个。让状态是以 iteratorRecord 作为参数执行 Elision IteratorDestructuringAssignmentEvaluation的结果。
      湾如果状态abrupt completion,则为   一世。如果 iteratorRecord 。[[done]]为 false ,则返回IteratorClose迭代器状态) 。
      II。返回Completion状态)。
  8.   
  9. 结果成为执行 AssignmentRestElement IteratorDestructuringAssignmentEvaluation并将 iteratorRecord 作为参数的结果。
  10.   
  11. 如果 iteratorRecord 。[[done]]为 false ,则返回IteratorClose迭代器结果)。
  12.   
  13. 返回结果
  14.   

这里, 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属性 - 通过将自己的iteratorgenerator / 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>