ES2018 和 ES2019

A.2 对象字面量的剩余操作符和扩展操作符
ECMAScript 2018 将数组中的剩余操作符和扩展操作符也移植到了对象字面量。这极大地方便了对
象合并和通过其他对象创建新对象。
A.2.1 剩余操作符
剩余操作符可以在解构对象时将所有剩下未指定的可枚举属性收集到一个对象中。比如:
const person = { name: ‘Matt’, age: 27, job: ‘Engineer’ };
const { name, …remainingData } = person;
console.log(name); // Matt
console.log(remainingData); // { age: 27, job: ‘Engineer’ }
每个对象字面量中最多可以使用一次剩余操作符,而且必须放在最后。因为每个对象字面量只能有
一个剩余操作符,所以可以嵌套剩余操作符。嵌套时,因为子属性对应的剩余操作符没有歧义,所以返
回对象的内容不会重叠:
const person = { name: ‘Matt’, age: 27, job: { title: ‘Engineer’, level: 10 } };
const { name, job: { title, …remainingJobData }, …remainingPersonData } = person;
console.log(name); // Matt
console.log(title); // Engineer
console.log(remainingPersonData); // { age: 27 }
console.log(remainingJobData); // { level: 10 }
const { …a, job } = person;
// SyntaxError: Rest element must be last element
剩余操作符在对象间执行浅复制,因此会复制对象的引用而不会克隆整个对象:
const person = { name: ‘Matt’, age: 27, job: { title: ‘Engineer’, level: 10 } };
const { …remainingData } = person;
console.log(person === remainingData); // false
console.log(person.job === remainingData.job); // true
A.2.2 扩展操作符
扩展操作符可以像拼接数组一样合并两个对象。应用到内部对象的扩展操作符会对所有自有可枚举
属性执行浅复制到外部对象,包括符号:
const s = Symbol();
const foo = { a: 1 };
const bar = { [s]: 2 };
const foobar = {…foo, c: 3, …bar};
console.log(foobar);
// { a: 1, c: 3 Symbol(): 2 }
扩展对象的顺序很重要,主要有两个原因。
(1) 对象跟踪插入顺序。从扩展对象复制的属性按照它们在对象字面量中列出的顺序插入。
(2) 对象会覆盖重名属性。在出现重名属性时,会使用后出现属性的值。
下面的例子演示了上述约定:
const foo = { a: 1 };
const bar = { b: 2 };
const foobar = {c: 3, …bar, …foo};
console.log(foobar);
// { c: 3, b: 2, a: 1 }
const baz = { c: 4 };
const foobarbaz = {…foo, …bar, c: 3, …baz};
console.log(foobarbaz);
// { a: 1, b: 2, c: 4 }
与剩余操作符一样,所有复制都是浅复制:
const foo = { a: 1 };
const bar = { b: 2, c: { d: 3 } };
const foobar = {…foo, …bar};
console.log(foobar.c === bar.c); // true

A.5 数组打平方法

ECMAScript 2019 在 Array.prototype 上增加了两个方法:flat()和 flatMap()。这两个方法
为打平数组提供了便利。如果没有这两个方法,则打平数组就要使用迭代或递归。
注意 flat()和 flatMap()只能用于打平嵌套数组。嵌套的可迭代对象如 Map 和 Set
不能打平。
A.5.1 Array.prototype.flatten()
下面是如果没有这两个新方法要打平数组的一个示例实现:
function flatten(sourceArray, flattenedArray = []) {
for (const element of sourceArray) {
if (Array.isArray(element)) {
flatten(element, flattenedArray);
} else {
flattenedArray.push(element);
}
}
return flattenedArray;
}
const arr = [[0], 1, 2, [3, [4, 5]], 6];
console.log(flatten(arr))
// [0, 1, 2, 3, 4, 5, 6]
这个例子在很多方面像一个树形数据结构:数组中每个元素都像一个子节点,非数组元素是叶节点。
因此,这个例子中的输入数组是一个高度为 2 有 7 个叶节点的树。打平这个数组本质上是对叶节点的按
序遍历。
有时候如果能指定打平到第几级嵌套是很有用的。比如下面这个例子,它重写了上面的版本,允许
指定要打平几级:
function flatten(sourceArray, depth, flattenedArray = []) {
for (const element of sourceArray) {
if (Array.isArray(element) && depth > 0) {
flatten(element, depth - 1, flattenedArray);
} else {
flattenedArray.push(element);
}
}
return flattenedArray;
}
const arr = [[0], 1, 2, [3, [4, 5]], 6];
console.log(flatten(arr, 1));
// [0, 1, 2, 3, [4, 5], 6]
为了解决上述问题,规范增加了 Array.prototype.flat()方法。该方法接收 depth 参数(默认
值为 1),返回一个对要打平 Array 实例的浅复制副本。下面看几个例子:
const arr = [[0], 1, 2, [3, [4, 5]], 6];
console.log(arr.flat(2));
// [0, 1, 2, 3, 4, 5, 6]
console.log(arr.flat());
// [0, 1, 2, 3, [4, 5], 6]
因为是执行浅复制,所以包含循环引用的数组在被打平时会从源数组复制值:
const arr = [[0], 1, 2, [3, [4, 5]], 6];
arr.push(arr);
console.log(arr.flat());
// [0, 1, 2, 3, 4, 5, 6, [0], 1, 2, [3, [4, 5]], 6]

猜你喜欢

转载自blog.csdn.net/cs18335818140/article/details/113832137