目录
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参数保存实际参数