我正在学习传播的新用途。我意识到 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 的新用法,并希望得到启发。...
答案 0 :(得分:2)
但是物体传播和可迭代传播是某种不同的生物吗?
是的。属性传播完全不使用迭代。它是新的主要语法,其运行时语义是在by the spec中定义的,而不是在iterables / iteration方面:
PropertyDefinition:... AssignmentExpression
- 让exprValue是评估AssignmentExpression的结果。
- 让fromValue为? GetValue(exprValue)。
- 让excludeNames为新的空列表。
- 返回? CopyDataProperties(对象,fromValue,excludedNames)。
属性扩展专门用于对象属性,没有像可扩展扩展那样对它进行额外的概括。 (也不是马上就会知道。:-))
对于您的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});