()的用法:转换成表达式

给已有变量,通过解构赋值的方式赋值

  1. let {a} = {a: 1};
  2. console.log(a);//1

想拆开它,拆开成给变量赋值

错误写法

  1. let a;
  2. {a} = {a: 1};//SyntaxError: Unexpected token '='
  3. console.log(a);//1

image.png
=是错误的

正确写法,用()转换成表达式

模式匹配的本质是声明变量,再给变量赋值,再取值,赋值给变量
es6认为{}是块级作用域,而不是对象的解构赋值操作,不认为{a}是一个对象,不能赋值。需要加()让里面的内容变成表达式
({a} = {a: 1})里面的{a}不会认为是块级作用域了,而认为是表达式的一部分,()里面的内容都是表达式,解构赋值是表达式

  1. let a;
  2. ({a} = {a: 1});
  3. console.log(a);//1

给对象通过解构赋值添加属性

给obj添加对象并且赋值
解构赋值有模式匹配这个步骤,解构赋值的本质是模式匹配,按照一定规则去匹配,提取匹配到的值,并给声明的变量赋值

  1. let a1 = [1, 2, 3], obj2 = {};
  2. [obj2.a, obj2.b, obj2.c] = a1;
  3. // ({obj2.a, obj2.b, obj2.c} = a1);//错误
  4. console.log(obj2.a, obj2.b, obj2.c);//1,2,3

()与{}、[]探究

  1. let [(a)]=[1];//Uncaught SyntaxError: Invalid destructuring assignment target
  1. let {a:(b)}={};//Uncaught SyntaxError: Invalid destructuring assignment target
  2. console.log(b);

这些代码全都报错

用let、var声明,加()就报错

用let声明,加()就报错,不能写在一个语句中

  1. // let {a:(b)}={};
  2. // let {(a):b}={};
  3. let ({a:b})={};
  4. console.log(b);

这个可以通过因为let a;与()写在两个语句中

  1. let a;
  2. ({a} = {a: 1});
  3. console.log(a);//1

()、[]与形参探究

  1. //1.html:63 Uncaught SyntaxError: Unexpected token '('
  2. function foo((z)){
  3. return z;
  4. }
  5. console.log(foo(1));
  1. function foo([z]){
  2. return z;
  3. }
  4. console.log(foo([1]));//1
  1. //Uncaught SyntaxError: Unexpected token '('
  2. // function foo([(z)]){
  3. function foo(([z])){
  4. return z;
  5. }
  6. console.log(foo([1]));

函数传参相当于let声明,let不能与()写,所以错误,与之前代码意思是一样的
声明方式大概是let声明的,底层源码c++写的

总结:用let/var声明,加()就报错

对象{}匹配数组[]

  1. let arr=[1,2,3];
  2. /*{}是匹配规则,有{}对象匹配,[]数组匹配,这里用对象匹配数组,数组也是一种特殊的对象
  3. 所以可以用对象匹配数组
  4. * {}里面的内容是匹配模式,叫匹配属性也行,0是匹配的模式,:first不是,键值对的方式,用什么模式去匹配
  5. [arr.length-1]是表达式,计算属性,应该是arr.length-1是表达式,[]是属性=
  6. let {0:first,[arr.length-1]:last}=arr;
  7. console.log(first,last);//1,3

数组也是特殊的对象,也能进行结构赋值,解构赋值

  1. // var [(b)] = [3];
  2. //Uncaught SyntaxError: Invalid destructuring assignment target
  3. [(b)] = [3];
  4. console.log(b);//3
  1. [(b)] = [3];
  2. // ([b])= [3];//Uncaught SyntaxError: Invalid left-hand side in assignment
  3. /*([b])的规则是是表达式,[3]的规则是数组,所以匹配失败*/
  4. console.log(b);//3
  1. /*认为(b)是变量,变量初始值是={},没有匹配东西,并没有匹配*/
  2. ({a:(b)={}});//{}
  3. // ({a:b={}});//{}
  4. // {a:b={}};//{}
  5. console.log(b);//{}
  1. var a={};
  2. [(a.b)]=[3];
  3. console.log(b);//Uncaught ReferenceError: b is not defined不能匹配
  1. var a={};
  2. [(a.b)]=[3];
  3. console.log(a.b);//3

总结

模式匹配必须模式一样才能匹配,[]{},表达式()不能匹配{}
用let/var声明,加()就报错
()让变成表达式才能加,加时要斟酌斟酌,容易报错

解构赋值

可以通过字符串拼接出对象的属性名

  1. let a='x',b='y',obj={};
  2. ({a:obj[a+b]}={a:2});
  3. console.log(obj);//{xy: 2}
  1. let obj1={a:1,b:3,c:3};
  2. let ({a:obj2.x}=obj1);//Uncaught ReferenceError: let is not defined
  3. /*let后面必须跟着变量,跟着定义的变量名,不能接着表达式*/
  4. console.log(obj1.x)

值的交换es6写法

