Skip to content

Commit

Permalink
261
Browse files Browse the repository at this point in the history
  • Loading branch information
ascoders committed Oct 31, 2022
1 parent 312cb81 commit 865ea3e
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 1 deletion.
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

前端界的好文精读,每周更新!

最新精读:<a href="./前沿技术/260.%E7%B2%BE%E8%AF%BB%E3%80%8A%E5%A6%82%E4%BD%95%E4%B8%BA%20TS%20%E7%B1%BB%E5%9E%8B%E5%86%99%E5%8D%95%E6%B5%8B%E3%80%8B.md">260.精读《如何为 TS 类型写单测》</a>
最新精读:<a href="./前沿技术/261.%E7%B2%BE%E8%AF%BB%E3%80%8ARest%20vs%20Spread%20%E8%AF%AD%E6%B3%95%E3%80%8B.md">261.精读《Rest vs Spread 语法》</a>

素材来源:[周刊参考池](https://github.com/ascoders/weekly/issues/2)

Expand Down Expand Up @@ -199,6 +199,7 @@
- <a href="./前沿技术/258.%E7%B2%BE%E8%AF%BB%E3%80%8Aproposal-extractors%E3%80%8B.md">258.精读《proposal-extractors》</a>
- <a href="./前沿技术/259.%E7%B2%BE%E8%AF%BB%E3%80%8AHeadless%20%E7%BB%84%E4%BB%B6%E7%94%A8%E6%B3%95%E4%B8%8E%E5%8E%9F%E7%90%86%E3%80%8B.md">259.精读《Headless 组件用法与原理》</a>
- <a href="./前沿技术/260.%E7%B2%BE%E8%AF%BB%E3%80%8A%E5%A6%82%E4%BD%95%E4%B8%BA%20TS%20%E7%B1%BB%E5%9E%8B%E5%86%99%E5%8D%95%E6%B5%8B%E3%80%8B.md">260.精读《如何为 TS 类型写单测》</a>
- <a href="./前沿技术/261.%E7%B2%BE%E8%AF%BB%E3%80%8ARest%20vs%20Spread%20%E8%AF%AD%E6%B3%95%E3%80%8B.md">261.精读《Rest vs Spread 语法》</a>

### TS 类型体操

Expand Down
142 changes: 142 additions & 0 deletions 前沿技术/261.精读《Rest vs Spread 语法》.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
符号 `...` 在 JS 语言里同时被用作 Rest 与 Spread 两个场景,本周我们就结合 [Rest vs Spread syntax in JavaScript](https://www.amitmerchant.com/rest-vs-spread-syntax-in-javascript/) 聊聊这两者的差异以及一些坑。

## 概述

### Spread

`...` 作为 Spread 含义时,效果为扩散对象的属性:

```ts
const obj = {
a: 1,
b: 2,
c: 3,
};

const newObj = {
...obj,
};

console.log(newObj);
// { a: 1, b: 2, c: 3 }
```

`...` 符号很形象的表示了把对象中所有属性拿出来平铺的含义。说到平铺,Spread 放在函数参数时,也表示将对象中每个 properties 拿出来作为平铺参数:

```ts
const arr = [1, 2, 3];

const sum = (a, b, c) => a + b + c;

console.log(sum(...arr)); // Outputs: 6
// ^
// sum(1, 2, 3)
```

### Rest

`...` 作 Rest 含义时,表示将多个值收集为一个数组,如用在函数定义的位置:

```ts
const sum = (...args) => {
return args.reduce((acc, curr) => acc + curr, 0);
// ^
// [1, 2, 3]
};

console.log(sum(1, 2, 3));
// 6
```

当然也可以在 `...` 前面放置其他变量,这样 `...` 仅聚合剩余的变量。`...` 之后不能再定义变量或者 `...`

```ts
const sum = (a, b, ...restOfArguments) => {
return a + b + restOfArguments.reduce((acc, curr) => acc + curr, 0);
// ^ ^ ^
// 1 2 [3, 4, 5]
};

console.log(sum(1, 2, 3, 4, 5));
// 15
```

## 精读

### Rest 处理 Set 与 Map

`Set``Map` 都可以通过数组模式赋初值:

```ts
const mySet = new Set(["a", "b", "c"]);
const myMap = new Map([
["a", 1],
["b", 2],
["c", 3],
]);
```

`...` 符号作 `Rest` 用途时,可以将其解构为数组:

```ts
[...mySet] // ['a', 'b', 'c']
[...myMap] // [ ['a', 1], ['b', 2], ['c', 3] ]
```

特别的,Map 与 Set 仅支持数组方式解构,不支持对象模式解构:

```ts
{...mySet} // {}
{...myMap} // {}
```

但对于一个普通数组,是同时支持数组与对象模式解构的:

```ts
const arr = ['a', 'b', 'c']
[...arr] // ['a', 'b', 'c']
{...arr} // {0: 'a', 1: 'b', 2: 'c'}
```

这是因为数组变量有潜在的下标,这些下标可以转换为对象的 Key,而 `Map` `Set` 不存在下标,所以转换为对象找不到 Key,因此就不支持对象模式的解构。

更具体的原因与对象的可迭代性有关,虽然 `Map``Set` 都支持迭代,但如果用 `for key of` 来测试,会发现它们的 key 是 `undefined`

### Spread 会丢失 get() 与 set()

Spread 并不代表完整复制整个对象,它能拷贝这个对象属性定义中的瞬时值,比如:

```ts
const obj = {
a: 1,
b: get() { return 2 }
}
const newObj = { ...obj }
```

`newObj.b` 属性不再是 `get()` 方法,而是固定值 `2`,这在 `get()` 函数内返回非固定值,或希望懒加载代码时会产生问题。

究其原因,Spread 毕竟不是在定义对象,更恰当的理解应该是 “访问对象”,所以访问的结果就是执行 `get()`

### Rest 会跳过不可枚举属性

```ts
const err = new Error('error')
{...error} // {}
```

`Error` 拥有两个不可枚举属性 `message``stack`,所以不会被 Rest 收集到,遇到这种场景可以使用其他方式,如直接访问 `error.message`

## 总结

`...` 用在赋值位置含义为 Spread,用在参数收集位置含义为 Rest,同时因为该语法写起来很简单,因此有一些默认逻辑小心不要掉坑里,比如默认会执行对象属性的 `getter`,会跳过不可枚举属性等。

> 讨论地址是:[精读《Rest vs Spread 语法》· Issue #447 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/447)
**如果你想参与讨论,请 [点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。**

> 关注 **前端精读微信公众号**
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">

> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)

0 comments on commit 865ea3e

Please sign in to comment.