解构:是一种打数据结构解构,将其拆分为更小的部分的过程。
1. 为什么需要解构
我们考虑一个大多数人在使用 Javascript 进行编码时可能遇到过的情况。
假设,我们有一个数据,在学生数据中用一个对象表示三个学科(数学、语文、英语)的分数,我们根据这些数据显示学生的分数信息:
const student = {
name:'jsPool',
age:20,
scores:{
math:95,
chinese:98,
english:93
}
}
function showScore(student){
console.log('学生名:' + student.name);
console.log('数学成绩:' + (student.scores.math || 0 ));
console.log('语文成绩:' + (student.scores.chinese || 0 ));
console.log('英语成绩:' + (student.scores.english || 0 ));
}
showScore(student)
复制代码
使用上面的代码,我们将获得所需的结果。但是,以这种方式编写的代码需要有一些值得注意的地方。 由于我们访问的对象 scores 嵌套在另一个对象 student 中,所以,我们的访问链变得更长,这意味着更多的输入, 而由于更多的输入,也就更有可能造成拼写的错误。当然,这并不是什么大问题,但是通过解构,我们可以用更具有表现力 和更紧凑的语法来做同样的事情。
2. 对象解构
对象解构的语法形式是在一个赋值操作符左边放置一个对象字面量,例如:
let node = {
type:"Identifier"
name:"foo"
}
let { type,name} = node
console.log(type) //Identifier
console.log(name) //foo
在这段代码中,node.type的值直接被存储在名为type的变量中,node.name的值也被存储在名为name的变量中。
2.1 非同名变量赋值
在这个例子中,我们使用与对象属性名相同的变量名称,当然,我们也可以定义与属性名不同的变量名称:
let node = {
type:"Identifier"
name:"foo"
};
const {type:lx,name:mz} = person;
console.log(lx); // Identifier
console.log(mz); // foo
复制代码
在这里,我们创建了两个局部变量:lx , mz,并将 lx 映射到 type,mz映射到 name。
不要忘记初始化程序
如果是使用var、let、const解构声明变量,则必须要提供初试化程序(也就是等号右侧的值)。下面这几行代码全部会导致程序抛出语法错误,他们都缺少了初始化程序:
//语法错误
var { type ,name} ;
//语法错误
let { type ,name} ;
//语法错误
const { type ,name} ;
如果不使用解构功能,则var和let声明不强制要求提供初始化程序,但是对于const声明,无论如何都必须提供初始化程序。
2.2 解构赋值
目前为止,我们已经将对象解构赋值应用到了变量的声明中。然而,我们同样可以再给变量赋值的时候使用解构语法。举个例子,你可能在定义变量之后想要修改他们的值,就像这样:
let node = {
type:"Identifier"
name:"foo"
}
type = 'Literal'
name = 5
//使用解构语法为多个变量赋值
({type,name} = node)
console.log(type) //Identifier
console.log(name) //foo
在这个示例中,声明变量type和name时初始化了一个值,在后面几行中,通过解构赋值的方法,从node对象读取相应的值重新为这两个变量赋值。请注意,一定要用到一对小括号包裹解构赋值语句,JS引擎将一对开放的花括号视为一个代码块,而语法规定,代码块语句不允许出现在赋值语句左侧,添加小括号可以将块语句转化为一个表达式,从而实现整个解构赋值的过程。
3. 嵌套对象的解构赋值
解构嵌套对象仍然与对象字面量的语法相似,可以将对象拆解以获取你想要的信息。
// 后台返回的数据
const userInfo = {
name: 'Lily',
age: '18',
education: {
degree: 'Masters',
school: 'SYSU'
}
};
const { education: { degree }} = userInfo; // Masters
4. 数组的解构赋值
与对象解构的语法相比,数组解构就简单多了,它使用的是数组字面量,且解构操作全部在数组内完成,而不是像对象字面量语法一样使用对象的命名属性。
let list = [10,'Leo Messi','Argentina'];
let [num,player] = list;
console.log(num,player);// 10 ,Leo Messi
复制代码
在上面的代码中,我们从数组 list 中解构出数组索引 0 和 1 所对应的值并分别存储至变量 houseNo 和 street 中。
在数组的解构中,也可以直接省略元素,只为需要的元素提供变量名:
let list = [10,'Leo Messi','Argentina'];
let [num,,city] = list;
console.log(num,city);// 221 , Argentina
复制代码
这段代码中使用解构语法从数组 list 中获取索引 0 和索引 2 所对应的元素,city 前的逗号是前方元素的占位符,无论数组中的元素有多少个,都可用这种方式来提取想要的元素。
5. 嵌套数组的解构赋值
就像对象一样,也可以对嵌套数组进行解构操作,在原有的数组解构模式中插入另一个数组解构模式,即可将解构过程深入到下一级:
let colors = [ 'red' , [ 'green' , 'yellow' ] , 'blue' ];
let [ firstColor , [ secondColor ] ] = colors;
console.log(firstColor,secondColor); // red , green
在这个例子中,我们通过数组的嵌套解构,为变量 firstColor 和 secondColor 分配对应的值。
5.1 不定元素
在数组中,可以通过...语法将数组中的其余元素赋值给一个特定的变量,就像这样:
let colors = ['red','green','blue'];
let [firstColor,...otherColors] = colors;
console.log(firstColor); // red
console.log(otherColors); // ['green','blue']
复制代码
这个例子中,数组 colors 的第一个元素被赋值给了 firstColor ,其他元素被赋值给了 otherColors 数组,所以 otherColors 中包含两个元素:'green' 和 'blue'
6. 混合解构
可以混合使用对象解构和数组解构来构建更多复杂的表达式,如此一来可以从任何混杂着对象和数组的数据结构中提取你想要的信息。
let node = {
name:'foo',
loc:{
start:{
line:1,
column:1
}
},
range:[0,3]
}
let {
loc:{start:{line}},
range:[startIndex]
} = node;
console.log(line); // 1
console.log(startIndex); // 0
复制代码
当使用混合解构语法时,可以从 node 对象中提取任意想要的信息。
混合解构这种方式对于从 JSON 中提取数据时尤其有效,不再需要遍历整个解构了。