Skip to content

Commit ee59620

Browse files
committed
edit docs/destructuring
1 parent 7bad020 commit ee59620

File tree

3 files changed

+190
-63
lines changed

3 files changed

+190
-63
lines changed

docs/async.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ function thunkify(fn){
370370
};
371371
```
372372

373-
它的源码主要多了一个检查机制,变量called确保回调函数只运行一次。这样的设计与下文的Generator函数相关。请看下面的例子。
373+
它的源码主要多了一个检查机制,变量`called`确保回调函数只运行一次。这样的设计与下文的Generator函数相关。请看下面的例子。
374374

375375
```javascript
376376
function f(a, b, callback){
@@ -380,11 +380,12 @@ function f(a, b, callback){
380380
}
381381

382382
var ft = thunkify(f);
383-
ft(1, 2)(console.log);
383+
var print = console.log.bind(console);
384+
ft(1, 2)(print);
384385
// 3
385386
```
386387

387-
上面代码中,由于thunkify只允许回调函数执行一次,所以只输出一行结果。
388+
上面代码中,由于`thunkify`只允许回调函数执行一次,所以只输出一行结果。
388389

389390
### Generator 函数的流程管理
390391

docs/destructuring.md

Lines changed: 141 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## 数组的解构赋值
44

5+
### 基本用法
6+
57
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
68

79
以前,为变量赋值,只能直接指定值。
@@ -28,7 +30,7 @@ foo // 1
2830
bar // 2
2931
baz // 3
3032

31-
let [,,third] = ["foo", "bar", "baz"];
33+
let [ , , third] = ["foo", "bar", "baz"];
3234
third // "baz"
3335

3436
let [x, , y] = [1, 2, 3];
@@ -38,16 +40,21 @@ y // 3
3840
let [head, ...tail] = [1, 2, 3, 4];
3941
head // 1
4042
tail // [2, 3, 4]
43+
44+
let [x, y, ...z] = ['a'];
45+
x // "a"
46+
y // undefined
47+
z // []
4148
```
4249

43-
如果解构不成功,变量的值就等于undefined
50+
如果解构不成功,变量的值就等于`undefined`
4451

4552
```javascript
4653
var [foo] = [];
4754
var [bar, foo] = [1];
4855
```
4956

50-
以上两种情况都属于解构不成功,foo的值都会等于undefined
57+
以上两种情况都属于解构不成功,`foo`的值都会等于`undefined`
5158

5259
另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
5360

@@ -73,29 +80,10 @@ let [foo] = false;
7380
let [foo] = NaN;
7481
let [foo] = undefined;
7582
let [foo] = null;
83+
let [foo] = {};
7684
```
7785

78-
解构赋值允许指定默认值。
79-
80-
```javascript
81-
var [foo = true] = [];
82-
foo // true
83-
84-
[x, y='b'] = ['a'] // x='a', y='b'
85-
[x, y='b'] = ['a', undefined] // x='a', y='b'
86-
```
87-
88-
注意,ES6内部使用严格相等运算符(===),判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值是不会生效的。
89-
90-
```javascript
91-
var [x = 1] = [undefined];
92-
x // 1
93-
94-
var [x = 1] = [null];
95-
x // null
96-
```
97-
98-
上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。
86+
上面的表达式都会报错,因为等号右边的值,要么转为对象以后不具备Iterator接口(前五个表达式),要么本身就不具备Iterator接口(最后一个表达式)。
9987

10088
解构赋值不仅适用于var命令,也适用于let和const命令。
10189

@@ -130,6 +118,62 @@ sixth // 5
130118

131119
上面代码中,`fibs`是一个Generator函数,原生具有Iterator接口。解构赋值会依次从这个接口获取值。
132120

121+
### 默认值
122+
123+
解构赋值允许指定默认值。
124+
125+
```javascript
126+
var [foo = true] = [];
127+
foo // true
128+
129+
[x, y = 'b'] = ['a'] // x='a', y='b'
130+
[x, y = 'b'] = ['a', undefined] // x='a', y='b'
131+
```
132+
133+
注意,ES6内部使用严格相等运算符(`===`),判断一个位置是否有值。所以,如果一个数组成员不严格等于`undefined`,默认值是不会生效的。
134+
135+
```javascript
136+
var [x = 1] = [undefined];
137+
x // 1
138+
139+
var [x = 1] = [null];
140+
x // null
141+
```
142+
143+
上面代码中,如果一个数组成员是`null`,默认值就不会生效,因为`null`不严格等于`undefined`
144+
145+
如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
146+
147+
```javascript
148+
function f(){
149+
console.log('aaa');
150+
}
151+
152+
let [x = f()] = [1];
153+
```
154+
155+
上面代码中,因为`x`能取到值,所以函数`f`根本不会执行。上面的代码其实等价于下面的代码。
156+
157+
```javascript
158+
let x;
159+
if ([1][0] === undefined) {
160+
x = f();
161+
} else {
162+
x = [1][0];
163+
}
164+
```
165+
166+
默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
167+
168+
```javascript
169+
let [x = 1, y = x] = []; // x=1; y=1
170+
let [x = 1, y = x] = [2]; // x=1; y=2
171+
let [x = 1, y = x] = [1, 2]; // x=1; y=2
172+
let [x = y, y = 1] = []; // ReferenceError
173+
```
174+
175+
上面最后一个表达式之所以会报错,是因为`x`用到默认值`y`时,`y`还没有声明。
176+
133177
## 对象的解构赋值
134178

135179
解构不仅可以用于数组,还可以用于对象。
@@ -181,6 +225,26 @@ foo // error: foo is not defined
181225

182226
上面代码中,真正被赋值的是变量`baz`,而不是模式`foo`
183227

228+
注意,采用这种写法时,变量的声明和赋值是一体的。对于let和const来说,变量不能重新声明,所以一旦赋值的变量以前声明过,就会报错。
229+
230+
```javascript
231+
let foo;
232+
let {foo} = {foo: 1}; // SyntaxError: Duplicate declaration "foo"
233+
234+
let baz;
235+
let {bar: baz} = {bar: 1}; // SyntaxError: Duplicate declaration "baz"
236+
```
237+
238+
上面代码中,解构赋值的变量都会重新声明,所以报错了。不过,因为`var`命令允许重新声明,所以这个错误只会在使用`let``const`命令时出现。如果没有第二个let命令,上面的代码就不会报错。
239+
240+
```javascript
241+
let foo;
242+
({foo} = {foo: 1}); // 成功
243+
244+
let baz;
245+
({bar: baz} = {bar: 1}); // 成功
246+
```
247+
184248
和数组一样,解构也可以用于嵌套结构的对象。
185249

186250
```javascript
@@ -216,17 +280,30 @@ start // error: start is undefined
216280

217281
上面代码中,只有`line`是变量,`loc``start`都是模式,不会被赋值。
218282

283+
下面是嵌套赋值的例子。
284+
285+
```javascript
286+
let obj = {};
287+
let arr = [];
288+
289+
({ foo: obj.prop, bar: arr[0] }) = { foo: 123, bar: true };
290+
291+
obj // {prop:123}
292+
arr // [true]
293+
```
294+
219295
对象的解构也可以指定默认值。
220296

221297
```javascript
222298
var {x = 3} = {};
223299
x // 3
224300

225301
var {x, y = 5} = {x: 1};
226-
console.log(x, y) // 1, 5
302+
x // 1
303+
y // 5
227304

228305
var { message: msg = "Something went wrong" } = {};
229-
console.log(msg); // "Something went wrong"
306+
msg // "Something went wrong"
230307
```
231308

232309
默认值生效的条件是,对象的属性值严格等于`undefined`
@@ -276,18 +353,28 @@ var x;
276353

277354
```javascript
278355
// 正确的写法
279-
({x} = {x:1});
356+
({x} = {x: 1});
280357
```
281358

282359
上面代码将整个解构赋值语句,放在一个圆括号里面,就可以正确执行。关于圆括号与解构赋值的关系,参见下文。
283360

361+
解构赋值允许,等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式。
362+
363+
```javascript
364+
({} = [true, false]);
365+
({} = 'abc');
366+
({} = []);
367+
```
368+
369+
上面的表达式虽然毫无意义,但是语法是合法的,可以执行。
370+
284371
对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。
285372

286373
```javascript
287374
let { log, sin, cos } = Math;
288375
```
289376

290-
上面代码将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多。
377+
上面代码将`Math`对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多。
291378

292379
## 字符串的解构赋值
293380

@@ -309,9 +396,30 @@ let {length : len} = 'hello';
309396
len // 5
310397
```
311398

399+
## 数值和布尔值的解构赋值
400+
401+
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
402+
403+
```javascript
404+
let {toString: s} = 123;
405+
s === Number.prototype.toString // true
406+
407+
let {toString: s} = true;
408+
s === Boolean.prototype.toString // true
409+
```
410+
411+
上面代码中,数值和布尔值的包装对象都有`toString`属性,因此变量`s`都能取到值。
412+
413+
解构赋值的规则是,只要等号右边的值不是对象,就先将其转为对象。由于`undefined``null`无法转为对象,所以对它们进行解构赋值,都会报错。
414+
415+
```javascript
416+
let { prop: x } = undefined; // TypeError
417+
let { prop: y } = null; // TypeError
418+
```
419+
312420
## 函数参数的解构赋值
313421

314-
函数的参数也可以使用解构
422+
函数的参数也可以使用解构赋值
315423

316424
```javascript
317425
function add([x, y]){
@@ -321,7 +429,7 @@ function add([x, y]){
321429
add([1, 2]) // 3
322430
```
323431

324-
上面代码中,函数add的参数实际上不是一个数组,而是通过解构得到的变量x和y
432+
上面代码中,函数add的参数实际上不是一个数组,而是通过解构得到的变量`x``y`
325433

326434
函数参数的解构也可以使用默认值。
327435

@@ -336,7 +444,7 @@ move({}); // [0, 0]
336444
move(); // [0, 0]
337445
```
338446

339-
上面代码中,函数move的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。如果解构失败,x和y等于默认值
447+
上面代码中,函数`move`的参数是一个对象,通过对这个对象进行解构,得到变量`x``y`的值。如果解构失败,`x``y`等于默认值
340448

341449
注意,指定函数参数的默认值时,不能采用下面的写法。
342450

@@ -421,9 +529,7 @@ function f([(z)]) { return z; }
421529
**(1)交换变量的值**
422530

423531
```javascript
424-
425532
[x, y] = [y, x];
426-
427533
```
428534

429535
上面代码交换变量x和y的值,这样的写法不仅简洁,而且易读,语义非常清晰。
@@ -433,7 +539,6 @@ function f([(z)]) { return z; }
433539
函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。
434540

435541
```javascript
436-
437542
// 返回一个数组
438543

439544
function example() {
@@ -450,23 +555,20 @@ function example() {
450555
};
451556
}
452557
var { foo, bar } = example();
453-
454558
```
455559

456560
**(3)函数参数的定义**
457561

458562
解构赋值可以方便地将一组参数与变量名对应起来。
459563

460564
```javascript
461-
462565
// 参数是一组有次序的值
463566
function f([x, y, z]) { ... }
464567
f([1, 2, 3])
465568

466569
// 参数是一组无次序的值
467570
function f({x, y, z}) { ... }
468-
f({x:1, y:2, z:3})
469-
571+
f({z: 3, y: 2, x: 1})
470572
```
471573

472574
**(4)提取JSON数据**
@@ -510,10 +612,9 @@ jQuery.ajax = function (url, {
510612

511613
**(6)遍历Map结构**
512614

513-
任何部署了Iterator接口的对象,都可以用for...of循环遍历。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便。
615+
任何部署了Iterator接口的对象,都可以用`for...of`循环遍历。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便。
514616

515617
```javascript
516-
517618
var map = new Map();
518619
map.set('first', 'hello');
519620
map.set('second', 'world');
@@ -523,13 +624,11 @@ for (let [key, value] of map) {
523624
}
524625
// first is hello
525626
// second is world
526-
527627
```
528628

529629
如果只想获取键名,或者只想获取键值,可以写成下面这样。
530630

531631
```javascript
532-
533632
// 获取键名
534633
for (let [key] of map) {
535634
// ...
@@ -539,7 +638,6 @@ for (let [key] of map) {
539638
for (let [,value] of map) {
540639
// ...
541640
}
542-
543641
```
544642

545643
**(7)输入模块的指定方法**

0 commit comments

Comments
 (0)