阅读 104

今天聊一聊ES6的箭头函数

这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战

箭头函数

箭头函数表达式的语法比函数表达式更简洁,并且没有自己的thisargumentssupernew.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。

const materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium']
console.log(materials.map((material) => material.length))
// expected output: Array [8, 6, 7, 9]
复制代码

基础语法

(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
//相当于:(param1, param2, …, paramN) =>{ return expression; }

// 当只有一个参数时,圆括号是可选的:
(singleParam) => { statements }
singleParam => { statements }

// 没有参数的函数应该写成一对圆括号。
() => { statements }
复制代码

高级语法

//加括号的函数体返回对象字面量表达式:
params => ({foo: bar})

//支持剩余参数和默认参数
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => {
statements }

//同样支持参数列表解构
let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f();  // 6
复制代码
引入箭头函数主要有两个方面的作用:更简短的函数而且不绑定 this

箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。因此,在下面的代码中,传递给setInterval的函数内的 this 与封闭函数中的this值相同:

function Person() {
  this.age = 0

  setInterval(() => {
    this.age++ // |this| 正确地指向 p 实例
  }, 1000)
}
var p = new Person()
复制代码

通过callapply调用

由于 箭头函数没有自己的 this 指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定 this),他们的第一个参数会被忽略。

var adder = {
  base : 1,

  add : function(a) {
    var f = v => v + this.base;
    return f(a);
  },

  addThruCall: function(a) {
    var f = v => v + this.base;
    var b = {
      base : 2
    };

    return f.call(b, a);
  }
};

console.log(adder.add(1));         // 输出 2
console.log(adder.addThruCall(1)); // 仍然输出 2
复制代码
使用箭头函数作为方法

箭头函数作为方法时,由于没有定义this绑定,方法里指向里上一个作用链的作用域。下面是例子中指向的是全局作用域。

//使用箭头函数作为方法
var obj = {
  a: 1,
  b: () => {
    console.log(this.a, this)
  },
  c: function () {
    console.log(this.a, this)
  },
}
//obj.b() //undefined {}
//上面是在node环境下运行的,在浏览器环境下运行会输出:undefined,window
//obj.c() //1 {a:1.b:[Function:b],c:[Function:c]}
Object.defineProperty(obj, 'b', {
  get: () => {
    console.log(this.a, typeof this.a, this)
    return this.a++
  },
})
//obj.b //undefined 'undefined' {}
//箭头函数不能用作构造器,和new一起用会报错
/*(var Foo = () => {}
var f = new Foo()*/
//箭头函数也没有prototype属性,同样报错
//箭头函数不能用作函数生成器。
复制代码
还有几点注意:
  • 箭头函数返回子面量对象时要加括号(这是因为花括号({} )里面的代码被解析为一系列语句(即 foo 被认为是一个标签,而非对象字面量的组成部分)。)
  • 箭头函数的作用域注意,是局部作用域
// 常规写法
var greeting = () => {
  let now = new Date()
  return 'Good' + (now.getHours() > 17 ? ' evening.' : ' day.')
}
greeting() //"Good day."
console.log(now) // ReferenceError: now is not defined 标准的let作用域

// 参数括号内定义的变量是局部变量(默认参数)
var greeting = (now = new Date()) =>
  'Good' + (now.getHours() > 17 ? ' evening.' : ' day.')
greeting() //"Good day."
console.log(now) // ReferenceError: now is not defined

// 对比:函数体内{}不使用var定义的变量是全局变量
var greeting = () => {
  now = new Date()
  return 'Good' + (now.getHours() > 17 ? ' evening.' : ' day.')
}
greeting() //"Good day."
console.log(now) // Fri Dec 22 2017 10:01:00 GMT+0800 (中国标准时间)

// 对比:函数体内{} 用var定义的变量是局部变量
var greeting = () => {
  var now = new Date()
  return 'Good' + (now.getHours() > 17 ? ' evening.' : ' day.')
}
greeting() //"Good day."
console.log(now) // ReferenceError: now is not defined
复制代码

上面是 MDN 的例子。

  • 同样的箭头函数还可以使用闭包和递归
箭头函数与匿名函数的区别
  • this 指向区别

    • 箭头函数根据所在的环境(我在哪个环境中,this 就指向谁),Arrow functions bind the parent context。按照词法作用域绑定 this
    • 匿名函数中 this 指向 window
使用箭头函数注意几点
  • 1、函数体内的 this 对象就是定义时所在的对象,而不是使用时所在对象;

  • 2、不可以当作构造函数使用,也就是不能用 new 命令实例化一个对象,否则会抛出一个错误;

  • 3、不可以使用 arguments 对象,该对象在函数体内不存在,如果要用的话,可以用 rest 参数代替;

  • 4、不可以使用 yield 命令,箭头函数不能用作 Generator 函数;

文章分类
前端
文章标签