数组的解构赋值:
基本用法
- 按照一定模式,从数组和对象中提取对象,对变量进行赋值,称为解构,写法属于“模式匹配”:按照对应位置,对变量赋值
let [a,b,c] = [1,2,3]
let [head,...tail] = [1,2,3,4]
head = 1
tail = [2,3,4]
- 解构不成功:变量的值就等于undefined.
let [bar,foo] = [1]
foo = undefined
- 不完全解构:
let [a,[b],d] = [1,[2,3],4]
a = 1
b= 2
d = 4
- 如果右边不是数组(不是可遍历的结构,参见《Iterator》一章),会报错
//转为对象以后不具备 Iterator 接口
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
//本身就不具备 Iterator 接口
let [foo] = {};
- set结构,也可以使用数组的解构赋值
let [x,y,z] = new Set(['a','b','c'])
- 只要数据结构具有迭代,都可以解构赋值
默认值
- 当一个数组成员严格等于(===)undefined的时候,才采用默认值([y= 'b'])
let [foo = true] = []
foo = true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
- 默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
function f() {
console.log('aaa');
}
let [x = f()] = [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'
- 解构失败,变量的值为undefined
let { bar, foo, baz } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
baz //undefined
- 可以将现有对象的方法,赋值到某个变量
// 例一:将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上
let {log,sin,cos} = Math
// 例二:将console.log赋值到log变量
const {log} = console
log('hello') = hello
- 变量名与属性名不一致:真正被赋值的是后者,而不是前者
let {foo:baz} = {foo:'aaa',bar:'bbb'}
baz:'aaa'
foo // error: foo is not defined
let obj = {first:'hello',last:'world'}
let {first:f,last:l} = obj
f = hello
l:world
let obj = {p:["hello",{y:"world"}]}
let {p:[x,{y}]} = obj
x = 'hello'
y = "world"
let {p,p:[x,{y}]} = obj
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]
- 三次解构赋值:
const node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
let { loc, loc: { start }, loc: { start: { line }} } = node;
line // 1
loc // Object {start: Object}
start // Object {line: 1, column: 5}
//只有line是变量,loc和start都是模式,不是变量
- 嵌套赋值:
let obj = {}
let arr = []
({foo:obj.prop,bar:arr[0]} = {foo:123,bar:true})
obj // {prop:123}
arr // [true]
let {foo:{bar}} = {baz:'baz'} //报错(因为foo这时等于undefined再取子属性就会报错)
- 对象的解构赋值可以取到继承的属性:
const obj1= {}
const obj2 = {foo:'bar'}
Object.setPrototypeof(obj1,obj2)
const {foo} = obj1
foo = 'bar'
对象obj1的原型对象是obj2。
foo属性不是obj1自身的属性,而是继承自obj2的属性,解构赋值可以取到这个属性。
- setPrototypeof:
__proto__原来获取或设置当前对象的prototype(原型)对象。
因为__proto__是一个内部属性,不是一个正式的对外的API.
所以在操作原型对象时应该使用Object.getPrototypeOf()代替读取操作,使用Object.setPrototypeOf()代替设置操作。
setPrototypeof:设置一个指定的对象的原型(即内部[[Prototype]]属性到另一个对象或null
Object.setPrototypeOf(obj, prototype)
obj:将被设置原型的对象.
prototype:该对象新的原型(可以是一个对象或者null)
默认值
var {x:y = 5} = {}
y = 5
var {x:y = 3} = {x = 5}
y = 5
- 默认值生效的条件是,对象的属性值严格等于undefined
var {x = 3} = {x = undefined}
x = 3
var {x = 3} = {x = null}
x = null
- 对数组进行对象属性的解构(属性名表达式):
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
- 错误的写法:
let x;
{x} = {x: 1}; // SyntaxError: syntax error
会报错,因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。
只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
// 正确的写法
let x;
({x} = {x: 1});
字符串的解构赋值
- 字符串被转换成了一个类似数组的对象
const [a,b,c,d,e] = "hello"
a = h
b = e
c = l
d = l
e = o
- 类似数组都有一个length属性,可以对这个属性解构赋值
let {length : len} = 'hello';
len // 5
数值和布尔值的解构赋值
- 解构赋值的规则:
只要等号右边的值不是数组或对象,就先转化为对象.
- 因为数值和布尔值的包装对象都有toString属性,因此变量s都能取到值:
let {toString:s} = 123
s === Number.prototype.toString
let {toString:s} = true
s === Boolean.prototype.toString
- 由于undefined和null无法转化为对象,所以解构会报错
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
函数参数的解构赋值
function add([x,y]){
return x+y
}
add([1,2]) //3
[[1,2],[3,4]].map(([a,b])=>{a+b}) //[3,7]
map:遍历数组返回一个新数组
对象的解构赋值默认值,没有使用函数参数的默认值:
解释
function foo({ x, y = 0 }) {
console.log(x, y)
}
foo({}); // undefined 0
foo({ x: 0 }); // 0 0
foo({ x: 1, y: 1 }); // 1 1
foo(); //报错:TypeError: Cannot read property 'x' of undefined
如果函数foo调用时没提供参数,变量x和y不会生成,从而报错。
function foo({ x, y = 0 } = {}) {
console.log(x, y)
}
foo({}); // undefined 0
foo({ x: 0 }); // 0 0
foo({ x: 1, y: 1 }); // 1 1
foo(); // undefined 0
为函数参数变量x、y指定默认值
function move({x= 0,y = 0} = {}){
return [x,y]
}
move({x:3,y:8}) = [3,8]
move({x :3}) = [3,0]
move({}) = [0,0]
move() = [0,0]
为函数参数指定默认值{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]
move({}) = [undefined,undefined]
move() = [0,0]
变量的解构赋值用途
- 交换变量的值
let x = 1
let y = 2
[x,y] = [y,x]
- 从函数返回多个值
function example(){
return[1,2,3]
}
let [a,b,c] = example()
function example(){
return {foo:1,bar:2}
}
let {foo,bar} = example()
- 函数参数的定义
function f([x,z,y]){...}
f([1,2,3])
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
- 提取JSON数据
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let {id,status,data:number} = jsonData
number = [867, 5309]
- 函数参数的默认值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}) {
// ... do stuff
};
- 遍历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
- 输入模块的指定方法
加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。
const { SourceMapConsumer, SourceNode } = require("source-map");
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。