什么是ES6箭头功能,它们如何工作? [英] What are ES6 arrow functions, how do they work?

查看:154
本文介绍了什么是ES6箭头功能,它们如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很好奇ES6箭头功能(胖箭头功能)。他们只是从CoffeeScript得到的语法糖,还是有更多的满足眼睛?

解决方案

ES6箭头功能深入



ES6最漂亮的功能之一就是轻松赢得比赛,如果这样的比赛将会举行。许多人不知道的是,箭头功能不仅仅是一种形式的语法糖,我们可以使用而不是常规回调。
我喜欢向参加我的培训/研讨会的人员解释,箭头功能是这个无论如何,参数 -less, new.target -less和 super
让我们现在可以通过较短的语法,深入了解箭头功能的具体细节。



词汇绑定这个



以前,如果将这些值设置为全局对象(如果它们被用作回调),那么常规函数将被赋值给新对象,以防它们被调用使用新的运算符,或者在jQuery的库的情况下,它们将被设置为在事件处理程序的情况下触发事件的对象,或者在 $。each iteration.This情况证明,即使对于有经验的开发人员来说也是很混乱的。
假设你有一段代码如下所示。

  var obj = {
nameValue :'default',
initializeHandlers:function(){
var nameInput = document.querySelector('#name');

nameInput.addEventListener('blur',function(event){
this.nameValue = event.target.value;
});
}
};

obj.initializeHandlers();

问题是这个 code> blur 事件处理程序设置为全局对象而不是obj。在严格的模式— 'use strict'; —您有可能冒犯您的申请,因为这个设置为 undefined 。为了分步这个问题,我们有两个选择:




  • 将事件处理程序转换为绑定到外层作用域的函数, a href =https://developer.mozilla.org/en-US/docs/Web =nofollow> Function.prototype.bind

  • initializeHandlers 函数中使用脏的 var self = this; (我认为这是一个黑客)



这两个选项如下所示。

  [...] 
initializeHandlers:function(){
var nameInput = document.querySelector('#name');
//更优雅,但我们可以做得更好
var blurHandler = function(event){
this.nameValue = event.target.value;
} .bind(this)

nameInput.addEventListener('blur',blurHandler);
}
[...]

[...]
initializeHandlers:function(){
var nameInput = document.querySelector('#名称');
// ugly and error-prone
var self = this;

nameInput.addEventListener('blur',function(event){
self.nameValue = event.target.value;
});
}
[...]

另一方面,箭头功能没有内部上下文。他们从外部范围继承他们的上下文。让我们来看看如何使用箭头来解决这个问题。

  const obj = {
nameValue:'default'
initializeHandlers:function(){
const nameInput = document.querySelector('#name');

nameInput.addEventListener('blur',(event)=> {
//这引用obj而不是全局对象
this.nameValue = event.target.value ;
});
}
};

在我们的新实现中这个引用 obj 对象,并且由于嵌套而不会丢失。



词法参数



有没有试过访问一个箭头函数中的参数对象?我有,我浪费了3个固定的时间,试图弄清楚为什么我得到外部函数的参数,而不是箭头函数的参数。
幸运的是,MDN存在,按照良好的做法,您最终检查文档,当您坐在角落时,膝盖卷入胸部,摇摆并重复自己:我应该是木匠!
有趣的是,箭头函数不会公开一个参数对象。如果您尝试访问它,您将获得周围功能的参数。在我们的例子中,由于外部函数也是一个箭头函数,我们在链中没有更多的功能,我们将得到一个 ReferenceError 。 p>

  const variadicAdder =(x)=> {

return()=> {
let args = Array.prototype.slice.call(arguments,0);
return args.reduce((cumulative,current)=> {
return cumulative + current;
},x);
}
}

const variadicAdderOf5 = variadicAdder(5);

console.log(variadicAdderOf5(10,11,12));
// ReferenceError:参数未定义

这里没有修复,因为有没什么破我们可以做的是从我们的 variadicAdder()返回一个简单的函数,而不是一个箭头。
这将使我们有机会访问参数对象而没有问题。更新的代码将如下所示,唯一的区别是
,它实际上可以工作,而不会抛出错误。

  const variadicAdder =(x)=> {

return function(){
let args = Array.prototype.slice.call(arguments,0);
return args.reduce((cumulative,current)=> {
return cumulative + current;
},x);
}
}

const variadicAdderOf5 = variadicAdder(5);

console.log(variadicAdderOf5(10,11,12));
// 38

了解更多关于 Array.prototype导致 Mozilla开发人员网络。



其他特征



正如我在介绍部分这篇文章,除了上下文和参数之外,箭头函数还有几个特点。
我想提到的第一件事是你不能使用带有箭头功能的新的运算符。作为一个直接的含义,箭头函数也没有 super()。如下面的代码段将简单地抛出一个 TypeError

  const Person =(name)=> {
this.name = name;
};

let p = new Person('John');
// TypeError:Person不是构造函数

第三个特征, ,无法使用运算符的直接含义就是箭头函数没有 new.target 。简而言之, new.target 允许您检测是否已将函数调用为构造函数。
箭头函数,从其周围的范围继承 new.target 。如果外部范围是一个函数,并且它像一个构造函数(例如 new Person('Adrian'); )被调用,那么 new.target 将指向外部函数。
Mozilla开发人员网络提供了有关 new.target 的详细说明,我鼓励您查看。



