ES6瞎学(二):解构赋值

本文详细介绍了ES6中的数组、对象、字符串、数值和布尔值的解构赋值用法,包括默认值设置、交换变量值、函数返回多值、函数参数定义、提取JSON数据、函数参数默认值、遍历Map结构以及模块方法输入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、数组的解构赋值

1.1 用法

以前,为变量赋值,只能直接指定值。

let a = 1;
let b = 2;

ES6 允许写成下面这样。

let [a, b] = [1, 2];
a   // 1
b   // 2

只要等号左右俩边的格式一样,变量会对应被赋值,就是解构成功了。

let [a, [b]] = [1, [2]];
a   // 1
b   // 2

let [, c] = [2, 3];
c   // 3

let [a, , c] = [1, 2, 3];
a   // 1
c   // 3

let [a, ...arr] = [1, 2, 3];
a    // 1
arr  // [2, 3]

如果解构不成功(右边不完全满足左边格式),变量的值就等于undefined。

let [a] = [];
console.log(a)
// undefined
let [a, b] = [1];
// undefinedundefined

但是当右边的格式和左边类似,只是数量上更多,则会被解构成功,但是只是部分解构,结果是成功。

let [a, b] = [1, 2, 3];
a   // 1
b   // 2

let [a, [b], c] = [1, [2, 3], 4];
a   // 1
b   // 2
c   // 4

对于 Set 结构,也可以使用数组的解构赋值(毕竟 Set 也是特殊的数组嘛)。

let [a, b, c] = new Set([1, 2, 3]);
a    // 1

事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。具体的等学到 Iterator 再说吧。

1.2 默认值

解构赋值允许指定默认值。

let [foo = true] = [];
foo   // true

let [a, b = 2] = [1]; 
// a = 1, b = 2
let [a, b = 2] = [1, undefined]; 
// a = 1, b = 2

好像不难理解吧,挺简单的,接下来再看一个。

function f() {
  return 1;
}

let [a = f()] = [2];
a   // 2 

其实也是可以用函数对其赋值,但是优先确定是否有结构赋值,有的情况下优先结构赋值,没有的话再计算函数后赋默认值。

二、对象的解构赋值

2.1 用法

let { a, b } = { a: 1, b: 2 };
a    // 1
b    // 2

再看一个:

let { c } = { a: 1, b: 2 };
c    // undefined
let { b } = { a: 1, b: 2 };
b    // 2

上面的数组解构,按样子写,c 会被第一个右边值赋予,但是在对象结构中,只有赋值左右同样名字的值(且不考虑左右顺序),c 在右边的对象中没有定义,则左边也就无法取到值。对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。

let { log, sin, cos } = Math;

是不是很方便!!!但是如果变量名与属性名不一致,必须写成下面这样。

let { a: c } = { a: 1, b: 2 };
c   // 1

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f   // 'hello'
l   // 'world'

这样写,真的累,但是也能看到它到底是怎么解构赋值的:

let { a: a, b: b} = { a: 1, b: 1 };

它是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

let { a: c } = { a: 1, b: 2 };
c    // 1
a    // error: a is not defined

上面代码中,a 是匹配的模式,c 才是变量。真正被赋值的是变量 c,而不是模式 a

与数组一样,解构也可以用于嵌套结构的对象。

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"

注意,这时 p 是模式,不是变量,因此不会被赋值。如果 p 也要作为变量赋值。

但是如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。

// 报错
let {a: {b}} = {c: 3};

上面代码中,等号左边对象的a属性,对应一个子对象。该子对象的b属性,解构时会报错。原因很简单,因为a这时等于undefined,再取子属性就会报错。

注意,对象的解构赋值可以取到继承的属性。

const obj1 = {};
const obj2 = { foo: 'bar' };
Object.setPrototypeOf(obj1, obj2);

const { foo } = obj1;
foo // "bar"

上面代码中,对象obj1的原型对象是obj2。foo属性不是obj1自身的属性,而是继承自obj2的属性,解构赋值可以取到这个属性。

2.2 默认值

对象的解构也可以指定默认值。

var {x = 3} = {};
x    // 3

var {x, y = 5} = {x: 1};
x    // 1
y    // 5

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"

注意:默认值生效的条件是,对象的属性值严格等于 undefined

var {x = 3} = {x: undefined};
x // 3

var {x = 3} = {x: null};
x // null

上面代码中,属性 x 等于 null ,因为 nullundefined 不严格相等,所以是个有效的赋值,导致默认值3不会生效。

三、字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

const [a, b, c, d, e] = 'hello';
a    // "h"
b    // "e"
c    // "l"
d    // "l"
e    // "o"

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

let {length : len} = 'hello';
len      // 5

四、数值和布尔值的解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。

let {toString: s} = 123;
s === Number.prototype.toString    // true

let {toString: s} = true;
s === Boolean.prototype.toString   // true

上面代码中,数值和布尔值的包装对象都有toString属性,因此变量s都能取到值。

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。

let { prop: x } = undefined;  // TypeError
let { prop: y } = null;       // TypeError

五、用途

变量的解构赋值用途很多。

(1)交换变量的值

let x = 1;
let y = 2;
[x, y] = [y, x];

上面代码交换变量x和y的值,这样的写法不仅简洁,而且易读,语义非常清晰。

(2)从函数返回多个值

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

function example() {
  return {
    a: 1,
    b: 2
  };
}
let { a, b} = example();

(3)函数参数的定义

解构赋值可以方便地将一组参数与变量名对应起来。

// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});

(4)提取 JSON 数据

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};
let { id, status, data: number } = jsonData;

console.log(id, status, number);        // 42, "OK", [867, 5309]

(5)函数参数的默认值

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};

(6)遍历 Map 结构

const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

如果只想获取键名,或者只想获取键值,可以写成下面这样。

for (let [key] of map) {
  // ...
}

for (let [,value] of map) {
  // ...
}

(7)输入模块的指定方法

加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

const { SourceMapConsumer, SourceNode } = require("source-map");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值