Skip to content

箭头函数

ECMAScript 6 标准新增了一种新的函数:Arrow Function(箭头函数)

js
let func = x => x

// 相当于
let func = function(x) {
  return x
}

// babel中编译
var func = function func(x) {
  return x
}

特点

  1. 箭头函数相当于匿名函数,并且简化了函数定义,并且没有自己的 this、arguments、super 或者 new.target

我们通过 babel 去观看箭头函数的转换

js
// ES6
;() => {
  console.log(this.a)
  console.log(arguments)
}

;(...ret) => {
  console.log(ret)
}

c => c

var Foo = () => {}
var foo = new Foo() // TypeError: Foo is not a constructor

// 装换后的
;("use strict")

var _arguments = arguments,
  _this = void 0

;(function() {
  console.log(_this.a)
  console.log(_arguments)
})

;(function() {
  for (var _len = arguments.length, ret = new Array(_len), _key = 0; _key < _len; _key++) {
    ret[_key] = arguments[_key]
  }

  console.log(ret)
})

;(function(c) {
  return c
})
var Foo = function Foo() {}
var foo = new Foo() // 这个时候是可以的

我们通过上面 babel 的转换可以看出

  1. 为什么没有自己的 this

通过将箭头函数中 this 全都修改成外部作用域中的 _this ,所以就没有自己的 this 而是指向外部作用域

js
window.name = "windowName"

let name = "globalName"

let obj = {
  name: "app",
  jumps: () => {
    console.log(this.name)
  },
  junpsFun() {
    console.log(this.name)
  },
}

//
obj.jumps() // windowName
obj.junpsFun() // app
  1. arguments 跟 this 一样
js
var _arguments = arguments,
  _this = void 0

;(function() {
  console.log(_this.a)
  console.log(_arguments)
})
  1. 不能通过 new 关键字调用

 new 关键字调用

但是通过 babel 转换的

js
// ES6
var Foo = () => {}
var foo = new Foo() // TypeError: Foo is not a constructor

// 装换后的
var Foo = function Foo() {}
var foo = new Foo() // 这个时候是可以的

其实还是可以使用 new 去实例化一个实例的,所以有些时候 Babel 与真正的是不一样的

  1. 箭头函数不能访问 arguments 对象,那么我们可以通过...rest 来存储所有参数,并获取
js
const getArgs = () => arguments
getArgs("1", "2", "3") // ReferenceError: arguments is not defined

const getArgs2 = (...rest) => rest
getArgs("1", "2", "3") // ["1", "2", "3"]

真正的箭头函数

  • 没有 this

箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值。

  • 没有 arguments

箭头函数没有自己的 arguments 对象,这不一定是件坏事,因为箭头函数可以访问外围函数的 arguments 对象

如果访问自己的 arguments 通过命名参数或者 rest 参数的形式访问参数:

js
let nums = (...nums) => nums
  • 不能通过 new 关键字调用

JavaScript 函数有两个内部方法:[[Call]] 和 [[Construct]]。

当通过 new 调用函数时,执行 [[Construct]] 方法,创建一个实例对象,然后再执行函数体,将 this 绑定到实例上。

当直接调用的时候,执行 [[Call]] 方法,直接执行函数体。

箭头函数并没有 [[Construct]] 方法,不能被用作构造函数,如果通过 new 的方式调用,会报错。

  • 没有 new.target

因为不能使用 new 调用,所以也没有 new.target 值。

  • 没有原型

由于不能使用 new 调用箭头函数,所以也没有构建原型的需求,于是箭头函数也不存在 prototype 这个属性。

  • 没有 super

连原型都没有,自然也不能通过 super 来访问原型的属性,所以箭头函数也是没有 super 的,不过跟 this、arguments、new.target 一样,这些值由外围最近一层非箭头函数决定。

小知识

当箭头函数箭头后面是简单操作时,直接去掉“{ }”,这样可以不使用 return 就能会返回值

js
// 箭头函数常规写法
console.log(
  Array.from([1, 2, 3], x => {
    return x + x
  })
) // expected output: Array [2, 4, 6]

// 箭头函数简单操作
console.log(Array.from([1, 2, 3], x => x + x)) // expected output: Array [2, 4, 6]

不适用箭头函数的地方

有哪些时候我们不适用箭头函数

  1. 对象的方法

  2. 原型上的方法

  3. 事件回调

  4. 需要访问构造函数(new)