2
2
3
3
## 数组的解构赋值
4
4
5
+ ### 基本用法
6
+
5
7
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
6
8
7
9
以前,为变量赋值,只能直接指定值。
@@ -28,7 +30,7 @@ foo // 1
28
30
bar // 2
29
31
baz // 3
30
32
31
- let [,, third] = [" foo" , " bar" , " baz" ];
33
+ let [ , , third] = [" foo" , " bar" , " baz" ];
32
34
third // "baz"
33
35
34
36
let [x, , y] = [1 , 2 , 3 ];
@@ -38,16 +40,21 @@ y // 3
38
40
let [head, ... tail] = [1 , 2 , 3 , 4 ];
39
41
head // 1
40
42
tail // [2, 3, 4]
43
+
44
+ let [x, y, ... z] = [' a' ];
45
+ x // "a"
46
+ y // undefined
47
+ z // []
41
48
```
42
49
43
- 如果解构不成功,变量的值就等于undefined 。
50
+ 如果解构不成功,变量的值就等于 ` undefined ` 。
44
51
45
52
``` javascript
46
53
var [foo] = [];
47
54
var [bar, foo] = [1 ];
48
55
```
49
56
50
- 以上两种情况都属于解构不成功,foo的值都会等于undefined 。
57
+ 以上两种情况都属于解构不成功,` foo ` 的值都会等于 ` undefined ` 。
51
58
52
59
另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
53
60
@@ -73,29 +80,10 @@ let [foo] = false;
73
80
let [foo] = NaN ;
74
81
let [foo] = undefined ;
75
82
let [foo] = null ;
83
+ let [foo] = {};
76
84
```
77
85
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接口(最后一个表达式)。
99
87
100
88
解构赋值不仅适用于var命令,也适用于let和const命令。
101
89
@@ -130,6 +118,62 @@ sixth // 5
130
118
131
119
上面代码中,` fibs ` 是一个Generator函数,原生具有Iterator接口。解构赋值会依次从这个接口获取值。
132
120
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
+
133
177
## 对象的解构赋值
134
178
135
179
解构不仅可以用于数组,还可以用于对象。
@@ -181,6 +225,26 @@ foo // error: foo is not defined
181
225
182
226
上面代码中,真正被赋值的是变量` baz ` ,而不是模式` foo ` 。
183
227
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
+
184
248
和数组一样,解构也可以用于嵌套结构的对象。
185
249
186
250
``` javascript
@@ -216,17 +280,30 @@ start // error: start is undefined
216
280
217
281
上面代码中,只有` line ` 是变量,` loc ` 和` start ` 都是模式,不会被赋值。
218
282
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
+
219
295
对象的解构也可以指定默认值。
220
296
221
297
``` javascript
222
298
var {x = 3 } = {};
223
299
x // 3
224
300
225
301
var {x, y = 5 } = {x: 1 };
226
- console .log (x, y) // 1, 5
302
+ x // 1
303
+ y // 5
227
304
228
305
var { message: msg = " Something went wrong" } = {};
229
- console . log ( msg); // "Something went wrong"
306
+ msg // "Something went wrong"
230
307
```
231
308
232
309
默认值生效的条件是,对象的属性值严格等于` undefined ` 。
@@ -276,18 +353,28 @@ var x;
276
353
277
354
``` javascript
278
355
// 正确的写法
279
- ({x} = {x: 1 });
356
+ ({x} = {x: 1 });
280
357
```
281
358
282
359
上面代码将整个解构赋值语句,放在一个圆括号里面,就可以正确执行。关于圆括号与解构赋值的关系,参见下文。
283
360
361
+ 解构赋值允许,等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式。
362
+
363
+ ``` javascript
364
+ ({} = [true , false ]);
365
+ ({} = ' abc' );
366
+ ({} = []);
367
+ ```
368
+
369
+ 上面的表达式虽然毫无意义,但是语法是合法的,可以执行。
370
+
284
371
对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。
285
372
286
373
``` javascript
287
374
let { log, sin, cos } = Math ;
288
375
```
289
376
290
- 上面代码将Math对象的对数 、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多。
377
+ 上面代码将 ` Math ` 对象的对数 、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多。
291
378
292
379
## 字符串的解构赋值
293
380
@@ -309,9 +396,30 @@ let {length : len} = 'hello';
309
396
len // 5
310
397
```
311
398
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
+
312
420
## 函数参数的解构赋值
313
421
314
- 函数的参数也可以使用解构 。
422
+ 函数的参数也可以使用解构赋值 。
315
423
316
424
``` javascript
317
425
function add ([x , y ]){
@@ -321,7 +429,7 @@ function add([x, y]){
321
429
add ([1 , 2 ]) // 3
322
430
```
323
431
324
- 上面代码中,函数add的参数实际上不是一个数组,而是通过解构得到的变量x和y 。
432
+ 上面代码中,函数add的参数实际上不是一个数组,而是通过解构得到的变量 ` x ` 和 ` y ` 。
325
433
326
434
函数参数的解构也可以使用默认值。
327
435
@@ -336,7 +444,7 @@ move({}); // [0, 0]
336
444
move (); // [0, 0]
337
445
```
338
446
339
- 上面代码中,函数move的参数是一个对象 ,通过对这个对象进行解构,得到变量x和y的值 。如果解构失败,x和y等于默认值 。
447
+ 上面代码中,函数 ` move ` 的参数是一个对象 ,通过对这个对象进行解构,得到变量 ` x ` 和 ` y ` 的值 。如果解构失败,` x ` 和 ` y ` 等于默认值 。
340
448
341
449
注意,指定函数参数的默认值时,不能采用下面的写法。
342
450
@@ -421,9 +529,7 @@ function f([(z)]) { return z; }
421
529
** (1)交换变量的值**
422
530
423
531
``` javascript
424
-
425
532
[x, y] = [y, x];
426
-
427
533
```
428
534
429
535
上面代码交换变量x和y的值,这样的写法不仅简洁,而且易读,语义非常清晰。
@@ -433,7 +539,6 @@ function f([(z)]) { return z; }
433
539
函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。
434
540
435
541
``` javascript
436
-
437
542
// 返回一个数组
438
543
439
544
function example () {
@@ -450,23 +555,20 @@ function example() {
450
555
};
451
556
}
452
557
var { foo, bar } = example ();
453
-
454
558
```
455
559
456
560
** (3)函数参数的定义**
457
561
458
562
解构赋值可以方便地将一组参数与变量名对应起来。
459
563
460
564
``` javascript
461
-
462
565
// 参数是一组有次序的值
463
566
function f ([x , y , z ]) { ... }
464
567
f ([1 , 2 , 3 ])
465
568
466
569
// 参数是一组无次序的值
467
570
function f ({x, y, z}) { ... }
468
- f ({x: 1 , y: 2 , z: 3 })
469
-
571
+ f ({z: 3 , y: 2 , x: 1 })
470
572
```
471
573
472
574
** (4)提取JSON数据**
@@ -510,10 +612,9 @@ jQuery.ajax = function (url, {
510
612
511
613
** (6)遍历Map结构**
512
614
513
- 任何部署了Iterator接口的对象,都可以用for ...of循环遍历 。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便。
615
+ 任何部署了Iterator接口的对象,都可以用 ` for ...of ` 循环遍历 。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便。
514
616
515
617
``` javascript
516
-
517
618
var map = new Map ();
518
619
map .set (' first' , ' hello' );
519
620
map .set (' second' , ' world' );
@@ -523,13 +624,11 @@ for (let [key, value] of map) {
523
624
}
524
625
// first is hello
525
626
// second is world
526
-
527
627
```
528
628
529
629
如果只想获取键名,或者只想获取键值,可以写成下面这样。
530
630
531
631
``` javascript
532
-
533
632
// 获取键名
534
633
for (let [key] of map) {
535
634
// ...
@@ -539,7 +638,6 @@ for (let [key] of map) {
539
638
for (let [,value] of map) {
540
639
// ...
541
640
}
542
-
543
641
```
544
642
545
643
** (7)输入模块的指定方法**
0 commit comments