()的用法:转换成表达式
给已有变量,通过解构赋值的方式赋值
let {a} = {a: 1};console.log(a);//1
想拆开它,拆开成给变量赋值
错误写法
let a;{a} = {a: 1};//SyntaxError: Unexpected token '='console.log(a);//1

=是错误的
正确写法,用()转换成表达式
模式匹配的本质是声明变量,再给变量赋值,再取值,赋值给变量
es6认为{}是块级作用域,而不是对象的解构赋值操作,不认为{a}是一个对象,不能赋值。需要加()让里面的内容变成表达式
({a} = {a: 1})里面的{a}不会认为是块级作用域了,而认为是表达式的一部分,()里面的内容都是表达式,解构赋值是表达式
let a;({a} = {a: 1});console.log(a);//1
给对象通过解构赋值添加属性
给obj添加对象并且赋值
解构赋值有模式匹配这个步骤,解构赋值的本质是模式匹配,按照一定规则去匹配,提取匹配到的值,并给声明的变量赋值
let a1 = [1, 2, 3], obj2 = {};[obj2.a, obj2.b, obj2.c] = a1;// ({obj2.a, obj2.b, obj2.c} = a1);//错误console.log(obj2.a, obj2.b, obj2.c);//1,2,3
()与{}、[]探究
let [(a)]=[1];//Uncaught SyntaxError: Invalid destructuring assignment target
let {a:(b)}={};//Uncaught SyntaxError: Invalid destructuring assignment targetconsole.log(b);
用let、var声明,加()就报错
用let声明,加()就报错,不能写在一个语句中
// let {a:(b)}={};// let {(a):b}={};let ({a:b})={};console.log(b);
这个可以通过因为let a;与()写在两个语句中
let a;({a} = {a: 1});console.log(a);//1
()、[]与形参探究
//1.html:63 Uncaught SyntaxError: Unexpected token '('function foo((z)){return z;}console.log(foo(1));
function foo([z]){return z;}console.log(foo([1]));//1
//Uncaught SyntaxError: Unexpected token '('// function foo([(z)]){function foo(([z])){return z;}console.log(foo([1]));
函数传参相当于let声明,let不能与()写,所以错误,与之前代码意思是一样的
声明方式大概是let声明的,底层源码c++写的
总结:用let/var声明,加()就报错
对象{}匹配数组[]
let arr=[1,2,3];/*{}是匹配规则,有{}对象匹配,[]数组匹配,这里用对象匹配数组,数组也是一种特殊的对象所以可以用对象匹配数组* {}里面的内容是匹配模式,叫匹配属性也行,0是匹配的模式,:first不是,键值对的方式,用什么模式去匹配[arr.length-1]是表达式,计算属性,应该是arr.length-1是表达式,[]是属性=let {0:first,[arr.length-1]:last}=arr;console.log(first,last);//1,3
数组也是特殊的对象,也能进行结构赋值,解构赋值
// var [(b)] = [3];//Uncaught SyntaxError: Invalid destructuring assignment target[(b)] = [3];console.log(b);//3
[(b)] = [3];// ([b])= [3];//Uncaught SyntaxError: Invalid left-hand side in assignment/*([b])的规则是是表达式,[3]的规则是数组,所以匹配失败*/console.log(b);//3
/*认为(b)是变量,变量初始值是={},没有匹配东西,并没有匹配*/({a:(b)={}});//{}// ({a:b={}});//{}// {a:b={}};//{}console.log(b);//{}
var a={};[(a.b)]=[3];console.log(b);//Uncaught ReferenceError: b is not defined不能匹配
var a={};[(a.b)]=[3];console.log(a.b);//3
总结
模式匹配必须模式一样才能匹配,[]{},表达式()不能匹配{}
用let/var声明,加()就报错
()让变成表达式才能加,加时要斟酌斟酌,容易报错
解构赋值
可以通过字符串拼接出对象的属性名
let a='x',b='y',obj={};({a:obj[a+b]}={a:2});console.log(obj);//{xy: 2}
let obj1={a:1,b:3,c:3};let ({a:obj2.x}=obj1);//Uncaught ReferenceError: let is not defined/*let后面必须跟着变量,跟着定义的变量名,不能接着表达式*/console.log(obj1.x)
值的交换es6写法
es6
let a = 10, b = 20;[b,a]=[a,b];//20 10 相当于({0:b,1:a}={0:a,1:b})// ({b,a}=[a,b]);//undefined undefined// ({b,a}=[a,b]);//undefined undefined// ({0:b,1:a}=[a,b]);//20,10// ({0:b,1:a}={0:a,1:b});//20,10console.log(a,b);//20,10
let a = 10, b = 20;[b,a]=[a,b];//20 10 相当于({0:b,1:a}={0:a,1:b})// let [b,a]=[a,b];//Uncaught SyntaxError: Identifier 'b' has already been declared/*加let[]是新建变量了,不加let是用之前的变量,加不加let都能结构赋值,不加let,有新变量之前没有过的,* 就会用var的方式定义出来*/// ({b,a}=[a,b]);//undefined undefined// ({b,a}=[a,b]);//undefined undefined// ({0:b,1:a}=[a,b]);//20,10// ({0:b,1:a}={0:a,1:b});//20,10/*这样也行,b变量=a,a变量=b*/// ({a:b,b:a}={a:a,b:b});//20,10console.log(a,b);//20,10
总结
变量的结构,本质就是变量的赋值,变量解构赋值,通过变量的解构进行赋值
解构通过匹配规则和模式拿到响应的变量,并给变量赋值
解构赋值可以同一个属性,给多个变量赋值
模式匹配可以匹配同源属性(同一个原属性);
不会看匹配一次,还是两次,只要能找到a,就会匹配
let {a:x,a:y}={a:1};console.log(x,y);//1,1
重复定义了
let {a:x,a:x}={a:1};console.log(x,y);//Uncaught SyntaxError: Identifier 'x' has already been declared
对象复杂嵌套的解构赋值写法
错误写法:不要把全部都写在一行上面
不要这么写,当对象嵌套很多层时,这样写很容易出错
let person = {name: 'zhangsan',age: 50,son: {name: 'lisi',ageLi: 30,son: {name: 'wangwu',ageWang: 18,son: {name: 'zhaoliu',ageZhao: 0}}}}let {son: {son: {son: {name, ageZhao}, ageWang}, ageLi}} = person;console.log(name,ageZhao,ageWang,ageLi);//zhaoliu 0 18 30
正确写法:利用合理的缩进,像写对象字面量一样写解构赋值的代码
利用合理的缩进,当对象嵌套对象时这样做,虽然代码量多了,行数多了,但可读性增加了,可读性很重要
let person = {name: 'zhangsan',age: 50,son: {name: 'lisi',ageLi: 30,son: {name: 'wangwu',ageWang: 18,son: {name: 'zhaoliu',ageZhao: 0}}}}let {son: {son: {son: {name, ageZhao},ageWang},ageLi}} = person;console.log(name, ageZhao, ageWang, ageLi);//zhaoliu 0 18 30
重点题目
var x=200,y=300,z=100;var obj1={x:{y:42},z:{y:z}};({y:x={y:y}}=obj1);({z:y={y:z}}=obj1);({x:z={y:x}}=obj1);console.log(x.y,y.y,z.y);
解析
var x=200,y=300,z=100;var obj1={x:{y:42},z:{y:z}};({y:x={y:y}}=obj1);/*{y:x={y:y}}匹配obj1,加(),右边{y:y}是一个对象,左边y:x不是对象,没法匹配* 应该拆分成y、x={y:y}赋予默认值,类似于({(y)(:)(x={y:y})}=obj1);虽然这样写报错,* 这是在这里体现个是一块的,一个整体的*用伪代码体现结构等,虽然不能运行成功*//*匹配y,在obj1里面,最外层找y,没有y,obj1.y=undefined,就会找默认值,x={y:y}意思是给x赋值为对象,从300变成对象了,* x={y:y}第一个y是键名,第二个y是变量值,是300,x={y:300}*/({z:y={y:z}}=obj1);/*匹配z,有z,不走默认值,变量y=obj.z={y:z}={y=100}*/({x:z={y:x}}=obj1);/*匹配x,有x,z=obj.x={y=42}*/console.log(x.y,y.y,z.y);//300 100 42
这种方式比较少用,虽然方便,但让代码可读性变低
在解构中使用对象或是数组的时候,慎用(可读性非常差);
当有时,得考虑有没有必要这样写,得练习,解构赋值没有那么简单,有非常多好用的用法,但是基础就这么多,把这些弄懂了,看任何代码都没有问题
组合起来千变万化
等价于
var x=200,y=300,z=100;var obj1={x:{y:42},z:{y:z}};/*可以变成,对象产生,变量已经确定了,可以减少复杂度,做题的时候,能减少复杂度就减少,kiss原则*/// var obj1={x:{y:42},z:{y:100}};({y:x={y:y}}=obj1);/*等价于伪代码,先把这一句分析明白了,后面的也就会了,先分析这一句,打印x看看值是什么*//*有=就可以拆分,把(变量=值)拆分了*//* ({y:(x={y:y})}=obj1);({(y):(x={y:y})}=obj1);({(y)(:)(x={y:y})}=obj1);*/console.log(x.y);//300console.log(x)//{y: 300}
函数形参与解构赋值
function test(x){console.log(x);}console.log(1);//1
形参与数组解构
function test([x,y]){/*通过结构赋值形参.相当于先进行解构赋值操作*/// [x,y]=[1,2]console.log(x);console.log(y);}test([1,2]);//1,2
function test([x, y]) {console.log(x);console.log(y);}test([1, 2]);//1,2test([1])//1,undefined// test()//Uncaught TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))test([])//undefined,undefined
形参与对象解构
function foo({x, y}) {console.log(x, y);}foo({x: 1, y: 2});//1,2foo({y: 2, x: 1});//1,2foo({ x: 1});//1,undefinedfoo({ });//undefined,undefinedfoo();//Uncaught TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined.
函数默认值与解构赋值
解构赋值与不传参数,报错
报错会影响之后程序的执行
function foo({x, y}) {console.log(x, y);}foo();/*Uncaught TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined.变成了undefined undefined*/
报错解决方法,兼容性写法
function foo({x, y}={}) {console.log(x, y);}foo();//undefined undefined
/*从{}里面取x,没有,取默认值x,={}的=号是找值再赋值,也可以先就理解成找值,不是赋值,不是单纯的赋值,不要下意识里就想成赋值了,=有赋值、找值两种用途* 从{y:10}中找y,y=10*/function foo({x=10}={},{y}={y:10}) {// function foo([{x=10}][=][{}],{y}={y:10}) {console.log(x, y);}foo();//10 10
综合题目
/*变成了{x=10}={},{y}={},={}在参数中是默认参数的意思,因为函数的形参是解构赋值语句,所以传入的值充当被查找的对象*/function foo({x=10}={},{y}={y:10}) {// function foo([{x=10}][=][{}],{y}={y:10}) {console.log(x, y);}// foo();//10 10foo({},{});//10 undefinedfoo({x:2},{y:3});//2 3// foo({x=2},{y=3});//Uncaught SyntaxError: Invalid shorthand property initializer/*一不小心就会出错,即使是大佬写的代码,也可能有马虎犯的低级错误,大公司了,比如微软,即使是大神写的代码,也会进行测试,*他们也会犯错误,犯低级错误,因为有时就写代码时没有思考,下意识就写了,这很正常 ,之后改正就行了,这与基础牢不牢固无关,* 就是偶然会出错,低级失误,就像打篮球的职业球员还会运球失误,传球失误,足球也有乌龙球,转态不好等*/
({x=10}={});({x:x=10}={});console.log(x);//10({y}={y:10});({y:y}={y:10});console.log(y);//10
解构存在隐式转换
字符串是类数组对象,也可以进行解构赋值
/*解构的隐式转换*//*hello经过隐式转换,转成类数组*/const [a,b,c,d,e]='hello';console.log(a,b,c,d,e);//h e l l o/*转换成类数组,找到length属性,新建变量len赋值*/let {length:len}='hello';console.log(len);//5
123转换成Number,再拿到它的toString对象(是个方法)
/*查找到了toString方法*/let {toString:s}=123;console.log(s);//ƒ toString() { [native code] }console.log(s===Number.prototype.toString);//true
undefined、null是不能进行隐式转换的
let {prop}=undefined;console.log(prop);//Uncaught TypeError: Cannot destructure property 'prop' of 'undefined' as it is undefined.
undefined、null是不能进行隐式转换的
