()的用法
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 target
console.log(b);
这些代码全都报错
用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
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,10
console.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,10
console.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);//300
console.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,2
test([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,2
foo({y: 2, x: 1});//1,2
foo({ x: 1});//1,undefined
foo({ });//undefined,undefined
foo();//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
*/
/*从{}里面取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 10
foo({},{});//10 undefined
foo({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
/*查找到了toString方法*/
let {toString:s}=123;
console.log(s);//ƒ toString() { [native code] }
console.log(s===Number.prototype.toString);//true
布尔值,number,string都能进行隐式转换
let {prop}=undefined;
console.log(prop);
//Uncaught TypeError: Cannot destructure property 'prop' of 'undefined' as it is undefined.
undefined、null是不能进行隐式转换的