目录
一、解构
1、数组解构
1.1 完全解构
1.2 不完全解构
1.3 默认值解构
1.4 集合解构(使用扩展运算符)
2、对象解构
2.1 嵌套解构
2.2 默认解构
3、字符串解构
3.1 使用数组进行解构
3.2 使用扩展运算符解构
3.3 使用对象进行解构
4、数值解构
5、布尔值解构
6、函数参数解构
函数的length属性
二、扩展运算符
三、箭头函数
1、箭头函数中this的指向
2、箭头函数的rest参数
3、普通函数和箭头函数的区别
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构,解构的本质属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。如果解构不成功,变量的值就等于undefined。
数组解构就是将等号左边的变量放到中括号内部,匹配右侧数组中的元素。
要注意模式匹配,即等号右边为数组,那么左边也应该用数组接收。
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
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
给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是因为函数没有写返回值)
扩展运算符[...]会把余下的值全部匹配到
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
对象解构就是将等号左边的变量放到大括号内部,匹配右侧对象中的元素。对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
同样的也要注意模式匹配,即等号右边为对象,那么左边也应该用对象接收。
变量与属性同名:
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
比如我们有如下嵌套结构,我们如何解构,使得变量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
当匹配值严格等于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。
let [a,b,c,d,e]='hello'
console.log(a,b,c,d,e); //h e l l o
let [...arr] = 'world'
console.log(arr); //[ 'w', 'o', 'r', 'l', 'd' ]
let {toString,valueOf,length} = 'hello'
console.log(toString,valueOf,length); //[Function: toString] [Function: valueOf] 5
相当于把'hello'当成String基本包装器类型。
let {toString,valueOf}=10;
console.log(toString,valueOf) //[Function: toString] [Function: valueOf]
let {toString,valueOf}=true;
console.log(toString,valueOf); //[Function: toString] [Function: valueOf]
// 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])
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 我是箭头函数
箭头函数没有自己的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
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)
(1)表现形式不同
(2)this指向不同,普通函数this指向调用该函数的对象,箭头函数没有自己的this,内部this指向声明箭头函数时外部作用域中的this
(3)普通函数的arguments保存实际参数,箭头函数的rest参数保存实际参数