From 865ea3e1aa471de2a9bd9085d524b0bd9dbf29ff Mon Sep 17 00:00:00 2001
From: ascoders <576625322@qq.com>
Date: Mon, 31 Oct 2022 08:54:41 +0800
Subject: [PATCH] 261
---
readme.md | 3 +-
...d \350\257\255\346\263\225\343\200\213.md" | 142 ++++++++++++++++++
2 files changed, 144 insertions(+), 1 deletion(-)
create mode 100644 "\345\211\215\346\262\277\346\212\200\346\234\257/261.\347\262\276\350\257\273\343\200\212Rest vs Spread \350\257\255\346\263\225\343\200\213.md"
diff --git a/readme.md b/readme.md
index a85cc18c..52bfcb2d 100644
--- a/readme.md
+++ b/readme.md
@@ -6,7 +6,7 @@
前端界的好文精读,每周更新!
-最新精读:260.精读《如何为 TS 类型写单测》
+最新精读:261.精读《Rest vs Spread 语法》
素材来源:[周刊参考池](https://github.com/ascoders/weekly/issues/2)
@@ -199,6 +199,7 @@
- 258.精读《proposal-extractors》
- 259.精读《Headless 组件用法与原理》
- 260.精读《如何为 TS 类型写单测》
+- 261.精读《Rest vs Spread 语法》
### TS 类型体操
diff --git "a/\345\211\215\346\262\277\346\212\200\346\234\257/261.\347\262\276\350\257\273\343\200\212Rest vs Spread \350\257\255\346\263\225\343\200\213.md" "b/\345\211\215\346\262\277\346\212\200\346\234\257/261.\347\262\276\350\257\273\343\200\212Rest vs Spread \350\257\255\346\263\225\343\200\213.md"
new file mode 100644
index 00000000..2eed5f76
--- /dev/null
+++ "b/\345\211\215\346\262\277\346\212\200\346\234\257/261.\347\262\276\350\257\273\343\200\212Rest vs Spread \350\257\255\346\263\225\343\200\213.md"
@@ -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),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。**
+
+> 关注 **前端精读微信公众号**
+
+
+
+> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh))