解构赋值

224 阅读4分钟

解构赋值?

从数组、对象、字符串中提取值,对变量进行赋值,这种方法称之为“解构赋值
解构赋值是对赋值运算符的扩展。
他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。

解构模型

在解构中,有下面两部分参与:
- 解构的源,解构赋值表达式的右边部分。
- 解构的目标,解构赋值表达式的左边部分。

分类

1.数组的解构赋值
简单来说 [数组对应数组]
a.完全解构
let[a,b,c]=[1,2,3]  //a 1 b 2 c 3
b.不完全结构
let [a,b]=[1,2,3] //a 1 b 2
c.结构不成功
let[foo]=1  //undefined
d.默认值:
如果一个数组成员是 null,默认值就不会生效,因为 null 不严格等于 undefined
let [x = 1] = [undefined];     x // 1
let [x = 1] = [null];          x // null
如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值
function f() {
    return "我是函数的返回值";
}
let [x =f()] = ["我是新赋的值"];
console.log(x);
默认值可以引用解构赋值的其他变量,但该变量必须已经声明
let [x=1, y = x] = [];       // x=1; y=1
let [x = y, y = 1] = [];    // ReferenceError: y is not defined
2.对象的解构赋值
数组的元素是按次序排列的,变量的取值由它的位置决定;对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let { foo, bar } = { foo: "aaa", bar: "bbb" };

  foo // "aaa"    baz // "undefined"
a. 别名的引用
let { foo:bar } = { foo: 'aaa', baz: 'bbb' };

            bar // "aaa"
b.解构也可用于嵌套结构的对象、
let obj = {

    p: [

        'Hello',

        { y: 'World' }

        ]

};

let {p, p: [x, { y }] } = obj;

x // "Hello"  y // "World"  p // ["Hello", {y: "World"}]
c.对象的解构也可以指定默认值
var {x = 3} = {};      x // 3
var {x, y = 5} = {x: 1};       x // 1 y // 5
d.★★默认值生效的条件是,对象的属性值严格等于 undefined★★。
var {x = 3} = {x: undefined};      x // 3

var {x = 3} = {x: null};           x // null
3.字符串的解构赋值
a.字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = 'hello';
    a // "h"   b // "e"   c // "l"   d // "l"   e // "o"
b.字符串属性解构
let {length : len} = 'hello';   len // 5
4.函数参数的解构赋值
a. 函数参数的解构
function add([x, y]){

return x + y;

}

add([1, 2]);     // 3
b. 函数参数的解构使用默认值
function move({x = 0, y = 0} = {}) {

return [x, y];

}

move({x: 3, y: 8});      // [3, 8]

move({x: 3});           // [3, 0]

move({});              // [0, 0]
5.数值和布尔值的解构赋值

应用

(1)交换变量的值
let x = 1;

let y = 2;

[x, y] = [y, x];
(2)从函数或数组返回变量的值
// 返回一个数组

function example() {

return [1, 2, 3];

}

let [a, b, c] = example();

// 返回一个对象

function example() {

return {

foo: 1,

bar: 2

};

}

let { foo, bar } = example();

(3)函数参数的定义
(4)提取 JSON 数据
(5)函数参数的默认值

解构赋值是深拷贝还是浅拷贝?

深拷贝:修改新变量的值不会影响原有变量的值。默认情况下基本数据类型都是深拷贝。
浅拷贝:修改新变量的值会影响原有的变量的值。默认情况下引用类型都是浅拷贝。
              const a = {
				name: 'John',
				age: 18,
				marriage: false,
				addr: {
					province: 'sichuan',
					city: 'chengdu'
				}
			}

			let {
				name,
				age,
				marriage,
				addr
			} = a

			name = 'rose'
			age = 19
			marriage = true
			addr.province = 'shanghai'
			addr.city = 'shanghai'

			console.log(name, age, marriage, addr.city) //rose 19 true shanghai 
			console.log(a)

copy.png

我们从对象a中解构赋值了name、age、marriage、addr四个变量,分别是stringnumberbooleanobject类型。改变这四个变量的值后,再与a原来的值作对比,我们发现a的name,age,marriage属性没有改变,而addr属性发生了改变。由此可以得出结论,解构赋值对object类型只是浅拷贝。

实际上,无论是使用扩展运算符(...)还是解构赋值,对于引用类型都是浅拷贝。所以在使用splice()、concat()、...对数组拷贝时,只有当数组内部属性值不是引用类型是,才能实现深拷贝。(解构赋值是深拷贝还是浅拷贝? - 简书 (jianshu.com)