es6

  1. let a = 10, b = 20;
  2. [b,a]=[a,b];//20 10 相当于({0:b,1:a}={0:a,1:b})
  3. // ({b,a}=[a,b]);//undefined undefined
  4. // ({b,a}=[a,b]);//undefined undefined
  5. // ({0:b,1:a}=[a,b]);//20,10
  6. // ({0:b,1:a}={0:a,1:b});//20,10
  7. console.log(a,b);//20,10
  1. let a = 10, b = 20;
  2. [b,a]=[a,b];//20 10 相当于({0:b,1:a}={0:a,1:b})
  3. // let [b,a]=[a,b];//Uncaught SyntaxError: Identifier 'b' has already been declared
  4. /*加let[]是新建变量了,不加let是用之前的变量,加不加let都能结构赋值,不加let,有新变量之前没有过的,
  5. * 就会用var的方式定义出来*/
  6. // ({b,a}=[a,b]);//undefined undefined
  7. // ({b,a}=[a,b]);//undefined undefined
  8. // ({0:b,1:a}=[a,b]);//20,10
  9. // ({0:b,1:a}={0:a,1:b});//20,10
  10. /*这样也行,b变量=a,a变量=b*/
  11. // ({a:b,b:a}={a:a,b:b});//20,10
  12. console.log(a,b);//20,10

总结

变量的结构,本质就是变量的赋值,变量解构赋值,通过变量的解构进行赋值
解构通过匹配规则和模式拿到响应的变量,并给变量赋值

解构赋值可以同一个属性,给多个变量赋值

模式匹配可以匹配同源属性(同一个原属性);
不会看匹配一次,还是两次,只要能找到a,就会匹配

  1. let {a:x,a:y}={a:1};
  2. console.log(x,y);//1,1

重复定义了

  1. let {a:x,a:x}={a:1};
  2. console.log(x,y);
  3. //Uncaught SyntaxError: Identifier 'x' has already been declared

对象复杂嵌套的解构赋值写法

错误写法:不要把全部都写在一行上面

不要这么写,当对象嵌套很多层时,这样写很容易出错

  1. let person = {
  2. name: 'zhangsan',
  3. age: 50,
  4. son: {
  5. name: 'lisi',
  6. ageLi: 30,
  7. son: {
  8. name: 'wangwu',
  9. ageWang: 18,
  10. son: {
  11. name: 'zhaoliu',
  12. ageZhao: 0
  13. }
  14. }
  15. }
  16. }
  17. let {son: {son: {son: {name, ageZhao}, ageWang}, ageLi}} = person;
  18. console.log(name,ageZhao,ageWang,ageLi);//zhaoliu 0 18 30

正确写法:利用合理的缩进,像写对象字面量一样写解构赋值的代码

利用合理的缩进,当对象嵌套对象时这样做,虽然代码量多了,行数多了,但可读性增加了,可读性很重要

  1. let person = {
  2. name: 'zhangsan',
  3. age: 50,
  4. son: {
  5. name: 'lisi',
  6. ageLi: 30,
  7. son: {
  8. name: 'wangwu',
  9. ageWang: 18,
  10. son: {
  11. name: 'zhaoliu',
  12. ageZhao: 0
  13. }
  14. }
  15. }
  16. }
  17. let {
  18. son: {
  19. son: {
  20. son: {
  21. name, ageZhao
  22. },
  23. ageWang
  24. },
  25. ageLi
  26. }
  27. } = person;
  28. console.log(name, ageZhao, ageWang, ageLi);//zhaoliu 0 18 30

重点题目

  1. var x=200,y=300,z=100;
  2. var obj1={x:{y:42},z:{y:z}};
  3. ({y:x={y:y}}=obj1);
  4. ({z:y={y:z}}=obj1);
  5. ({x:z={y:x}}=obj1);
  6. console.log(x.y,y.y,z.y);

解析

  1. var x=200,y=300,z=100;
  2. var obj1={x:{y:42},z:{y:z}};
  3. ({y:x={y:y}}=obj1);
  4. /*{y:x={y:y}}匹配obj1,加(),右边{y:y}是一个对象,左边y:x不是对象,没法匹配
  5. * 应该拆分成y、x={y:y}赋予默认值,类似于({(y)(:)(x={y:y})}=obj1);虽然这样写报错,
  6. * 这是在这里体现个是一块的,一个整体的
  7. *用伪代码体现结构等,虽然不能运行成功*/
  8. /*匹配y,在obj1里面,最外层找y,没有y,obj1.y=undefined,就会找默认值,x={y:y}意思是给x赋值为对象,从300变成对象了,
  9. * x={y:y}第一个y是键名,第二个y是变量值,是300,x={y:300}*/
  10. ({z:y={y:z}}=obj1);
  11. /*匹配z,有z,不走默认值,变量y=obj.z={y:z}={y=100}*/
  12. ({x:z={y:x}}=obj1);
  13. /*匹配x,有x,z=obj.x={y=42}*/
  14. console.log(x.y,y.y,z.y);//300 100 42

这种方式比较少用,虽然方便,但让代码可读性变低
在解构中使用对象或是数组的时候,慎用(可读性非常差);
当有时,得考虑有没有必要这样写,得练习,解构赋值没有那么简单,有非常多好用的用法,但是基础就这么多,把这些弄懂了,看任何代码都没有问题
组合起来千变万化

