解构赋值的介绍
ES6 中实现了一种全新的复合声明与赋值的写法,叫做解构赋值。(英文是destructuring assignment)。在解构赋值中,等号右手端的值是数组或对象,即:结构化的值,而左边则是通过模拟数组或对象的字面量语法来指定一个或多个变量。
在解构赋值发生的时候,他会从右边提取出一个或多个值,并保存到左边的变量中。解构赋值常用于声明语句中的初始化变量,定义函数参数时也经常使用解构赋值。
解构赋值的第一个Demo
我们来演示一段解构赋值的示例
这里我们采取node.js以脱离浏览器来演示ES中的解构赋值。
let x = 1;
let y = 2;
console.log(x,y);
这里我们创建一个js文件,采用常规的赋值方式,可以看到这里用了三行代码。
接下来我们在控制台中输入 node ES6.js
控制台打印出 1 2
接下来我们采取ES中的解构赋值来重构这段代码。
let [x,y] = [1,2];
console.log(x,y);
我们重新调用node,控制台中打印出了和上面相同的效果,但是很明显的是我们的代码更加简洁,对于学习过ES Moudle的人来讲,可读性也更强,尤其是对于多个变量的情况下,这种解构赋值的方式会更加明显的简洁优雅。
解构赋值操作对象
下面我们用解构赋值来遍历一个对象。
let target = {
"x1":1,
"x2":2,
"x3":3,
"x4":4,
}
for (let [name,value] of Object.entries(target)) {
console.log(name,value);
}
结果如上,可以看到也是十分简洁的,不仅如此,ES中的结构赋值还可以频繁用于函数返回等地方。
解构赋值的一些小细节
在解构赋值中,其实左右两边的个数不一定要相同,如果左边的变量更多,多余的变量会被设成undefined,而如果右边更多,多的值会被忽略。
所以,在实际使用的时候,我们在左边的变量可以包含额外的逗号,用来跳过右边的一些值。
这里我们来做一个演示。
let [x1,,,x2] = [1,2,3,4,5,6,7,8,9,10];
console.log(x1,x2);
结果如上,可以看到,我们通过逗号跳过了一些值。
经典的...的使用
在很多优秀的程序员的代码里,我们经常看到...的使用,接下来我们来研究一下...的使用,这也是解构赋值的一种。
我们来看下一段代码
let [x1,...x2] = [1,2,3,4,5,6,7,8,9,10];
console.log("x1:"+x1+"\n"+"x2:"+x2);
我们node执行一下结果
结果如下:
可以看到,x1还是右侧的第一个值,而剩下的值都被收集到了x2中。
那么这里我们可以推广下去,以后我们需要拷贝数组的时候,可以通过这种[...]的解构赋值的方式来进行数组的拷贝。
深拷贝与浅拷贝
既然提到了数组的拷贝,那么我们就不能绕开经典的深拷贝浅拷贝问题。
浅拷贝 (影子克隆):只复制对象的基本类型,对象类型,仍属于原来的引用. 深拷贝 (深度克隆):不仅复制对象的基本类,同时也复制原对象中的对象.就是说完全是新对象产生的. 浅 拷贝和深拷贝之间的区别:浅拷贝是指将对象中的数值类型的字段拷贝到新的对象中,而对象中的引用型字段则指复制它的一个引用到目标对象。. 如果改变目标对象 中引用型字段的值他将反映在原始对象中,也就是说原始对象中对应的字段也会发生变化。
那么我们的[...]的解构赋值的方式进行拷贝是深拷贝还是浅拷贝呢。
浅拷贝演示
我们来看下面的浅拷贝的一个案例
const s1 = [1,2,3];
let s2 = s1;
s2[0] = 0;
console.log(s1[0]);
这里我们定义了一个数组s1,然后我们直接将他赋给s2,这里其实是一个浅拷贝,我们改变s2的第一位的值,但是我们的s1的第一位的值也随之发生了变化。
深拷贝实例
接下来我们看一下深拷贝的一个方式。
我们来重构上面的代码。
const s1 = [1,2,3];
let s2 = [];
for (let i = 0;i < s1.length;i++){
s2[i] = s1[i];
}
s2[0] = 10;
console.log(s1[0]);
再次node一下,运行结果如下:
可以看到,我们的s1并没有随着s2的改变而改变,这是一个深拷贝。
[...]的方式
那么我们的[...]的方式是什么呢?我们来试验一下。
const s1 = [1,2,3];
let [...s2] = s1;
s2[0] = 10;
console.log(s1[0]);
接下来我们继续在控制台node一下,结果如下:
可见我们对s2的操作并没有改变s1,这是一个深拷贝,而且对比传统的深拷贝,这种方式简单了太多太多了。
一些总结和建议
有时候我们会遇到一些复杂的解构赋值,接下来我们看这2个例子。
let p = [{x:1,y:2},{x:3,y:4}];
let [{x:x1,y:y1},{x:x2,y:y2}] = p;
console.log(x1,y1,x2,y2);
结果如下:
我们在看一个
let p = {p1:[1,2],p2:[3,4]};
let {p1:[x1,y1],p2:[x2,y2]} = p;
console.log(x1,y1,x2,y2)
控制台node一下,结果如下图:
我们可以看出,在一些情况下,复杂的解构赋值甚至会让代码更繁琐难以理解,这种情况下我们采取传统的的代码会更加简洁易懂。
总结
ES中的解构赋值是一种非常非常强大的机制,我们熟练运用会简化我们的开发,提高我们代码的可读性和优雅,但是有时候 解构赋值会起到反作用,我们需要看情况合理运用解构赋值。