'箭头函数'和'函数'是可以等价交换的吗?

javascript ecmascript-6 arrow-functions


ES2015中的箭头函数提供了更简洁的语法。

  • 我现在可以用箭头函数代替所有的函数声明表达式了吗?
  • 我需要注意什么?

Examples:

构造函数

function User(name) {
  this.name = name;
}

// vs

const User = name => {
  this.name = name;
};

原型方法

User.prototype.getName = function() {
  return this.name;
};

// vs

User.prototype.getName = () => this.name;

对象(字面)方法

const obj = {
  getName: function() {
    // ...
  }
};

// vs

const obj = {
  getName: () => {
    // ...
  }
};

Callbacks

setTimeout(function() {
  // ...
}, 500);

// vs

setTimeout(() => {
  // ...
}, 500);

变式函数

function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// vs
const sum = (...args) => {
  // ...
};



Answer 1 Felix Kling


tl;dr:No! Arrow functions and function declarations / expressions are not equivalent and cannot be replaced blindly.
If the function you want to replace does not use this , arguments and is not called with new , then yes.


As so often: it depends. Arrow functions have different behavior than function declarations / expressions, so let's have a look at the differences first:

1. Lexical this and arguments

Arrow functions don't have their own this or arguments binding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, this and arguments refer to the values of this and arguments in the environment the arrow function is defined in (i.e. "outside" the arrow function):

// Example using a function expression
function createObject() {
  console.log('Inside `createObject`:', this.foo);
  return {
    foo: 42,
    bar: function() {
      console.log('Inside `bar`:', this.foo);
    },
  };
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject

// Example using a arrow function
function createObject() {
  console.log('Inside `createObject`:', this.foo);
  return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
  };
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject

In the function expression case, this refers to the object that was created inside the createObject . In the arrow function case, this refers to this of createObject itself.

This makes arrow functions useful if you need to access the this of the current environment:

// currently common pattern
var that = this;
getData(function(data) {
  that.data = data;
});

// better alternative with arrow functions
getData(data => {
  this.data = data;
});

Note that this also means that is not possible to set an arrow function's this with .bind or .call .

If you are not very familiar with this , consider reading

2. Arrow functions cannot be called with new

ES2015 distinguishes between functions that are callable and functions that are constructable. If a function is constructable, it can be called with new , i.e. new User() . If a function is callable, it can be called without new (i.e. normal function call).

通过函数声明表达式创建的函数是可构造和可调用的。
Arrow functions (and methods) are only callable. class constructors are only constructable.

如果你试图调用一个不可调用的函数或构造一个不可构造的函数,你会得到一个运行时错误。


知道了这一点,我们可以说明如下:

Replaceable:

  • Functions that don't use this or arguments .
  • Functions that are used with .bind(this)

Not replaceable:

  • 构造函数
  • Function / methods added to a prototype (because they usually use this )
  • Variadic functions (if they use arguments (see below))

让我们用你的例子来仔细看一下。

Constructor function

This won't work because arrow functions cannot be called with new . Keep using a function declaration / expression or use class .

Prototype methods

Most likely not, because prototype methods usually use this to access the instance. If they don't use this , then you can replace it. However, if you primarily care for concise syntax, use class with its concise method syntax:

class User {
  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }
}

Object methods

Similarly for methods in an object literal. If the method wants to reference the object itself via this , keep using function expressions, or use the new method syntax:

const obj = {
  getName() {
    // ...
  },
};

Callbacks

It depends. You should definitely replace it if you are aliasing the outer this or are using .bind(this) :

// old
setTimeout(function() {
  // ...
}.bind(this), 500);

// new
setTimeout(() => {
  // ...
}, 500);

But: If the code which calls the callback explicitly sets this to a specific value, as is often the case with event handlers, especially with jQuery, and the callback uses this (or arguments ), you cannot use an arrow function!

Variadic functions

Since arrow functions don't have their own arguments , you cannot simply replace them with an arrow function. However, ES2015 introduces an alternative to using arguments : the rest parameter.

// old
function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// new
const sum = (...args) => {
  // ...
};

相关的问题。

进一步的资源:




Answer 2 Ashutosh


Arrow functions => best ES6 feature so far. They are a tremendously powerful addition to ES6, that I use constantly.

Wait, you can't use arrow function everywhere in your code, its not going to work in all cases like this where arrow functions are not usable. Without a doubt, the arrow function is a great addition it brings code simplicity.

But you can’t use an arrow function when a dynamic context is required: defining methods, create objects with constructors, get the target from this when handling events.

不应使用箭头函数,因为:

  1. They do not have this

    It uses “lexical scoping” to figure out what the value of “ this ” should be. In simple word lexical scoping it uses “ this ” from the inside the function’s body.

  2. They do not have arguments

    Arrow functions don’t have an arguments object. But the same functionality can be achieved using rest parameters.

    let sum = (...args) => args.reduce((x, y) => x + y, 0) sum(3, 3, 1) // output - 7 `

  3. They cannot be used with new

    箭头函数不能成为 construtors,因为它们没有原型属性。

什么时候使用箭头功能,什么时候不用。

  1. 不要使用添加函数作为对象字面上的属性,因为我们不能访问这个。
  2. Function expressions are best for object methods. Arrow functions are best for callbacks or methods like map , reduce , or forEach .
  3. Use function declarations for functions you’d call by name (because they’re hoisted).
  4. 使用箭头函数进行回调(因为它们往往会比较麻烦)。