目录
一、解构
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构,解构的本质属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。如果解构不成功,变量的值就等于undefined。
1、数组解构
数组解构就是将等号左边的变量放到中括号内部,匹配右侧数组中的元素。
要注意模式匹配,即等号右边为数组,那么左边也应该用数组接收。
1.1 完全解构
let [a,b,c,d,e] = [1,2,3,4]
console.log(a,b,c,d,e); //1 2 3 4 undefined
let [a,b,c,d,e] = [1,2,3,[4,5],6]
console.log(a,b,c,d,e); //1 2 3 [ 4, 5 ] 6
1.2 不完全解构
let [a,b,c,[d],e] = [1,2,3,[4,5,6],7]
console.log(a,b,c,d,e); //1 2 3 4 7
1.3 默认值解构
给a,b,c分别设置默认值为1,2,3,当匹配值严格等于undefined时,默认值才生效。
默认值不生效:
let [a=1,b=2,c=3] = [4,5,6]
console.log(a,b,c); //4 5 6
匹配值为undefined,默认值生效:
let [a=1,b=2,c=3] = []
console.log(a,b,c); //1 2 3
let [a=1,b=2,c=3] = [4,5]
console.log(a,b,c); //4 5 3
默认也可以是函数:
let test = ()=>{
console.log('我是箭头函数');
}
let [a=test()] = []
console.log(a); //我是箭头函数
(输出的值后面还有一个undefined是因为函数没有写返回值)
1.4 集合解构(使用扩展运算符)
扩展运算符[...]会把余下的值全部匹配到
let [a,...b] = [1,2,3,4]
console.log(a,b); //1 [ 2, 3, 4 ]
扩展运算符实现的是值的拷贝而不是引用:(因此可以用来实现深拷贝)
let a = [1,2,3,4,5]
let [...arr] = a
console.log(arr); //[ 1, 2, 3, 4, 5 ]
console.log(arr === a); //false
2、对象解构
对象解构就是将等号左边的变量放到大括号内部,匹配右侧对象中的元素。对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
同样的也要注意模式匹配,即等号右边为对象,那么左边也应该用对象接收。
变量与属性同名:
let {name,age}={name:"zhangsan",age:18}
console.log(name,age); //zhangsan 18
上述代码相当于:
let {name:name,age:age}={name:"zhangsan",age:18}
console.log(name,age); //zhangsan 18
如果变量名和属性名不一致,需要重命名:
let {name:a,age:b} = {name:"zhangsan",age:18}
console.log(a,b); //zhangsan 18
2.1 嵌套解构
比如我们有如下嵌套结构,我们如何解构,使得变量a取得'hello',变量b取得'world'
let obj={p:['hello',{y:"world"}]};
分析:
1、首先,最外层是对象,根据模式匹配,左边我们也要使用对象,即{}
2、然后对象里面是属性名p,根据变量名和属性名一致:{p}
3、接下来属性值是一个数组,根据模式匹配,我们也要用数组:{p:[]}
4、然后数组里面用a变量接收'hello':{p:[a]}
5、然后数组的第二个元素又是一个对象,根据模式匹配,我们要使用对象:{p:[a,{}]}
6、然后对象里面是属性名y,根据变量名和属性名一致,我们应该使用y,但是我们想要使用变量b取得'world',所以我们要重命名:{p:[a,{y:b}]}
最终解构结果如下:
let obj={p:['hello',{y:"world"}]};
let {p:[a,{y:b}]} = obj
console.log(a,b); //hello world
2.2 默认解构
当匹配值严格等于undefined时,默认值才生效。
let {x:y=10}={x:6}
console.log(y); //6
小练习:
const [a, b, c, ...d] = [1, 2, 3, 11, 999];
const { e,f1, g, ...h } = { f: 4, g: 5, i: 6, j: 7 };
console.log(a, b, c, d, e, f1, g, h); //1 2 3 [ 11, 999 ] undefined undefined 5 { f: 4, i: 6, j: 7 }
扩展运算符[...]会把剩余的未被解构赋值的全部获取到,因此d的值为[ 11, 999 ],h的值为{ f: 4, i: 6, j: 7 },e和f1变量名和属性名不同,无法获取到值,因此为undefined。
3、字符串解构
3.1 使用数组进行解构
let [a,b,c,d,e]='hello'
console.log(a,b,c,d,e); //h e l l o
3.2 使用扩展运算符解构
let [...arr] = 'world'
console.log(arr); //[ 'w', 'o', 'r', 'l', 'd' ]
3.3 使用对象进行解构
let {toString,valueOf,length} = 'hello'
console.log(toString,valueOf,length); //[Function: toString] [Function: valueOf] 5
相当于把'hello'当成String基本包装器类型。
4、数值解构
let {toString,valueOf}=10;
console.log(toString,valueOf) //[Function: toString] [Function: valueOf]
5、布尔值解构
let {toString,valueOf}=true;
console.log(toString,valueOf); //[Function: toString] [Function: valueOf]
6、函数参数解构
// 1.函数参数对象解构
function test({name,age,...a}){ //...a解构剩余对象中的属性并返回一个新对象
console.log(name,age,a) //zhangsan 12 { gender: 1 }
}
test({name:"zhangsan",age:12,gender:1})
// 2.函数参数对象默认值解构
function test1({name,age=1,...a}){
console.log(name,age,a) //zhangsan 1 { gender: 1 }
}
test1({name:"zhangsan",gender:1})
// 3.函数参数数组解构
function test2([a,b,c,d]){
console.log(a,b,c,d) //1 2 3 4
}
test2([1,2,3,4])
函数的length属性
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。通常情况下,定义了默认值的参数,应该是函数的尾参数,此时函数的length属性将返回没有指定默认值的之前的参数个数 。
function test(a,b,c,d,e=3,f,g){
}
test(1,2,3)
//函数名.length 返回形参个数
console.log(test.length); //4 (设定默认值之后就成尾参数了,它及之后的参数都会被忽略)
二、扩展运算符
拓展运算符用到左侧是聚合,用到右侧是展开:
let [...a] = arr
console.log(a); //[ 1, 2, 3, 4 ]
let obj = {name:"zhangsan",age:18}
let obj1 = {gender:'male'}
let temp = {
...obj,
...obj1,
}
temp.id = 100
console.log(temp); //{ name: 'zhangsan', age: 18, gender: 'male', id: 100 }
三、箭头函数
普通函数:
let test = function(){
console.log("我是普通函数");
}
箭头函数:
let test = ()=>{
console.log("我是箭头函数");
}
小括号中写形参,如果形参只有一个,可以省略括号,(但不建议省略),花括号里面写函数体,如果函数体只有一条语句,可以省略花括号:
let test = a=>console.log(a,"我是箭头函数");
test(10) //10 我是箭头函数
1、箭头函数中this的指向
箭头函数没有自己的this,内部this指向声明箭头函数时外部作用域中的this。
来看几个例子:
(1)普通函数声明的方法,this指向对象本身,因此上述结果为zhangsan
let obj = {
name:"zhangsan",
age:18,
sayName(){
console.log(this.name); //zhangsan
}
}
obj.sayName()
(2)当方法使用箭头函数声明时,箭头函数外部作用域就是全局作用域。
node环境下:
node环境下单独使用this时,this指向一个{}
let name = 'lisi'
let obj = {
name:"zhangsan",
age:18,
sayName:()=>{
console.log(this.name); //undefined
console.log(this); //{}
}
}
obj.sayName()
console.log(this); //{}
浏览器环境下:
(由于let和const声明的变量不会挂载到window上,因此这里使用var声明变量name)
var name = 'lisi'
let obj = {
name: "zhangsan",
age: 18,
sayName: () => {
console.log(this.name); //lisi
console.log(this); //window
}
}
obj.sayName()
(3)方法中返回一个箭头函数:此时箭头函数的外部作用域是sayName方法,因此箭头函数this的指向就是sayName方法this的指向,sayName方法this指向对象obj
let name = 'lisi'
let obj = {
name: "zhangsan",
age: 20,
sayName(){
return ()=>{
console.log(this.name); //zhangsan
console.log(this); //obj
}
}
}
obj.sayName()()
(4)方法中返回一个全局作用域定义的箭头函数:此时箭头函数的外部作用域是全局作用域
node环境下:
let name = 'lisi'
let sayName = () => {
console.log(this.name); //undefined
console.log(this); //{}
}
let obj = {
name: "zhangsan",
age: 20,
sayName() {
return sayName
}
}
obj.sayName()()
console.log(this); //{}
浏览器环境下:
var name = 'lisi'
let sayName = () => {
console.log(this.name); //lisi
console.log(this); //window
}
let obj = {
name: "zhangsan",
age: 20,
sayName() {
return sayName
}
}
obj.sayName()()
console.log(this); //window
2、箭头函数的rest参数
es5函数内部属性有arguments,箭头函数内arguments不再保存实参,如果想接受实参,可以使用rest参数。
rest参数实际上是扩展运算符,只是给它起了一个高级的名字:rest参数。
let test=(a,...b)=>{
console.log(a,b); //1 [ 2, 3, 4, 5 ]
}
test(1,2,3,4,5)
3、普通函数和箭头函数的区别
(1)表现形式不同
(2)this指向不同,普通函数this指向调用该函数的对象,箭头函数没有自己的this,内部this指向声明箭头函数时外部作用域中的this
(3)普通函数的arguments保存实际参数,箭头函数的rest参数保存实际参数