变量的解构赋值
变量的解构赋值我把它理解为快速的从的、已知数据中提取你想要拿到的数据,既从等号右边复制给左边想要被复制的变量。
数组的解构赋值
下面列举下几中常见的数组解构赋值
var [a,b,c]=[1,2,3,4]
console.log(a,b,c)
// 1 2 3
var [a,b,c]=[1,2]
console.log(a,b,c)
// 1 2 undefined
var [a,[b,c],d]=[1,2,3]
// 报错
var [a, ,c]=[1,2,3]
// a 1
// c 3
可以很直观的看出,等号左边被复制的变量应该按照一一对应的顺序与等号后面对应,比入数组和字符串就是成立的,对应位置的变量也应该相同,第三个例子中就是应为[b,c]与2无法对应,无法进行解析赋值。
let [foo] = 1; //number
let [foo] = false; //boolean
let [foo] = NaN; //NaN
let [foo] = undefined; //undefined
let [foo] = null; //null
let [foo] = {}; //object
默认值
默认值的设置,可以在解析赋值中为赋到值的变量设置一个默认值,当赋值成功过后默认值就被覆盖。
var [a,b,c=3,d=4]=[1,2, ,10]
console.log(a,b,c,d)
// 1 2 3 10
注意,当右边被复制为null的时候,默认值还是会被覆盖,只有为undefined的时候才会启用默认值,如下
var [a,b=2,c=3,d=4]=[1, ,null,undefined]
console.log(a,b,c,d)
同时默认值必须是已知的,即可以采用变量,但是必须是实现申明的变量。
对象的解构赋值
对象的解构赋值大致可以通过两个例子来解释下,通过对象的解构赋值赋值的本质上的机制是啥
let {a,b}={b:1,a:2}
// a 2 b 1
let {a:b,a}={a:1}
// a 1 b 1
通过上面两个例子其实我们可以看出大概的赋值规则
- 首先对象的解构赋值是根据寻找相同key值来赋值的,而数组则是根据顺序来赋值
- 其实对象的解构赋值并不是赋值key值,而是赋值key值指向后面的变量,即上面的例子可以改写为
let {a:a,b:b}={b:1,a:2}
// a 2 b 1
let {a:b,a:a}={a:1}
// a 1 b 1
这样子的话就可以明显的看出其实是复制给key值指向的变量,默认与key值相同,这样看就非常明了了
已声明变量赋值
var a
{a}={a:1}
// 报错
({a}={a:1})
// a 1
var a
var {a}={a:1}
// a 1
var a
let {a}={a:1}
// 报错
导致上面第一个例子报错的原因其实是因为,由于{a}被认为是一个代码块,代码块跟对象赋值肯定不成立,后面由于存在let重复声明了。
解构赋值为浅复制
var a={
b:{
c:1
}
}
var {b}=a
b.c //1
b.c=2
a.b.c //2
可以看出解构赋值他是一个浅复制的过程。
我们发现在对一个对象进行解构赋值的时候,等号右边可以为数组,数组的下标可以作为key值,相反对数组进行解构赋值时,右边必须为数组。
var array=[1,2,3,4]
var {
0:a,
2:b
}=array
// a 1 b 3
var [a,b]={a:1,b:2}
// 报错
默认值
其实对象的默认值跟数组的定义差不多,都是设置为未赋值成功情况下的值
var {
a,
b:c=1,
d=10
}={a:2}
console.log(a,c,d)
// 2 1 10
字符串的解构赋值
var [a,b]='你好'
// a 你 b 好
var a='asdasd'
var {split:method}=a
method.apply('abc',[''])
// [a,b,c]
通过上面的例子,有时候我们可以看成是数组的解构赋值,这样子的话就很好理解,同时也可以通过解构赋值将内置的方法继承出去。
函数参数的解构赋值
基本用法
function c(x,y=2){
console.log(x,y)
}
c(1)
与解构赋值结合的用法
function demo({x,y=5}){
console.log(x,y)
}
demo({}) // undefined 5
demo({x:1,y:2}) // 1 2
demo({x:1}) // 1 5
demo() // 报错
这个相当于对象的解构赋值的操作,所以当传入的参数为空的时候,无法扩展赋值,x未定义,所以报错,其他的按照正常的对象解构赋值就可以得出结果。
当给函数的参数设置默认值的情况
function demo1({x,y}={x:0,y:1}){
console.log(x,y)
}
function demo2({x:0,y:1}={}){
console.log(x,y)
}
demo1() 0 1
demo2() 0 1
demo1({}) undefined undefined
demo2({}) 0 1
demo1({x:3}) 3 1
demo2({x:3}) 3 undefined
通过上面的例子我们就能够很好理解了,在未给函数传参的情况下,函数参数的默认参数才会起作用,即等号右边才会起作用。
函数的length
函数的length属性其实就是除去存在默认值的参数的个数。
(function (x=1,y){}).length //1
因为length属性的含义是,该函数预期传入的参数个数
(function (...args){}).length // 0
注意:在设置了默认值之后的未传默认值的参数也不算入length
(function(x,y=2,z,y){}).length
// 1
参数变量其实默认声明了,所以在函数内不能再申明了,否则会报错
参数的位置
一般把带有默认值的参数都放在后面,如果不为末尾,这样的话不传递该参数的话,后面是无法传递的,同时会导致length属性.
function demo(x=1,y){
console.log(x,y)
}
demo(,1) //报错
demo(null,1) //null 1
记住,只有当赋值为undefined的时候才会采用默认值
作用域
函数参数中的变量设置默认值时,会生成一个单独的作用域。
var a=2
function demo(a,b=a){
console.log(b)
}
demo(1)
// 1
var a=2
function demo(a,b=function(){a=1}){
var a=3
b()
console.log(a)
}
demo()
// 3
var a=2
function demo(a,b=function(){a=1}){
a=3
console.log(a)
}
demo()
// 1
- 上面的第一个例子可以很清楚的看出,函数申明中参数b的默认参数a并不是在外面定义的全局变量。
- 例二可以看出函数中重新申明的a与参数变量的a也不是在同一作用域,所以输出结果为3
- 例三可以看出不声明a,那么这个a的指向就是参数变量a,所以结果为1
圆括号问题
在解构赋值当中,一般我们不建议存在圆括号,应为会产生各种错误,除非那种结构会产生歧义的情况下才需要使用圆括号,下面来看下那些错误的方式和需要用的地方
- 变量声明中不能加圆括号
- 函数参数中,不能带有圆括号。
- 赋值语句中,不能将整个模式,或嵌套模式中的一层,放在圆括号之中
可以使用括号例子
可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确
总结:尽量不要使用圆括号加入到解构赋值中去
用处
1.交换值
var x=1,y=2
[y,x]=[x,y]
// x 2 y 1
2.从函数返回多个值
函数只能返回一个值,可以利用解构同时生成多个值
function demo(){
return [1,2,3]
}
var [a,b,c]=demo()
function demo1(){
return {x:1,y:2}
}
var {x,y}=demo1()
3.函数参数的定义
传递有序参数
function demo([x,y]){
console.log(x,y) // 1 2
}
demo([1,2])
传递无序参数
function demo1({x,y}){
console.log(x,y) //2 1
}
demo1({y:1,x:2})
4.JSON数据的提取
// 提取json中有用的数据
var res={
a:12323,
b:function(){}
}
var {a,b}=res
5.设置参数的默认值
设置默认值,防止报错等
**6.遍历Map解构
var map=new Map()
map.set('你好','世界')
map.set('hello','world')
for(let [key, value] of Map){
console.log(key+' '+value)
}
// 你好 世界
// hello world
6.输入模块的指定方法
import {a, b} = require(model)
加载模块时,提取所需的部分方法,很便捷明了