【JavaScript】解构赋值

1 作用于数组

1.1 解构赋值简介

解构赋值:按照一定的模式,从数组 / 对象中提取值,并对变量进行赋值

let [a, b, c] = [12, 5, 6]; // 左边的结构 = 右边的结构
console.log(a, b, c); // 12 5 6

本质上,这种写法属于 “模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值

变量 = 值
let [a, b, c] = [12, [5, 6]];
console.log(a, b, c); // 12 [ 5, 6 ] undefined

let [a, [b, c]] = [12, [5, 6]];
console.log(a, b, c); // 12 5 6

let [a, [[b], c]] = [1, [[2], 3]];
console.log(a, b, c); // 1 2 3
变量 < 值 - - - 不完全解构:左边模式,只匹配右边模式的一部分。这种情况下,仍可成功解构
let [, , c] = "baz";
console.log(c) // "z"

let [x, , y] = [1, 2, 3];
console.log(x, y); // 1 3

let [x, y] = [1, 2, 3];
console.log(x, y); // 1 2

let [a, [b], c] = [1, [2, 3], 4];
console.log(a, b, c); // 1 2 4
变量 > 值 - - - 解构不成功,变量的值就等于 undefined
let [a] = []; // a 为 undefined
let [b, a] = [1]; // a 为 undefined
模式不匹配 - - - 报错 TypeError
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

1.2 默认值

我们可以给变量设置默认值,格式:变量名 = 默认值

let [a, b, c = "暂无数据"] = ["aa", "bb", "cc"]; // c 设置了默认值
console.log(a, b, c); // aa bb cc

let [a, b, c = "暂无数据"] = ["aa"]; // b 没有默认值
console.log(a, b, c); // aa undefined 暂无数据

ES6 使用严格相等运算符 ===,来判断一个位置是否有值。所以,如果数值是 undefined,就会使用默认值

// 我们也可以选择性使用 undefined,来使用默认值
let [a, b = "暂无数据", c] = ["aa", undefined, "cc"];
console.log(a, b, c); // aa 暂无数据 cc

// 如果传入的是 null,则不会使用默认值:undefined == null,undefined !== null
let [a, b = "暂无数据", c] = ["aa", null, "bb"];
console.log(a, b, c); // aa null bb
默认值可以是表达式

如果默认值是表达式,那这个表达式是惰性求值的,即只有在用到时,才会求值

function f() {
    console.log(2); // 不会输出
    return 2;
}

let [x = f()] = [1];
console.log(x); // 1
  • 默认值生效时,才会调用 f()
function f() {
    console.log(2);
    return 2;
}

let [x = f()] = [];
console.log(x); // 2 2
默认值可以是解构赋值的其他变量
let [x = 1, y = x] = [1, 2]; // x = 1;  y = 2
let [x = 1, y = x] = [2]; // x = 2;  y = 2
let [x = 1, y = x] = []; // x = 1;  y = 1
  • 被引用的变量必须是已经声明了的,否则会报错:
let [x = y, y = 1] = []; // ReferenceError: Cannot access 'y' before initialization

y=1 之前的区域为 y 的暂时性死区

作用:可以很方便地交换两个值
let a = 12, b = 5;
console.log(a, b); // 12 5
[a, b] = [b, a];
console.log(a, b); // 5 12



2 作用于对象

2.1 对象的解构赋值

  • 数组的元素是按次序排列的,变量的取值由它的位置决定
  • 对象的属性没有次序,所以属性名必须对应,才能取到正确的值
  • 对象的属性没有次序,所以不限获取的位置 & 次数
let obj = { // 定义对象
    name: "superman",
    age: 18
};

let {
    name: nam,
    age: ag
} = obj;

console.log(nam, ag); // superman 18
  • 对于对象,解构赋值的内部机制,是先找到同名属性,再赋值给对应的变量。真正被赋值的是后面的变量
  • 根据 ES6 的对象定义,属性名与变量名一样时,对象的解构赋值可以简写:
let {
    name: name,
    age: age,
    sex: sex
} = obj;

