Javascript “箭头函数”和“函数”等价/可交换吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34361379/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:13:04  来源:igfitidea点击:

Are 'Arrow Functions' and 'Functions' equivalent / exchangeable?

javascriptecmascript-6arrow-functions

提问by Felix Kling

Arrow functions in ES2015 provide a more concise syntax.

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

  • Can I replace all my function declarations / expressions with arrow functions now?
  • What do I have to look out for?
  • 我现在可以用箭头函数替换我所有的函数声明/表达式吗?
  • 我需要注意什么?

Examples:

例子:

Constructor function

构造函数

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

// vs

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

Prototype methods

原型方法

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

// vs

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

Object (literal) methods

对象(文字)方法

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

// vs

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

Callbacks

回调

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

// vs

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

Variadic functions

可变函数

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

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

回答by 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 notuse this, argumentsand is not called with new, then yes.

tl;博士:不!箭头函数和函数声明/表达式不是等价的,不能盲目替换。
如果您要替换的函数使用thisarguments并且使用调用new,则是。



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 thisand arguments

1. 词法thisarguments

Arrow functions don't have their own thisor argumentsbinding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, thisand argumentsrefer to the values of thisand argumentsin the environment the arrow function is definedin (i.e. "outside" the arrow function):

箭头函数没有自己的thisarguments绑定的。相反,这些标识符像任何其他变量一样在词法范围内解析。这意味着,一个箭头函数内部,this并且arguments指的值thisarguments在箭头功能环境定义中(即,“外”的箭头功能):

// 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, thisrefers to the object that was created inside the createObject. In the arrow function case, thisrefers to thisof createObjectitself.

在函数表达式的情况下,this指的是在createObject. 在箭头函数的情况下,this指的thiscreateObject自身。

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

如果您需要访问this当前环境,这使得箭头函数很有用:

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

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

Notethat this also means that is notpossible to set an arrow function's thiswith .bindor .call.

请注意,这也意味着无法this使用.bind或设置箭头函数.call

If you are not very familiar with this, consider reading

如果你不是很熟悉this,可以考虑阅读

2. Arrow functions cannot be called with new

2. 不能调用箭头函数 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).

ES2015 区分了可调用函数和可构造函数。如果函数是可构造的,则可以使用 调用它 new,即new User()。如果一个函数是可调用的,它就可以在没有调用的情况下被调用new(即正常的函数调用)。

Functions created through function declarations / expressions are both constructable and callable.
Arrow functions (and methods) are only callable. classconstructors are only constructable.

通过函数声明/表达式创建的函数既可构造又可调用。
箭头函数(和方法)只能调用。 class构造函数只能构造。

If you are trying to call a non-callable function or to construct a non-constructable function, you will get a runtime error.

如果您尝试调用不可调用的函数或构造不可构造的函数,则会出现运行时错误。



Knowing this, we can state the following.

知道了这一点,我们可以陈述以下内容。

Replaceable:

可更换:

  • Functions that don't use thisor arguments.
  • Functions that are used with .bind(this)
  • 不使用thisor 的函数arguments
  • 使用的函数 .bind(this)

Notreplaceable:

不可更换:

  • Constructor functions
  • Function / methods added to a prototype (because they usually use this)
  • Variadic functions (if they use arguments(see below))
  • 构造函数
  • 添加到原型的函数/方法(因为它们通常使用this
  • 可变参数函数(如果它们使用arguments(见下文))


Lets have a closer look at this using your examples:

让我们用你的例子仔细看看这个:

Constructor function

构造函数

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

这是行不通的,因为箭头函数不能用new. 继续使用函数声明/表达式或使用class.

Prototype methods

原型方法

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

很可能不是,因为原型方法通常用于this访问实例。如果他们不使用this,那么您可以更换它。但是,如果您主要关心简洁的语法,请使用class其简洁的方法语法:

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:

对于对象字面量中的方法也是如此。如果该方法想通过 引用对象本身this,请继续使用函数表达式,或使用新的方法语法:

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

Callbacks

回调

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

这取决于。如果您在外部this使用别名或正在使用,则绝对应该替换它.bind(this)

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

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

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

但是:如果调用回调的代码显式设置this为特定值(事件处理程序经常出现这种情况,尤其是使用 jQuery),并且回调使用this(或arguments),则不能使用箭头函数!

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.

由于箭头函数没有自己的arguments,您不能简单地用箭头函数替换它们。但是,ES2015 引入了使用的替代方法argumentsrest 参数

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

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


Related question:

相关问题:

Further resources:

更多资源:

回答by Ashutosh

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

箭头函数 => 迄今为止最好的 ES6 特性。它们是 ES6 的一个非常强大的补充,我经常使用。

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

等等,你不能在你的代码中到处使用箭头函数,它不会在所有情况下都起作用,比如this箭头函数不可用的地方。毫无疑问,箭头函数是一个很好的补充,它带来了代码的简单性。

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.

但是当需要动态上下文时不能使用箭头函数:定义方法,使用构造函数创建对象,在处理事件时从中获取目标。

Arrow functions should NOT be used because:

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

  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 argumentsobject. 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 withnew

    Arrow functions can't be construtors because they do not have a prototype property.

  1. 他们没有 this

    它使用“词法范围”来确定“ ”的值this应该是什么。在简单的词法作用域中,它使用this函数体内的“ ”。

  2. 他们没有 arguments

    箭头函数没有arguments对象。但是使用其余参数可以实现相同的功能。

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

  3. 它们不能与new

    箭头函数不能是构造函数,因为它们没有原型属性。

When to use arrow function and when not:

何时使用箭头函数,何时不使用:

  1. Don't use to add function as a property in object literal because we can not access this.
  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. Use arrow functions for callbacks (because they tend to be terser).
  1. 不要使用将函数作为属性添加到对象字面量中,因为我们无法访问它。
  2. 函数表达式最适合对象方法。箭头函数最适合回调或方法,如mapreduce、 或forEach
  3. 对按名称调用的函数使用函数声明(因为它们被提升)。
  4. 对回调使用箭头函数(因为它们往往更简洁)。

回答by toddmo

To use arrow functions with function.prototype.call, I made a helper function on the object prototype:

为了使用箭头函数function.prototype.call,我在对象原型上创建了一个辅助函数:

  // Using
  // @func = function() {use this here} or This => {use This here}
  using(func) {
    return func.call(this, this);
  }

usage

用法

  var obj = {f:3, a:2}
  .using(This => This.f + This.a) // 5

Edit

编辑

You don't NEED a helper. You could do:

你不需要帮手。你可以这样做:

var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5