变量的解构赋值(模式匹配)

  ...  拓展运算符  可以将数据类型变为数组

  解构赋值:数组的解构赋值  对象的解构赋值

  1. 前后模式必须匹配

    后面的值是什么格式,前面变量声明的也是什么格式,比如后面的值是二维数组,前面声明的也是二维模式

    案例:

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

      console.log(b);   //2

  2. 前多后少

    前面声明的变量多,后面赋值的少,解构不成功,就相当于只声明了变量,但没赋值,解构不成功,值都是 undefined

    案例:

      let [a,b]=[1];   // a    b   是变量

      console.log(b)  // undefined

  3. 前少后多

    1. 省略赋值  let[,,c]=[45,12,33]     //  c 是变量

    2. 不定参数的解构赋值,使用 ... 叫拓展运算符 ,注意事项 :拓展运算符必须写后面

      拓展运算符:...as 将后面的值以数组的形式,赋值给 as ,拓展运算符必须写在最后

    案例:

      1. let [,,c]=[45,26,13] // c 是变量

          console.log(c)  // 13

      2. let [...a]=[45,26,13];    // a 是变量

          console.log(a)  // 数组的形式 [45,26,13]

  4. 带有默认值问题

    问题:先给默认值,在解构赋值,还是先解构赋值,如果没有在考虑默认值?

    案例分析

      let [x,y=(function(){console.log("haha");return 10;})()]=[45,23];

      console.log(y)  //23

      最终没有输出 haha ,说明不是先给默认值,二十先解构赋值,如果没有,在考虑默认值

  所以:解构不成功的时候,才会有默认值,没有赋值,没有定义

  判断一个变量有没有定义:

    var a=null;  a=[];  a={};  a=""   都是定义了

    var a=undefined   未定义

    所以只有解构的时候,后面是 undefined 的时候,才会走默认值,否则后面给什么值就是赋值什么;

  解构不成功:undefined

  对象的解构赋值;

    1. 变量和属性必须同名,才可以解构赋值

    2. 如果解构失败,值是 undefined

      let {name,a}={name:"zhang",age:20};  // name a 是变量

      console.log(name,a) // zhang   undefined

      其中 name a 是变量  对象的 name age 是属性,name变量 找到了对象的属性 name 所以,得到值为 zhang; 

      a 变量,找不到对象的属性,所以得不到值,为 undefined;  

      因为解构赋值,所以我们有了这样一个新的写法

      let {ceil}=Math;  

      console.log(ceil(1.2))  // 2    解析这个代码  let {ceil} = {ceil:function(){}}   //这里面放的 math 对象的方法, ceil 的方法等于 ceil 的变量,所以 ceil 的变量 也拥有了相同的方法

    3. 特殊情况,变量名和属性名不一致怎么办?

      let {foo:b}={foo:"zhang"}  //  = 左边: foo 是属性 b 是变量  = 右边:foo 是属性

        前面 foo 是属性,后面 b 变量,解构的机制,是对应的属性值 赋值给后面的变量

    4. 对象解构的默认值问题

      默认值跟数组解构的默认值是一样的,解构成功就直接赋值,不走默认值,解构不成功,就是没有值,或者值是 undefined 走默认值;

      let {name,age=45}={name:zhang}  console.log(age) // 45 

      let {name,age=45}={name:"zhang",age:undefined}   console.log(age)   //45      

    5. 对象解构的赋值注意点

      {} 前面不能没东西    {a}={a:12}  x  这种写法是错的

      解决:我们必须声明 一个变量才可以:let {a}={a:12}

    6. = 右边在什么情况下,才可以解构

      = 右边的值,只要带有 length 属性,才可以解构,如果非要把不能解构的东西解构,转成字符串即可

  函数参数解构

    函数传对象,要在形参附一个空对象

  带 = 

  function fn([a,b]=[12,23]){

    console.log(a+b)

  }  

  函数参数默认值

  function fn(b,v=12){

    console.log(b)

  }

  fn(12)  前面是形参,后面是默认值,带默认值的参数尽量要写后面

 

  两句法则:

    有没有办法解构

    解构成不成功

  函数参数等号左边是形参,右边是默认值,函数调用不传参,走函数形参的默认值;函数调用传参,默认值就不走了,走实参

 

  备注:

    函数作用域

    函数在调用会形成私有作用域,在这个作用域下,声明的变量和参数变量都是私有的变量,外界访问不到同时,他在操作相同的变量是,不会操作外部的

  

  形参的没有变量提升,如果传值直接赋值,所以形参有暂时性死区这一说

  暂时性死区,没有赋值,直接操作变量

 

  函数一个类数组参数 arguments 是实参构成的集合,是一个类数组

  ... 拓展运算符,可将实参变成一个数组;

 

  5. 箭头函数

    1. 箭头函数 是适用于匿名函数

    用 function 声明的函数,是有名函数

    做回调函数的时候,也是一个匿名函数

    var fn=function(){}    匿名函数    做了回调函数

  匿名函数的定义:只要不是关键字 function 声明的函数叫匿名函数

  var fn=(形参) => { 函数体 }

  每个函数结束的时候一定要 return

  let fn=x=>x   这种语法 : 第一个 x  代表 形参  第二个 x 代表 return 的语句

  当只有一个参数,可以省略小括号;

  当函数体只有一行代码且 return xxx 的时候,可以省略 {} 和 return

  箭头函数的优势:

    1. 箭头函数没有 this 指向

      改变 this 指向的方法

        1. 在函数前 提前对 this 赋值

        2. 在函数结尾处 {}.bind(this)

        3. 在函数结尾处 {}.apply(this) 或 {}.call(this)

        4. 使用箭头函数

    2. 箭头函数获取实参,不能使用arguments 用 ...arg

    3. 箭头函数不能充当类,因为 this 指向 window,而 类 的 this 指向当前实例对象

     箭头函数的 this 指向 window

    函数角色

      函数可以扮演 类,普通函数,function 实例对象

      类:每个类身上有一个 prototype 的属性,这个属性是一个对象,里面有个 constructor 的属性,属性值是类本身

      new 实例的时候,其实就是调用这个 constructor 的函数

      对象,每个对象天生有个 __proto__ 的属性

    __proto__ 也是一个对象,里面有个构造函数指向他的类这个对象,也有一个 constructor 这个属性值是他的类

  对象的属性

    首先看对象中私有的属性中,有没有这个属性,有就直接使用,没有就使用 __proto__  向他的父类的原型上查找;

  注意:

    1. object 是所以对象的基类,包括 window event 等

    2. 普通函数的父类是 Function 

    3. 通过 function 定义的类 是 Function 

    4. 所以实例对象的 __proto__ 都指向父类的原型;

  实例对象的原型 __proto__ 如果私有没有就找父类原型的 如果父类没有直接查找 Object 的原型 不找 Function

  anonymous  匿名的