我很好奇ES6箭头功能(胖箭头功能)。它们只是源自CoffeeScript的语法糖,还是对它们有更多的东西而不是眼睛?
答案 0 :(得分:2)
ES6最漂亮的功能之一,如果举办这样的比赛,它很容易赢得选美比赛。许多人不知道的是,箭头函数不仅仅是我们可以使用的一种语法糖,而不是常规的回调。
我想向参加我的培训/研讨会的人员解释一下,箭头函数是this
- 少,arguments
- 少,new.target
- 少和super
- 少。
现在让我们通过更短的语法,深入了解箭头函数的细节。
以前,常规函数将this
值设置为全局对象(如果它们用作回调),设置为新对象,以防它们使用new
运算符调用,或者在此情况下像jQuery这样的库,它们将被设置为在事件处理程序的情况下触发事件的对象,或者$.each
迭代中的当前元素。即使对于有经验的开发人员来说,这种情况也很困惑。
假设您有一段代码如下所示。
var obj = {
nameValue: 'default',
initializeHandlers: function() {
var nameInput = document.querySelector('#name');
nameInput.addEventListener('blur', function(event) {
this.nameValue = event.target.value;
});
}
};
obj.initializeHandlers();
问题是this
事件处理程序中的blur
设置为全局对象而不是obj。在严格模式下‘use strict’;
- 您可能会因为this
设置为undefined
而违反申请。为了解决这个问题,我们有两个选择:
Function.prototype.bind
var self = this;
函数中使用脏initializeHandlers
表达式(我将其视为黑客)这两个选项如下所示。
[...]
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;
});
}
[...]
另一方面,箭头函数没有内部上下文。它们从外部范围继承其上下文。我们来看看箭头函数如何解决这个问题。
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;
});
}
};
在我们的新实现中,this
是对obj
对象的硬引用,不会因嵌套而丢失。
您是否尝试过访问箭头功能中的arguments
对象?我有,而且我浪费了3个小时试图弄清楚为什么我得到外部函数的参数而不是箭头函数的参数。
值得庆幸的是,MDN存在,并且作为良好的实践要求,你最后检查文档,当你坐在角落里,膝盖塞到你的胸口,摇摆并重复自己:“我应该是一个木匠!”
除此之外,箭头函数不会公开arguments
对象。如果您尝试访问它,您将获得周围函数的参数。在我们的例子中,鉴于外部函数也是一个箭头函数,并且我们在链中没有更多函数,我们将获得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
这里没有修复,因为没有任何破坏。我们可以做的是从variadicAdder()
返回一个普通函数,而不是箭头。
这将使我们有机会无问题地访问arguments
对象。更新的代码将如下所示,唯一的区别
它实际上会工作而不会抛出错误。
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
要了解有关Array.prototype.reduce
的更多信息,请转到Mozilla Developer Network。
正如我在本文的介绍部分中提到的,除了上下文和参数之外,箭头函数还有其他几个特性。
我想提到的第一件事是你无法使用new
运算符和箭头函数。直接暗示,箭头函数也没有super()
。像下面这样的片段只会抛出一个TypeError
。
const Person = (name) => {
this.name = name;
};
let p = new Person('John');
// TypeError: Person is not a constructor
第三个特征也是无法使用new
运算符的直接含义,即箭头函数没有new.target
这一事实。简而言之,new.target
允许您检测函数是否已被调用为构造函数。
箭头函数从其周围范围继承new.target
。如果外部作用域是一个函数,并且它被称为构造函数(例如new Person('Adrian');
),那么new.target
将指向外部函数。
Mozilla开发者网络提供了new.target
的详细说明,我建议您查看。
此文章也发布在我的博客上:/es6-arrow-functions-in-depth/