变量的解构赋值(模式匹配)
... 拓展运算符 可以将数据类型变为数组
解构赋值:数组的解构赋值 对象的解构赋值
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 匿名的