简单介绍
ES6 语法中,允许按照规定的方式,从数组和对象中提取值,来对变量进行赋值,称之为解构。
ES5中,我们给变量赋值都是通过 var 定义的方式
var a = 1
var arr = []
var obj = {}
详细分析
数组的解构赋值
在ES6中只要数据有 Iterator 接口,都可以进行解构赋值。Iterator(遍历器)也是一个在 ES6 中很神奇的东西,其实它在很多语言中也有,这个我们会在后面分析的,我们这里就对于有 Iterator 接口的,都可以进行解构赋值就行。
eg1:
// ES6
let [a, b, c] = [1, 2, 3]
// ES5
var a = 1,
b = 2,
c = 3;
上面就是将数组进行解构,可以从数组中提取值,按照对应位置,对变量进行一个赋值操作,换成 ES5 大家就很明显可以理解了。
在其他教程上都对于这种写法,认为是一个模式匹配,只要等号两边的模式相同,左边的变量就会被赋予右边对应的值。
eg2:
// 模式匹配
let [a, [[b], c]] = [1, [[2], 3]]
// a = 1 b = 2 c = 3
// 省略解构
let [, a, b] = [1, 2, 3, 4]
// a =2 b = 3
// 含剩余参数的解构
let [a, ...rest] = [1, 2, 3, 4, 5]
// var a = 1, rest = [2, 3, 4, 5];
//剩余参数没有值的时候
let [a,...reset] = [1]
var _ref = [1],
a = _ref[0],
reset = _ref.slice(1);
// 备注: 获取剩余数值时候,后面没有值的时候,返回的是个空数组
// 下面转为 ES5 也可以看到,将数组第一个 slice 了
当非数组用数组的方式解构的时候,即等号右边不是数组,且不是可遍历的结构,都会报错
eg:3
let [foo] = 1 // Uncaught TypeError: 1 is not iterable
let [foo1] = false // Uncaught TypeError: false is not iterable
let [foo2] = undefined // Uncaught TypeError: undefined is not iterable
let [foo3] = null // Uncaught TypeError: null is not iterable
let [foo4] = {} // Uncaught TypeError: {} is not iterable
let [foo5] = NaN // Uncaught TypeError: NaN is not iterable
// 以上都会报错
因为上面转成 ES5 都能知道了
var _ = 1,
foo = _[0];//报错
// 其他都是同理
set的解构赋值
ES6 提供了新的数据结构 Set,类似于数组的一个新的数据解构。set对象是值的集合,元素只会出现一次,即Set中的元素是唯一的。
eg1:
let [x, y] = new Set([1, 2])
// x => 1
// y => 2
Generator 函数解构
Generator 函数后面我们会单独写一章来分析的,这里我们就知道 Generator 函数是有 Iterator 的,所以是可以 for of,或者说是可以解构的。
eg1:
function* fun(){
let a = 0;
let b = 1;
while(true){
yield a;
[a,b] = [b,a+b];
}
}
let [first,second,third,fourth,fifth,sixth] = fun();
console.log(sixth); //结果为5
解构时的默认值
eg1:
// ES6
let [a=3, b = 5] = [undefined, 4]
// a => 3
// b => 5
// ES5
var _undefined = undefined,
a = _undefined === void 0 ? 3 : _undefined,
_ = 4,
b = _ === void 0 ? 5 : _;
下面这段转为 ES5,其实就是多了是否为 undefined 的判断,如果对应的右边是 undefined,但是左右有默认值,则变量还是为默认值。
对象的解构赋值
数组因为是线性的结构,所以数组的解构是按次序排列来的,变量取值是按照对应位置来的。而对象的属性是没有顺序的,所以对象解构的时候,必须与对象的属性同名才能取到正确的值。
eg1:
// ES6
let { a, b } = { a: 1, b: 2 }
// a => 1
// b => 2
// ES5
var _a$b = {
a: 1,
b: 2
},
a = _a$b.a,
b = _a$b.b;
实际上就是将对象里面对应属性名的值赋给解构中的变量。
eg2:
// ES6
let {a: c, b: d} = {a: 3, b: 4}
a => undefined
b => undefined
c => 3
d => 4
// ES5
var _a$b = {
a: 3,
b: 4
},
c = _a$b.b,
d = _a$b.a;
在上面 ES6 中的解构,可以看到,其中 a 和 b 是 undefined,而对应的 ES5 中,其实就是对 c 和 d 进行了对应位置的赋值。
所以,对象的解构内部机制应该是先找到同名的属性,然后再赋予相应的变量,真正被赋予的是前一个对象的后一个变量,即上面的 c 和 d,而不是左边对象的模式,即 a 和 b。
eg3:
// ES6
let e = {a: c, b: d} = {a: 3, b: 4}
e.a => 3
e.b => 4
c => 3
d => 4
a => undefined
b => undefined
对象解构中的括号问题
eg1:
let a
[a] = [3]
a => 3
eg2:
let a
{ a } = { a: 3 }
// Uncaught SyntaxError: Unexpected token '='
对于这里数组解构和对象解构,数组是可以完成解构的,但是对象会报错。因为 [a] 再js引擎中,只会理解为成一个数组。但是对于 {a},js引擎可能理解成一个代码块或者理解成一个对象。现在对于行首是 {} 的,全部都理解为代码块,所以要让js引擎不认为这是代码块。
eg3:
let a
({a} = {a: 3})
这里用括号将 {} 包起来的,都是表达式。这样再表达式内部,{} 就可以被认为是一个对象了,就可以顺利的解构了。
字符串的解构赋值
let [a, b, c] = '123'
// a => 1
// b => 2
// c => 3
typeof a => string 字符串解构出来还是字符串
对于字符串的长度
let {length: s} = '123'
// s => 3
// typeof s => number
这里 length 是为了和字符串中属性 length 对应,然后对应长度值赋值给 s,得到字符串长度。
函数参数的解构赋值
function test([x, y]) {
console.log(x, y)
}
test([1, 2]) // 1, 2
总结
以上就是对于解构赋值的一些学习笔记,解构赋值在 ES6 开发过程中能使代码更优雅,我们在获取对象或者对应数组各类取值,都可以使用这种方式来拿到值,不需要再使用之前 var 定义一堆变量了,并且取不到的变量也默认定义后是 undefined 了。对于解构赋值大家如果还有更多见解,欢迎评论讨论呀。