console.log(name, age, sex); // superman 18 男
let {
    name,
    age,
    sex
} = obj;
  • 注意:对于对象,let 后面的 {} 是用于解构的,不会形成块级作用域,在同一作用域中不能重复 let
let a;
let { a } = { a: "apple" };  // SyntaxError: Identifier 'a' has already been declared

2.2 默认值

变量默认值生效的条件:属性值严格等于 === undefined

let { x = 3 } = {};
console.log(x); // 3

上述 {} 中没有 x 属性,默认给变量 x 赋值为 3

let { x, y = 5 } = { x: 1 };
console.log(x, y); // 1 5

上述 { x: 1 } 中,找到属性 x,再将属性值 1 赋值给变量 x;找不到属性 y,默认给变量 y 赋值为 5

let { x: y = 3 } = {}; // x 是属性名,y 才是变量
console.log(y); // 3

上述 {} 中,找不到属性 x,默认给变量 y 赋值为 3

let { x: y = 3 } = { x: 5 }; // x 是属性名,y 才是变量
console.log(y); // 5

上述 { x: 5 } 中,找到属性 x,将 属性值 5 赋给变量 y

2.3 数组的特殊解构

数组的本质是特殊的对象,所以可以对数组进行对象属性的解构

let arr = [1, 2, 3];
let { 0: first, [arr.length - 1]: last } = arr;
console.log(first, last); // 1 3
默认值可以是其他变量
let { x = 3, y = x } = {};
console.log(x, y); // 3 3



3 作用于基本类型的数据

3.1 字符串

  • 字符串有 length 属性,可以看做是类数组(对象)
const [a, b, c, d, e] = 'hello';
console.log(a, b, c, d, e) // h e l l o
  • 本质上,类数组是有 length 属性的对象,因此还可以对 length 属性进行解构赋值
let {
    length: len
} = 'hello';
console.log(len); // 5
  • 说明类数组可以使用正常的数组 / 对象的解构方式

3.2 数值、布尔值

let toString = Object.prototype.toString;
// 等价于
let {toString} = Object.prototype; // 对象的解构赋值
  • 解构赋值时,如果等号右边是数值 / 布尔值,会先转为包装类的对象
let { toString: s } = 123; // 123 转成对象 Number(123)
console.log(s === Number.prototype.toString) // true

let { toString: s } = true; // true 转成对象 Boolean(true)
s === Boolean.prototype.toString // true



4 作用于函数

4.1 配合函数参数

说到底就是数组 / 对象的解构赋值,只是写到函数参数的位置而已

  • 数组参数
function add([a, b]) {
    console.log(a + b);
}
add([2, 3]) // 5
  • 对象参数:
function fn({ a, b }) {
    console.log(a, b); // 1 2
}
fn({ a: 1, b: 2 })
对象参数的默认值 & 对象参数属性的默认值
function move({
    x = 0, // 对象参数的属性设置了默认值
    y = 0
} = {}) { // 对象参数设置了默认值
    console.log([x, y]);
}

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

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

// 因为对象参数的属性设置了默认值,所以可以传空对象
move({}); // [0, 0]

// 因为对象参数设置了默认值,所以可以不传参
move(); // [0, 0]
  • 如果只有对象参数的默认值:
function move({ x, y } = { x: 0, y: 0 }) { // 这里只给对象参数设置了默认值
    return [x, y]; // 没有给对象参数的属性设置默认值
}

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

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

// 没有设置对象参数的默认属性值,所以输出 undefined
move({}); // [undefined, undefined]

// 需要不传参才能使用默认对象参数
move(); // [0, 0]

4.2配合函数返回值

function getPos() {
    return {
        left: 10,
        _top: 20 // top 是保留字,不能用作变量名
    };
}
let {
    left,
    _top
} = getPos();
console.log(left, _top); // 10 20



5 解构嵌套的结构

let obj = { // 解构对象,则按属性名赋值
    p: [
        'Hello',
        {
            y: 'World'
        }
    ]
};

let {
    p, // ["Hello", {…}]
    p: [
        a, b  // Hello {y: "World"}
    ],
    p: [
        a, { // Hello
            y // World
        }
    ]
} = obj;
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JS.Huang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值