一、概念
对象是属性的集合,从对象里取值,ES3/5只能逐个取,而解构赋值表达式
可以实现批量取值,赋值。
// 数据对象person
var person = {
name: 'john',
age: 22
}
// ES5的方式:
var name = person.name,
age = person.age;
// ES6解构赋值方式
var {name, age} = person;
二、对象解构赋值
2.1 语法
// 格式1:声明即赋值
var {sourceObjKey1: targetValName1=defaultVal1, sourceObjKey2: targetValName2=defaultVal2, ..., sourceObjKeyN: targetValNameN=defaultValN} = sourceObj;
// 格式2, 先声明,后赋值。此时必须使用括号包裹整个赋值表达式
var targetValName1,targetValName2, ..., targetValNameN;
({sourceObjKey1: targetValName1=defaultVal1, sourceObjKey2: targetValName2 = defaultVal2, ...,sourceObjKeyN: targetValNameN=defaultValN} = sourceObj);
- sourceObj:表示数据源对象
- sourceObjKey:表示需要从数据源对象中取值的属性名称,如果和valName1同名,可以省略不写;
- targetValName:表示需要把获取的属性值赋值给的模板变量,即
targetValName=obj[sourceObjKey]
; - defaultVal:表示sourceObj对象不包含属性sourceObjKey(或者取值为undefined)时指定的默认值,可选的。
所以用ES5的表示方式相当于:
var targetValName1 = sourceObj[sourceObjKey1],
targetValName2 = sourceObj[sourceObjKey2],
targetValNameN = sourceObj[sourceObjKeyN];
如果key和valName的相同,可以简写为:
// 格式1:声明即赋值
var {targetValName1=defaultVal1, targetValName2=defaultVal2, ..., targetValNameN=defaultValN} = sourceObj;
// 格式2, 先声明,后赋值。此时括号是必须的
var targetValName1,targetValName2, ..., targetValNameN;
({targetValName1=defaultVal1, targetValName2=defaultVal2, ..., targetValNameN=defaultValN} = sourceObj);
大部分场景都是使用简写的方式。
假设有个对象dad:
// Object
var dad = {
name: 'john',
age: 30,
children: [
{
name: 'Tom',
age: 2
},
{
name: 'Jim',
age: 1
}
]
}
现在要把dad属性分别保存到变量name, age, children里:
// 格式1: 声明即赋值
var {name:name, age:age, children:children} = dad;
console.log(name); // john
console.log(age); // 30
console.log(children.length); // 2
// 格式2, 先声明,后赋值。此时括号是必须的,否则报语法错误
var name, age, children;
({name:name, age:age, children:children} = dad)
对应的简写格式:
// 格式1
var {name, age, children} = dad;
// 格式2
var name, age, children;
({name, age, children} = dad)
2.2 默认值
对于没有匹配到 或者匹配到的属性值为undefined的变量可以指定默认值。
dad.name = void 0; // dad定义见上例,
var { weight = '66kg', name='new name'} = dad; // dad没有定义weight属性
console.log(weight, name); // weight='66kg', name='new name'
2.3 动态属性名称
在上面的语法结构中
var {key1: valName1, key2: valName2, ..., keyN: valNameN} = obj;
其中key1,key2...keyN还可以是个变量,为了标识他们是变量而不是字面量,则需用用中括号包裹:
var key = 'name';
var {[key]:val } = dad;
console.log(val); // 'john'
key = 'age';
({[key]:val } = dad);
console.log(val); // 30
2.4 小结
- 解构赋值的前提是同构,即左右两边的对象解构要一致;
- 对象解构赋值在绑定值时根据属性key(key的名称和结构位置)进行匹配的。赋值操作符(等号)两边的解构要一致才能正确赋值;
- 解构赋值表达式是赋值表达式的语法糖。
三、数组解构赋值
数组的属性名称叫索引,表示的是位置。所以跟对象的解构赋值相比语法上有些不同:
3.1 语法
// 语法格式1: 声明即赋值
var arr = [1, 2, 3, 4, 5, 6];
var [f, s, t] = arr;
// 语法格式2: 先声明,后赋值
var a, b, c;
[a, b, c] = arr;
console.log([f, s, t]) // [1, 2, 3]
console.log([a, b, c]) // [1, 2, 3]
数组解构赋值在绑定值时根据属性下标和进行匹配的。赋值操作符(等号)两边的解构要一致才能正确赋值,如果匹配不成功则取值为undefined。
3.2 跳跃式的赋值
var arr = [1, 2, 3];
var [,f,s] = arr; // f=2, s=3
3.3 获取数组剩下的元素
通过rest操作符(...)修饰变量可以实现获取数组剩下的元素:
var arr = [3, 4, 5, 6];
var [a, ...b] = arr;
console.log(b); // [4,5,6]
变量b获取数组arr剩余的元素,此时注意变量b必须放在最后,否则语法错误。如果没有剩余的元素,则为空数组,
var arr = [3];
var [a, b, ...c] = arr;
console.log(a) // 3
console.log(b) // undefined
console.log(c) // []
3.4 嵌套
// 获取二维数组的元素
var [[a00=1], [,a11]] = [[1, 2], [3, 4]];
console.log(`a00=${a00}, a11=${a11}`)
// 继续上面的例子,现在的需求是把dad对象里第2个孩子的属性保存到name,age变量里(这个写法就复杂了,结合了数组解构赋值和对象解构赋值):
var {children: [,{name, age}]} = dad;
console.log([name, age])
注意: 复杂的嵌套降低了可读性,需要权衡下是否要使用
3.5 数组也是对象
数组本身也是对象,数组的赋值解构也可以通过对象解构赋值的方式表示:
var arr = [1, 2, 3];
var {0:f, 1:s, 2:t} = arr; // 等价 var [f, s, t] = arr;
console.log([f, s, t]) // f=1, s=2, t=3
这样写确实麻烦哈,数组解构赋值是对数组对象解构赋值的的简化。他们的赋值匹配模式本质上是一样的。
四、对非对象的变量进行解构
var {a } = 1, // undefined
{b} = true, // undefined
{c} = 'a', // undefined
{d} = null, // 类型错误
{e} = undefined; // 类型错误
JS对这些基本类型数字,字符串,boolean都定义了对应的对象类型,在对这些类型的数据进行解构赋值操作时,会转成对应的对象类型。但是null, undefined却没有对应的对象类型,所有在运行时会报类型错误。
五、一些应用场景
总结一句话: 只要是发生赋值操作的场景都可以使用解构赋值表达式。
5.1 函数参数解构赋值
function log({title: tag = "Debug", message}) {
console.log(`${tag}: ${message}`);
}
log({title: 'Info', message: 'This is a log message'})
要使用ES5实现上面的功能,大致如:
function log(option) {
if(!option) option= {};
var tag = option.title || 'Debug',
message = option.message;
console.log(`${tag}: ${message}`);
}
log({title: 'Info', message: 'This is a log message'})
解构赋值用作函数的形参使得参数更加直观明了,并且可以赋值默认值。ES5的写法得读代码才能看到具体需要什么参数。
5.2 for-of语句
可以对集合元素进行解构操作,更方便循环体内取值。
for(var {name, age} of dad.children) {
console.log(`name: ${name}, age: ${age}`)
}
5.3 函数返回值解构
// 方便正则取值
var url = 'https://developer.mozilla.org/en-US/Web/JavaScript';
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
console.log(parsedURL);
var [, protocol, fullhost, fullpath] = parsedURL;
console.log(protocol); // "https"
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。