ES6基础:变量的解构赋值
前言
为什么要把ES6系列总结出来呢,第一个是为了加深印象,第二个就是在之后的代码中尽量将能用的新特性都用上!
如果我们以ES6的前后来区分代码风格的话,那么有关变量的部分应该是这样的
之前:
function newPoint(options) {
const arg = options === undefined ? {} : options;
const x = arg.x ? 0 : arg.x;
const y = arg.y ? 0 : arg.y;
const r = arg.r ? 10 : arg.r;
console.log(x, y, r);
}
newPoint({x: 5, y: 5, r: 10});
之后
function newPoint({ x = 0, y = 0, r = 10 }) {
console.log(x, y, r);
}
newPoint({ x: 5, y: 5, r: 10 });
或许你会觉得这并没有什么,除了看上去代码简洁之外并没有实际意义,事实却并非如此~
一、数组的解构赋值
首先看看最容易被人忽略的数组解构。
我们在获取获取数组内的元素时,大多是通过下标的方式arr[0],这种方式也确实方便,但针对特定的情况时,解构会大大提高你的效率
1.1 同时赋值多个变量
先来看这样一段代码:
let a = 1;
let b = 2;
let c = 3;
let d = 4;
当你需要使用a、b…时,你可能会这么做。而数组的解构可以让你用更少的代码做到同样的事。
let [a, b, c, d] = [1, 2, 3, 4];
a // 1
b // 2
c // 3
d // 4
1.2 解构嵌套数组
解构嵌套数组,就是模式匹配,只要等号两边的层级结构相同,就可以拿到对应位置的值,这在某些特定的情况十分有用。
const arr = [1, [2, 3, [4, 5, 6]]];
const [a, [b, c, [d, e, f]]] = arr;
a //1
b //2
c //3
d //4
e //5
f //6
1.3 相同“模式”的不完全解构
在1.1和1.2小节中,我们总是完整的对应数组结构来获取数据,但当我们模式相同但变量没有完全对应时,会发生什么呢?
let [a, b, c] = [1, 2, 3, 4]; // 1 2 3
let [a, b, c, d] = [1, 2, 3]; // 1 2 3 undefined
let [a, [b, c, [d, e]]] = [1, [2, 3, [4, 5, 6]]]; // 1 2 3 4 5
1.4 解构的默认值
为了防止1.3小节中出现的解构得到的值存在undefined的情况(实际开发中,也需要兼容某些数据),我们可以对其设定默认值。
let [a = true] = [];
a // true
注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null
上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。
如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
function f() {
console.log('aaa');
}
let [x = f()] = [1];
上面代码中,因为x能取到值,所以函数f根本不会执行。上面的代码其实等价于下面的代码。
注意
数组的解构是根据它的位置(模式)对应的
解构操作允许有默认值,但一定是已经声明的。
如果等号的右边不是数组(或者严格地说,不是可遍历的结构)那么将会报错
二、对象的解构赋值
对象的解构赋值应该是我们使用的最平凡的解构操作了,先来看看基本操作:
const { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
2.1 根据属性解构对象
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
如果变量名与属性名不一致,必须写成下面这样。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj; // 起了个别名
f // 'hello'
l // 'world'
这实际上说明,对象的解构赋值是下面形式的简写:
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
模式foo的值复制给变量foo,真正被赋值的是后者,而不是前者。
注意
对象解构和数组解构一样,都支持嵌套解构
对象解构同样支持默认值
三、函数参数的解构赋值
利用解构优化函数调用时中场景:
3.1 解构对象类型参数
function fetch(option){
var name = option.name;
var age = option.age;
var like = option.like;
}
// ES6
function fetch({ name, age, like }) {
// 参数经历了 let { name, age, like } = option
}
3.2 解构数组类型参数
const arr = [
[1, 1],
[2, 2],
[3, 3],
[4, 4]
];
const newArr = arr.map(([x, y]) => x + y);
newArr // [ 2, 4, 6, 8 ]
3.3 为参数设定默认值
设定默认值,可以避免许多拿不到数据的情况
function func({ name = '余光', age = 23, like = 'FE' }) {
console.log(name, age, like);
}
const options = { name: '余光' }
func(options);
四、常见的使用场景
变量的解构赋值用途很多。
4.1 交换变量的值(虽然没用过,但看起来很好用)
let x = 1;
let y = 2;
[x, y] = [y, x];
上面代码交换变量x和y的值,这样的写法不仅简洁,而且易读,语义非常清晰。
4.2 从函数返回多个值
函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。
返回一个数组
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
返回一个对象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
4.3 函数参数的定义
解构赋值可以方便地将一组参数与变量名对应起来。
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
4.4 提取 JSON 数据
解构赋值对提取 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]
// 上面代码可以快速提取 JSON 数据的值。
4.5 函数参数的默认值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}) {
// ... do stuff
};
指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || ‘default foo’;这样的语句。
更多的解构场景,基本上都是在上面的基础上略作改动,希望大家能看到它的闪光点哦~
最后提一句,既然到此我们已经了解了解构赋值,不妨在之后的代码中完全使用它!!!