变量的解构赋值
数组的解构赋值
解构:从数组和对象中提取值,对变量进行赋值,称为解构。
let [a, b, c] = [1, 2, 3]; // 1 2 3
let [foo, [[foo1], foo2]] = [1, [[2], 3]] // 1 2 3
let [ , , third] = ['foo', 'foo1', 'foo2']; // third => "foo2"
let [x, , z] = [1, 2, 3]; // x, z => 1, 3
let [head, ...tail] = [1, 2, 3, 4]; // head, tail => 1, [2, 3, 4]
let [header, footer] = [1, 2, 3, 4]; // header, footer => 1, 2
let [x, y, ...z] = ['aaa']; // aaa undefined []
// 解构不成功,变量值为 undefined
let [f] = [] // undefined
let [d, e] = [1] // 1 undefined
// 不完全解构,等号左边的变量只匹配等号右边一部分的数组
let [x, y] = [1, 2, 3]; // x, y => 1, 2
let [a, [b], d] = [1, [2, 3], 4]; // a, b, d => 1, 2, 4
// 如果等号右边不是数组,将会报错
let [foo] = 1;
let [foo] = false; // VM1232:1 Uncaught TypeError: false is not iterable
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
// 但等号右边是字符串类型不会报错
let [h] = '1' // h => "1"
// Set结构,也可以使用数组的解构赋值
let [o, p, q] = new Set(['a', 'b', 'c']) // a b c
// *默认值*
let [r = true] = [] // true
let [s, t = 'bbb'] = ['aaa'] // aaa bbb
let [u, v = 'bbb'] = ['aaa', undefined] // aaa bbb
let [w, x = 'bbb'] = ['aaa', 'ccc'] // aaa ccc
let [uu, vv = 'bbb'] = ['aaa', null]
// aaa null (数组成员严格等于undefined,默认值才会生效。null不严格等于undefined,所以默认值不会生效。)
// *默认值是表达式*
function fn(){
console.log('aaa')
}
let [abc = fn()] = [1] // 1 (因为表达式惰性求值,用到时才执行, 能取到值直接用。)
// 默认值可以引用解构赋值的其他变量,但该变量必须已声明
let [x = 1, y = x] = []; // x=1; y=1
let [x = 1, y = x] = [2]; // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ReferenceError: y is not defined
对象的解构赋值
数组的解构:变量是按元素的排列次序相应取值;
对象的解构:与次序无关,变量必须与属性同名才能取到正确的值。
let { foo, bar } = { foo: 'aaa', bar: 'bbb' } // foo => "aaa" bar => "bbb"
// { baz } 相当于 { baz: baz } 的简写,右边对象没有baz属性,所以左边baz变量取不到值
let { baz } = { foo: 'aaa', bar: 'bbb' }; // baz => undefined
let { a: bbbb } = { a: 'aaaa' } // a => a is not defined bbb => 'aaaa'
// 连续解构赋值
let obj = {
p: [
'hello',
{ y: 'world' }
]
}
let { p, p: [x, y] } = obj
// p => ["hello", {…}] x => "hello" y => { y: 'world' }
// 嵌套赋值
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });// obj => {prop:123} arr => [true]
// 默认值
let { xx = 3 } = {} // xx => 3
let { xx: yy = 3 } = { xx: 55 } // yy => 55
let { aa, bb = 3 } = { aa: 11 } // aa => 11 bb => 3
// 默认值生效的条件是属性值严格等于undefined
let { xxx = 333 } = { xxx: undefined } // xxx => 333
let { yyy = 333 } = { yyy: null } // yyy => null
// 注意点
1. 避免在行首直接使用大括号,JavaScript将其解释为代码块,使用圆括号解决如下:
let x;
({x} = {x: 1});
2. 左边不放置任何变量也是可以的
({} = [true, false]);
({} = 'abc');
({} = []);
3. 对数组进行对象属性的解构
let {0: first, [array.length - 1]: last} = array // first => 1 last => 3
连续解构赋值+重命名
let obj = {
a:{
b: {
c: 1
}
}
}
const {a: {b: {c}}} = obj
a b // a is not defined
c // 1
let obj2 = {
a:{
b: 3
}
}
const {a: {b: data}} = obj2
data // 3
字符串的解构赋值
// 字符串被转换为一个类似数组的对象
const [a, b, c, d, e] = 'hello' // a => 'h', b => 'e', c => 'l', d => 'l', e => 'o'
// 类似数组的对象都有一个length属性,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
// 由于undefined和null无法转为对象所以会报错
let { prop: ha } = undefined
let { prop: hh } = null
// VM1317:1 Uncaught TypeError: Cannot destructure property `prop` of 'undefined' or 'null'.
函数参数的解构赋值
// 解构成x, y变量来看
function add([x, y]) {
return x + y
}
add([2, 3]) // 5
// 默认值(是为x, y变量指定默认值)
function move({ x = 0, y = 0 } = {}) {
return [x, y]
}
move({ x: 3, y: 5 }) // [3, 5]
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: 5 }) // [3, 5]
move({ x: 3 }) // [3, undefined]
move({}) // [undefined, undefined]
move() // [0, 0]
不能使用圆括号的情况
// 全部报错 Uncaught SyntaxError: Unexpected token (
1. 变量声明语句
let [(a)] = [1];
let {x: (c)} = {};
let {(x): c} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
2. 函数参数(也属于变量声明)
function f([(z)]) {
return z;
}
3. 赋值语句的模式
([a]) = [5]
({ p }) = {p: 1}
可以使用圆括号的情况
只有一种情况:赋值语句的非模式部分
// 正确
[(a)] = [5]
{ p: (p) } = {p: 1}
用途
1. 变量交换
let x = 1;
let y = 2;
[x, y] = [y, x] // [2, 1]
2. 解决函数只能返回一个值的问题
function fn() {
return [1, 2, 3]
}
let [a, b, c] = fn() // a b c => 1 2 3
function f() {
return {
foo: 1,
bar: 2
}
}
let { foo, bar } = f() // foo bar => 1 2
3. 函数参数的定义
function foo([x, y, z]) {
return [x, y, z]
}
foo([1, 2, 3]) // [1, 2, 3]
function example({x, y, z}) {
return {x, y, z}
}
example({z: 1, y: 2, x: 3}) // {x: 3, y: 2, z: 1}
4, 提取json数据
let jsonData = {
name: 'zhangsan',
value: 'OK',
data: [1, 2]
}
let {name, value, data: num} = jsonData // name value num => 'zhangsan' "OK" [1, 2]