😁 作者简介:一名大三的学生,致力学习前端开发技术
⭐️个人主页:夜宵饽饽的主页
❔ 系列专栏:前端js专栏
👐学习格言:成功不是终点,失败也并非末日,最重要的是继续前进的勇气
🔥前言:
这是自己在学习JavaScript的学习笔记和总结,希望可以帮助到你,解构赋值是一个非常棒的方法,可以使代码易读,简洁,高效
第3章 变量的解构赋值
3.1 数组的解构赋值
3.1.1 基本用法
ES6允许按照一定模式从数组和对象中提取值,然后对变量进行赋值,这被称为解构
1.解构成功
let [foo, [[bar], baz]]=[1, [[2], 3]]
//foo=1,bar=2,baz=3
let [head,...tail]=[1,2,3,4]
//head=1,tail=[2,3,4]
2.解构失败
如果解构失败,变量的值就等于undefined
let [foo]=[];
let [bar,foo]=[1];
//foo=undefined
以上两种情况的foo的值都为undefined
3.解构不完全
等号左边的模式只匹配一部分的等号右边的数组,这种情况下,解构依然是可以成功的
let [x,y]=[1,2,3]
4.解构异常
如果等号的右边不是数组(严格的说不是可遍历的结构),那么解构将会报错
//报错
let [foo]=1;
let [foo]=false
let [foo]=NaN
let [foo]=undefined
let [foo]=null
let [foo]={}
上面的语句都会报错
3.1.2 默认值
解构赋值允许指定默认值
let [ foo=true ]=[]
//foo=true
let [ x, y='b' ]=['a']
//x='a',y='b'
⭐️ 注意:要使默认值生效,数组成员的值必须严格等于undefined
let [x=1]=[undefined]
//x=1
以下这种情况默认值不会生效
let [x=1]=[null]
//x=null
如果一个默认值是一个表达式,那么这个表达式是惰性求值,即只有在用到时才会求值
function f(){
console.log('aaa')
}
let [ x=f() ]=[ 1 ]
上面的代码中,因为x能取到值,所以函数f根本不会执行。
⭐️:默认值可以引用解构赋值的其他变量,但该变量必须已经声明
let [x=1,y=x]=[1,2]
//x=1,y=2
let [x=y,y=1]=[];
//ReferenceError
最后的表达式之所以会报错,是因为x使用到y时,y还没有声明
3.2 对象的解构赋值
对象的解构赋值与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值是由它的位置决定的,而对象的属性没有次序,所以我们要从变量与属性名考虑
3.2.1.变量与属性名同名
let {bar foo}={foo:'aaa',bar:'bbb'}
//foo='aaa'
//bar='bbb'
3…2.2.变量与属性名不一致
var {foo:baz}={foo:'aaa',bar:'bbb'}
//baz='aaa'
这两种方法,我们如果从对象的简介形式考虑,会发现这两种情况是一样的
let {bar:bar,foo:foo}={foo:'aaa',bar:'bbb'}
也就是说,对象的解构赋值的内部机制是找到同名属性,然后再赋值给对应的变量,真正被赋值的是后者,而不是前者,
上面的代码中,foo是匹配的模式,baz才是变量,真正被赋值的是变量baz,而不是模式foo
3.2.3.解构嵌套结构的对象
let obj={
p:[
'Hello',
{y:'World'}
]
};
let {p:[ x , {y} ] }=obj
//x='Hello'
//y='World'
❗️ 注意:这时候p是模式,不是变量,因此不会被赋值,如果我们想要p也作为变量去赋值的话,可以这样写
let obj={
p:[
'Hello',
{y:'World'}
]
};
let { p, p:[ x , {y} ] }=obj
//x='Hello'
//y='World'
//p=['Hello,{y:'World'}']
或者我们也可以使用其他已经声明的变量来嵌套赋值
let obj={}
let arr=[];
({foo:obj.prop,bar:arr[0]}={foo:123,bar:true})
//obj={prop:123}
//arr=[true]
我们可以注意到,解构语句打上了圆括号,这是因为,我们不打上圆括号的话,JavaScript引擎会将{x}理解成为代码块,从而发生语法错误,只有不将大括号写在行首,避免JavaScript将其解释为代码块,关于解构赋值与圆括号的关系请看下文
3.2.4 对象解构的默认值
默认值生效的条件依旧是undefined
var {x=3}={}
//x=3
var {x:y=3}={}
//y=3
var {x:y=3}={x:5}
//y=5
3.2.5 现有对象的解构
let {log,sin cos}=Math
上面的代码会将Math对象的对数,正弦,余弦三个方法赋值到对应的变量上,使用起来就会方便很多
3.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
3.4 数值和布尔的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
let {toString:s}=123
//s===Number.prototype.toString
解构赋值的规则是,只要等号的右边不是数值或对象,就要转换为对象
3.5 函数参数的解构赋值
3.5.1 基本用法
function add([x,y]){
return x+y
}
add([1,2])
上面的代码中,函数add的参数表面上是一个数组,但在传入参数的那一刻,数组被解构成变量x和y,对于函数内部的代码来说,它们能感受到参就是x和y
3.5.2 使用默认值
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]
上面的代码中,函数move的参数是一个对象,通过对这个对象进行解构,得到变量y和x的值,如果解构失败,x和y等于默认值
❗️注意:还有一种写法会得到不同的情况
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]
上面的代码中,是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会有不同的结果
😄:理解的小技巧
你可以先不考虑参数中的({x,y}={x:0,y:0})的右边,就当做真正的参数解构赋值,({x,y})
然后去赋值
当遇到什么都没有传入,那么就考虑函数本身的默认值,就比如
function fn(x=3){}
fn()
这样的话,函数的默认值x=3就成立啦
3.6 圆括号的问题
❓ 问题:解构赋值虽然方便,但是解析起来并不容易,对于编译器来说,一个式子到底是模式还是表达式,没有办法从一开始就知道,必须解析到等号才能知道。
由此带来的问题是,如果模式中出现圆括号该怎么处理?ES5的规则是,只要有可能导致解构的歧义,就不得使用圆括号
但是,这条规则实际上不那么容易辨别,处理起来相当麻烦,因此建议,只要有可能,就不要在模式中使用圆括号
3.6.1 不能使用圆括号的情况
1. 变量声明语句
let [(a)]=[1]
let {x:(c)}={}
let ({x:c})={}
let {(x:c)}={}
let {(x):c}={}
let {o:({p:p})}={o:{p:2}}
上面6个语句会报错,因为它们都是变量声明语句,模式不能使用圆括号。
2.函数参数
函数参数也属于变量声明,因此不能使用圆括号
//报错
function f([z]){return z;}
//报错
function f([z,(x)]){return x;}
3.赋值语句的模式
//全部报错
( { p:a } )={ p:42 }
( [a] )=[5]
上面的代码将整个模式放在圆括号之中,导致报错
//报错
[( { p:a } ),{x:c}]=[{},{}]
上面的代码将一部分模式放到圆括号之中,导致报错
3.6.2 可以使用圆括号的情况
这种情况只有一种就是:赋值语句的非模式部分可以使用圆括号
[(b)]=[3] //正确
({p:(d)}={}) //正确
[(parseInt.prop)]=[3] //正确
上面的三个语句都是可以正确执行,因为它们都是赋值语句,而不是声明语句,另外它们的圆括号都不属于模式的一部分
- 第1行语句中,模式是取数组的第一个成员,跟圆括号无关
- 第2行语句中,模式是p而不是d
- 第3行语句与第1行语句的性质一样
3.7 用途
3.7.1 交换变量的值
let a=1
let b=2
[a.b]=[b,a]
上面的代码交换了变量的值,这种写法不仅简单,而且易读
3.7.2 从函数返回多个值
一般来说,函数只能返回一个值,要想返回多个值,必须将它们放在数组或者对象里返回,当使用解构赋值时,取出这些值就变得非常方便
//返回一个数组
function example(){
return [1,2,3]
}
let [a,b,c]=example()
console.log("a=%s,b=%s,c=%s",a,b,c)
//a=1,b=2,c=3
//返回一个对象
function exampleobj(){
return {
foo:1,
bar:2
};
}
let {foo,bar}=exampleobj()
console.log("foo=%s,bar=%s",foo,bar)
//foo=1,bar=2
3.7.3 函数参数的定义
解构赋值可以方便地将一组参数与变量名对应起来。
//参数是一组有序的值
function f([x.y.z]){...}
f([1,2,3])
//参数是一组无序的值
function fe({x,y,z}){...}
f({z:3,y:2,x:1})
3.7.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]
3.7.5 函数参数的默认值
jQuery.ajax=function(url,{
async=true,
beforeSend=function(){},
cache=true,
complete=function(){}
...
}){
}
指定参数的默认值,这样就避免了在函数体内部再写var foo=config.foo||‘default foo’ 这样的语句了
3.7.6 输入模块的指定加载方法
const {SourceMapConsumer,SourceNode}=require("source-map")