欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2. 解构赋值

程序员文章站 2024-01-28 11:25:40
...

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称作解构,之前我们为变量进行赋值,只能直接指定

let a=1;

ES6允许我们以以下方式对变量进行赋值

let[a,b,c]=[1,2,3];
//a 1 b 2 c 3

let [a,[b],c,d]=[1,[2],3];
// a 1 b 2 c 3 d undefined

let[a,,c]=[1,2,3];
// a 1 c 3
//上面代码表示,可以从数组中提取值,按照对应位置对变量进行赋值,本质上这种写法属于匹配模式,只要等号两边的模式相同,左边的变量就会被赋予对应的值,如果匹配没有成功,那么会赋值为undefined

//注意,解构要求右边必须是可遍历的结构,否则会报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
//以上这些都报错
//解构赋值允许使用默认值,我们可以提前为变量设置默认值
let[x=1]=[ ];//1

//同时需要注意,在使用时解构的值的优先级是高于默认值的,但在存在默认值的情况下我们不能通过解构为某个值赋值为undefined
let[x=1]=[2];//2

let[x=1]=[undefined];//1

//如果默认值是一个表达式,但是该表达式是惰性求职的,只有在有用的时候才会求值,否则该表达式不会运行
function fn(){  
    return 'hello';
}
let [x=fn()]=[1];//1

let[x=fn()]=[];//hello

//默认值可以引用解构赋值的其它变量,但该变量之前必须已经被声明
let[x=1,y=x]=[2] //x=2 y=2
let[x=y,y=1]=[ ] // //ReferenceError

对象的解构赋值

解构不仅可以用于数组,还可以用于对象,但与数组的结构赋值不同的是,数组的解构赋值是按照排列顺序来对照进行赋值,但是对象则没有次序,必须变量与属性同名,才能取到正确的值

let {bar,foo}={foo:"a",ber:"b"};
//foo a
//bar b
let {baz}={foo:"a",bar:"b"};
baz //undefined

//如果我们想要为baz赋值,而在对应的解构中没有baz的同名对象,那么我们需要使用以下的格式
let {foo:baz}={foo:"a",bar:"b"};
console.log(baz); //a

let obj={first:"hello",last:"world"};
let {first:f,last:l}=obj;
console.log(l); //hello
console.log(f); //world
//由上面的解构赋值我们可以发现,解构后的值并不是赋值在first和last上的,而是赋值在f,l上,那么我们可以推导出实际的赋值过程
let {foo,bar}={foo:"a",bar:"b"}//实际是下面的过程
let{foo:foo,bar:bar}={foo:"a",bar:"b"}//在赋值时如果我们在左侧没有手动设置属性的对应值,那么会默认为我们转化为foo:foo的格式,然后再右侧找到与foo同名的属性,将对应的值赋值在左侧的变量对应的值上,也就是说真正被赋值的是右侧的变量

与数组一样,解构也可以用于嵌套结构的对象

let obj={
    loc:{
        start:{
            line:1,
            column:5
         }
    }
};

let {loc,loc:{start},loc:{start:{line}}}=obj;

console.log(loc);   //{start{...}}
console.log(start); //{line: 1, column: 5}
console.log(line);  //1
//注意,在最后一次的赋值中,只有line是变量,loc和start都是模式

//在使用已经声明的变量来进行解构时,必须确保{不在首行,否则js会将其作为块来解析,浏览器会报错,在这种情况下我们需要使用()将整体包裹起来,避免js将其解释为代码块
let obj={},
    arr=[];
({foo:obj.prop,bar:arr[0]}={foo:123,bar:true})
console.log(obj); //prop:123
console.log(arr); //[true]

//解构允许在等号左边的模式之中不放置任何的变量名,因此,可以写出以下的格式,不过毫无意义
({}=[true,false]);

对象的解构赋值也可以设定默认值

var {x = 3} = {};
x // 3

var {x, y = 5} = {x: 1};
x // 1
y // 5

var {x: y = 3} = {};
y // 3

var {x: y = 3} = {x: 5};
y // 5

对象的解构赋值,可以很方便的将对象的方法,赋值到某个变量上

let {log,sin,cos}=Math;
console.log(log); //ƒ log() { [native code] }
//上面的代码可以很轻松的帮我们实现将Math.log方法赋值到变量log上

由于数组的本质是特殊的对象,因此可以对数组进行对象属性的解构

let arr=[1,2,3];
let {0:first,[arr.length-1]:last}=arr;
console.log(first); //1
console.log(last);  //3

//arr在对象的解构时格式是[下标值:值],也就是说上面的例子实际可以理解为
{0:first,2:last}={0:1,1:2,2:3}

字符串/布尔值/数值的解构赋值

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值

let {length:len}="hello";
//len 5
let {toString:s}=123;
//s  ƒ toString() { [native code] }
//对这段代码我自己的理解是在使用对象解构时会默认将右边的代码转化对象格式并去查询是否存在有与左边同名的属性,如果存在的话那么就将赋值左边的变量,没有的话赋值为undefined