如果不能迭代,对象散布如何工作?

时间:2018-06-28 13:54:11

标签: javascript ecmascript-6 javascript-objects

我正在学习传播的新用途。我意识到 object spread 是ES2018的提案。它可以通过以下方式在节点10.5中工作:

const oldObj = {name:"doug", age:34};
const newObj = {...oldObj}; 
console.log(newObj); // { name: 'doug', age: 34 }

扩展的一种有趣用法是将可迭代对象转换为数组。例如,它可以与Maps配合使用,为您提供一个值对数组的数组

const mappie = new Map().set("name", "doug").set("age", 234).set("profession", "seeker of Cthulhu");

const arr1 = [...mappie];

console.log(arr1); // [ [ 'name', 'doug' ], [ 'age', 234 ], [ 'profession', 'seeker of Cthulhu' ] ]

但是我不能在对象上使用

const obj = {
  name: "doug",
  age: 234,
  profession: "seeker of Chthulhu"
};

const arr2 = [...obj];
console.log(arr2);

给我

TypeError: obj is not iterable

好的,我知道对象是不可迭代的(目前)。但是,物体传播可重复传播是某种不同的生物吗?那是它在某些情况下会起作用,而在其他情况下则不会,并且应该只意识到对象只能散布到对象中,而不能散布到数组中?还是我错过了全局?我试图了解 spread 的新用法,并希望得到启发。...

2 个答案:

答案 0 :(得分:2)

  

但是物体传播可迭代传播是某种不同的生物吗?

是的。属性传播完全不使用迭代。它是新的主要语法,其运行时语义是在by the spec中定义的,而不是在iterables / iteration方面:

  

PropertyDefinition:... AssignmentExpression

     
      
  1. 让exprValue是评估AssignmentExpression的结果。
  2.   
  3. 让fromValue为? GetValue(exprValue)。
  4.   
  5. 让excludeNames为新的空列表。
  6.   
  7. 返回? CopyDataProperties(对象,fromValue,excludedNames)。
  8.   

属性扩展专门用于对象属性,没有像可扩展扩展那样对它进行额外的概括。 (也不是马上就会知道。:-))

对于您的const arr2 = [...obj];用例,您可能需要Object.entries

const arr2 = Object.entries(obj);

示例:

const obj = {
  name: "doug",
  age: 234,
  profession: "seeker of Chthulhu"
};
const arr2 = Object.entries(obj);
console.log(arr2);

...或Object.keys(如果您只需要属性名称),或Object.values(如果您只想要值)。

当然,您可以根据需要使对象可迭代:只需为其提供迭代器即可。例如:

const obj = {
  name: "doug",
  age: 234,
  profession: "seeker of Chthulhu",
  * [Symbol.iterator]() {
    return yield* Object.entries(this);
  }
};
const arr2 = [...obj];
console.log(arr2);

您可以通过为它们创建的任何类的实例定义合适的迭代器,并在原型上提供一个Symbol.iterator命名的属性,来使其可迭代:

class ExampleList {
    constructor() {
        this.head = this.tail = null;
    }

    add(value) {
        const entry = {value, next: null};
        if (!this.tail) {
            this.head = this.tail = entry;
        } else {
            this.tail = this.tail.next = entry;
        }
    }

    * [Symbol.iterator]() {
        for (let current = this.head; current; current = current.next) {
            yield current.value;
        }
    }
}

const list = new ExampleList();
list.add("a");
list.add("b");
list.add("c");

for (const value of list) {
    console.log(value);
}

  

那是在某些情况下会起作用,但在其他情况下不会...

嗯,一般来说,传播符号是正确的。属性扩展仅在对象初始化程序中定义,并且仅在操作数是某种对象时才起作用。 (与之对应的新属性rest表示法是在解构分配模式中定义。)可迭代的扩展仅在数组初始化程序和函数参数列表中定义,并且仅在其操作数是某种可迭代的情况下才起作用。 (及其对应的可迭代休息符号在创建数组的解构分配模式中定义。)

答案 1 :(得分:2)

T.J。 Crowder的回答是正确的,但是对于评论来说太长了,希望对实用程序有更好的理解:考虑经常需要从对象中获取几个属性并将它们放入新对象的情况。几个第三方库(例如Ramda和lodash)实现了实用程序功能,但是结合了速记属性,解构和对象散布,可以在原始JS中简洁地完成它:

const foo = { a: 1, b: 2, c: 3, d: 4 };
const { a, d } = foo;
const bar = { a, d };
console.log(bar); // { a: 1, d: 4 }

如果您不介意滥用逗号运算符,则可以进一步缩短此时间:

let a, d, bar, foo = { a: 1, b: 2, c: 3, d: 4 };
bar = ({a, d} = foo, {a, d});