等价于

  1. var x=200,y=300,z=100;
  2. var obj1={x:{y:42},z:{y:z}};
  3. /*可以变成,对象产生,变量已经确定了,可以减少复杂度,
  4. 做题的时候,能减少复杂度就减少,kiss原则*/
  5. // var obj1={x:{y:42},z:{y:100}};
  6. ({y:x={y:y}}=obj1);
  7. /*等价于伪代码,先把这一句分析明白了,后面的也就会了,先分析这一句,打印x看看值是什么*/
  8. /*有=就可以拆分,把(变量=值)拆分了*/
  9. /* ({y:(x={y:y})}=obj1);
  10. ({(y):(x={y:y})}=obj1);
  11. ({(y)(:)(x={y:y})}=obj1);*/
  12. console.log(x.y);//300
  13. console.log(x)//{y: 300}

函数形参与解构赋值

  1. function test(x){
  2. console.log(x);
  3. }
  4. console.log(1);//1

形参与数组解构

  1. function test([x,y]){
  2. /*通过结构赋值形参.相当于先进行解构赋值操作*/
  3. // [x,y]=[1,2]
  4. console.log(x);
  5. console.log(y);
  6. }
  7. test([1,2]);//1,2
  1. function test([x, y]) {
  2. console.log(x);
  3. console.log(y);
  4. }
  5. test([1, 2]);//1,2
  6. test([1])//1,undefined
  7. // test()//Uncaught TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
  8. test([])//undefined,undefined

形参与对象解构

  1. function foo({x, y}) {
  2. console.log(x, y);
  3. }
  4. foo({x: 1, y: 2});//1,2
  5. foo({y: 2, x: 1});//1,2
  6. foo({ x: 1});//1,undefined
  7. foo({ });//undefined,undefined
  8. foo();//Uncaught TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined.

函数默认值与解构赋值

解构赋值与不传参数,报错

报错会影响之后程序的执行

  1. function foo({x, y}) {
  2. console.log(x, y);
  3. }
  4. foo();
  5. /*
  6. Uncaught TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined.
  7. 变成了undefined undefined
  8. */

报错解决方法,兼容性写法

  1. function foo({x, y}={}) {
  2. console.log(x, y);
  3. }
  4. foo();//undefined undefined
  1. /*从{}里面取x,没有,取默认值x,={}的=号是找值再赋值,也可以先就理解成找值,
  2. 不是赋值,不是单纯的赋值,不要下意识里就想成赋值了,=有赋值、找值两种用途
  3. * 从{y:10}中找y,y=10*/
  4. function foo({x=10}={},{y}={y:10}) {
  5. // function foo([{x=10}][=][{}],{y}={y:10}) {
  6. console.log(x, y);
  7. }
  8. foo();//10 10

综合题目

  1. /*变成了{x=10}={},{y}={},={}在参数中是默认参数的意思,因为函数的形参是解构赋值语句,所以传入的值充当被查找的对象*/
  2. function foo({x=10}={},{y}={y:10}) {
  3. // function foo([{x=10}][=][{}],{y}={y:10}) {
  4. console.log(x, y);
  5. }
  6. // foo();//10 10
  7. foo({},{});//10 undefined
  8. foo({x:2},{y:3});//2 3
  9. // foo({x=2},{y=3});//Uncaught SyntaxError: Invalid shorthand property initializer
  10. /*一不小心就会出错,即使是大佬写的代码,也可能有马虎犯的低级错误,大公司了,比如微软,即使是大神写的代码,也会进行测试,
  11. *他们也会犯错误,犯低级错误,因为有时就写代码时没有思考,下意识就写了,这很正常 ,之后改正就行了,这与基础牢不牢固无关,
  12. * 就是偶然会出错,低级失误,就像打篮球的职业球员还会运球失误,传球失误,足球也有乌龙球,转态不好等*/
  1. ({x=10}={});
  2. ({x:x=10}={});
  3. console.log(x);//10
  4. ({y}={y:10});
  5. ({y:y}={y:10});
  6. console.log(y);//10

解构存在隐式转换

字符串是类数组对象,也可以进行解构赋值

  1. /*解构的隐式转换*/
  2. /*hello经过隐式转换,转成类数组*/
  3. const [a,b,c,d,e]='hello';
  4. console.log(a,b,c,d,e);//h e l l o
  5. /*转换成类数组,找到length属性,新建变量len赋值*/
  6. let {length:len}='hello';
  7. console.log(len);//5

123转换成Number,再拿到它的toString对象(是个方法)

  1. /*查找到了toString方法*/
  2. let {toString:s}=123;
  3. console.log(s);//ƒ toString() { [native code] }
  4. console.log(s===Number.prototype.toString);//true

布尔值,number,string都能进行隐式转换

undefined、null是不能进行隐式转换的

  1. let {prop}=undefined;
  2. console.log(prop);
  3. //Uncaught TypeError: Cannot destructure property 'prop' of 'undefined' as it is undefined.

undefined、null是不能进行隐式转换的