这篇文章也发表在我的博客上: / es6-arrow-functions -in-depth /


I am curious about ES6 arrow functions (fat arrow functions). Are they simply syntactic sugar derived from CoffeeScript, or is there more to them than meets the eye?

解决方案

ES6 Arrow functions in depth

One of the prettiest features of ES6, it could easily win a beauty contest, if such a contest would be held. What many people don’t know is that the arrow function is not simply a form of syntactic sugar that we can use instead of the regular callback. As I like to explain it to the people who attend my trainings/workshops, arrow functions are this-less, arguments-less, new.target-less and super-less. Let us now get past the shorter syntax and dive deeper into the specifics of the arrow function.

Lexical-bound this

Previously, regular functions would have their this value set to the global object if they were used as callbacks, to a new object in case they were called with the new operator or, in the case of libraries like jQuery, they would be set to the object that triggered an event in case of event handlers, or the current element in a $.each iteration.This situation proved very confusing even for experienced developers. Let’s say you have a piece of code like the one below.

var obj = {
  nameValue: 'default',
  initializeHandlers: function() {
    var nameInput = document.querySelector('#name');

    nameInput.addEventListener('blur', function(event) {
      this.nameValue = event.target.value;
    });
  }
};

obj.initializeHandlers();

The problem is that this inside the blur event handler is set to the global object rather than obj. In strict mode — ‘use strict’; — you risk breaking your application because this is set to undefined. In order to side-step this issue we have two options:

  • Convert the event handler to a function bound to the outer scope, using Function.prototype.bind
  • Use the dirty var self = this; expression in the initializeHandlers function (I see this as a hack)

Both options are illustrated below.

[...]
initializeHandlers: function() {
  var nameInput = document.querySelector('#name');
  // more elegant but we can do better
  var blurHandler = function(event) {
    this.nameValue = event.target.value;
  }.bind(this)

  nameInput.addEventListener('blur', blurHandler);
}
[...]

[...]
initializeHandlers: function() {
  var nameInput = document.querySelector('#name');
  // ugly and error-prone
  var self = this;

  nameInput.addEventListener('blur', function(event) {
    self.nameValue = event.target.value;
  });
}
[...]

On the other hand, arrow functions have no internal context. They inherit their context from the outer scope. Let’s take a look at how arrow functions solve this problem.

const obj = {
  nameValue: 'default',
  initializeHandlers: function() {
    const nameInput = document.querySelector('#name');

    nameInput.addEventListener('blur', (event) => {
      // this references obj instead of the global object
      this.nameValue = event.target.value;
    });
  }
};

In our new implementation this is a hard reference to the obj object and doesn’t get lost due to nesting.

Lexical arguments

Have you ever tried to access the arguments object inside an arrow function? I have, and I wasted 3 solid hours trying to figure out why do I get the arguments of the outer function instead of those of the arrow functions. Thankfully, MDN exists, and as good practice dictates, you check the documentation at the end, when you sit in a corner, knees tucked to your chest, rocking and repeating to yourself: "I should have been a carpenter!" Fun aside, arrow functions do not expose an arguments object. If you try to access it, you will get the arguments of the surrounding function. In our case, given the fact that the outer function is an arrow function as well, and we have no more functions further up the chain, we will get a ReferenceError.

const variadicAdder = (x) => {

  return () => {
    let args = Array.prototype.slice.call(arguments, 0);
    return args.reduce((accumulator, current) => {
      return accumulator + current;
    }, x);
  }
}

const variadicAdderOf5 = variadicAdder(5);

console.log(variadicAdderOf5(10, 11, 12));
// ReferenceError: arguments is not defined

There is no fix here, as there is nothing broken. What we can do is to return a plain function, rather than an arrow, from our variadicAdder(). This will give us the opportunity to access the arguments object without an issue. The updated code will look like the one below with the only difference that it will actually work and not throw an error.

const variadicAdder = (x) => {

  return function() {
    let args = Array.prototype.slice.call(arguments, 0);
    return args.reduce((accumulator, current) => {
      return accumulator + current;
    }, x);
  }
}

const variadicAdderOf5 = variadicAdder(5);

console.log(variadicAdderOf5(10, 11, 12));
// 38

To find out more about Array.prototype.reduce, head to the Mozilla Developer Network.

Other characteristics

As I mentioned in the introductory section of this article, arrow functions have several more characteristics besides the context and the arguments. The first thing I would like to mention is that you are unable to use the new operator with arrow functions. As a direct implication, arrow functions also don’t have super(). Snippets like the one below would simply throw a TypeError.

const Person = (name) => {
  this.name = name;
};

let p = new Person('John');
// TypeError: Person is not a constructor

The third characteristic, which is as well, a direct implication of the inability to use the new operator, is the fact that arrow functions don’t have new.target. In a nutshell, new.target allows you to detect whether or not a function has been called as a constructor. Arrow functions, inherit new.target from their surrounding scope. If the outer scope is a function, and it is called like a constructor (e.g. new Person('Adrian');), then new.target will point to the outer function. The Mozilla Developer Network hosts a detailed explanation on new.target and I encourage you to check it out.

This article is also published on my blog, here: /es6-arrow-functions-in-depth/

这篇关于什么是ES6箭头功能,它们如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