创建箭头函数是为了简化函数scope
并this
通过使其更简单来解决关键字。他们使用=>
看起来像箭头的语法。
注意:它不会取代现有的功能。如果你用箭头函数替换每个函数语法,它不会在所有情况下都有效。
让我们看看现有的 ES5 语法。如果this
关键字在对象的方法(属于对象的函数)中,它指的是什么?
var Actor = {
name: 'RajiniKanth',
getName: function() {
console.log(this.name);
}
};
Actor.getName();
上面的代码片段将引用 anobject
并打印出 name "RajiniKanth"
。让我们探索下面的片段,看看这会指出什么。
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
this.movies.forEach(function(movie) {
alert(this.name + " has acted in " + movie);
});
}
};
Actor.showMovies();
现在如果this
关键字在里面method’s function
呢?
在这里 this 将比 指window object
的inner function
是它的脱落scope
。因为this
, 总是引用它所在函数的所有者,在这种情况下 - 因为它现在超出范围 - 窗口/全局对象。
当它在 anobject
的方法中时——function
的所有者是对象。因此this关键字绑定到对象。然而,当它在一个函数内部时,无论是独立的还是在另一个方法中,它都将始终引用该window/global
对象。
var fn = function(){
alert(this);
}
fn(); // [object Window]
我们的 ES5 本身有办法解决这个问题。在深入研究 ES6 箭头函数之前,让我们先研究一下如何解决它。
通常,您会在方法的内部函数之外创建一个变量。现在的‘forEach’
方法获得访问this
,因此object’s
属性和它们的值。
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
var _this = this;
this.movies.forEach(function(movie) {
alert(_this.name + " has acted in " + movie);
});
}
};
Actor.showMovies();
使用bind
附加的this
引用该方法的关键词method’s inner function
。
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
this.movies.forEach(function(movie) {
alert(this.name + " has acted in " + movie);
}.bind(this));
}
};
Actor.showMovies();
现在有了 ES6 箭头函数,我们可以用更简单的方式处理词法范围问题。
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
this.movies.forEach((movie) => {
alert(this.name + " has acted in " + movie);
});
}
};
Actor.showMovies();
箭头的功能更像是函数语句,只是它们结合了这对父母范围。如果箭头函数在顶部作用域中,则this
参数将引用窗口/全局作用域,而常规函数内的箭头函数的 this 参数将与其外部函数相同。
使用箭头函数在创建时this
绑定到封闭范围并且不能更改。new 运算符、bind、call 和 apply 对此没有影响。
var asyncFunction = (param, callback) => {
window.setTimeout(() => {
callback(param);
}, 1);
};
// With a traditional function if we don't control
// the context then can we lose control of `this`.
var o = {
doSomething: function () {
// Here we pass `o` into the async function,
// expecting it back as `param`
asyncFunction(o, function (param) {
// We made a mistake of thinking `this` is
// the instance of `o`.
console.log('param === this?', param === this);
});
}
};
o.doSomething(); // param === this? false
在上面的例子中,我们失去了对 this 的控制。我们可以通过使用this
或的变量引用来解决上面的例子bind
。使用 ES6,管理 将变得更容易,this
因为它与词法作用域的绑定。
var asyncFunction = (param, callback) => {
window.setTimeout(() => {
callback(param);
}, 1);
};
var o = {
doSomething: function () {
// Here we pass `o` into the async function,
// expecting it back as `param`.
//
// Because this arrow function is created within
// the scope of `doSomething` it is bound to this
// lexical scope.
asyncFunction(o, (param) => {
console.log('param === this?', param === this);
});
}
};
o.doSomething(); // param === this? true
何时不使用箭头函数
在对象字面量内。
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
getName: () => {
alert(this.name);
}
};
Actor.getName();
Actor.getName
与箭头函数来定义,但在调用它提示未定义,因为this.name
是undefined
作为上下文仍然window
。
发生这种情况是因为箭头函数在词汇上将上下文与window object
... 即外部作用域绑定在一起。执行this.name
相当于window.name
,这是未定义的。
对象原型
在 上定义方法时,同样的规则适用prototype object
。而不是使用箭头函数来定义 sayCatName 方法,这会带来不正确的context window
:
function Actor(name) {
this.name = name;
}
Actor.prototype.getName = () => {
console.log(this === window); // => true
return this.name;
};
var act = new Actor('RajiniKanth');
act.getName(); // => undefined
调用构造函数
this
在构造调用中是新创建的对象。执行 new Fn() 时, 的上下文constructor Fn
是一个新对象:this instanceof Fn === true
。
this
是从封闭上下文中设置的,即外部作用域,这使得它不会分配给新创建的对象。
var Message = (text) => {
this.text = text;
};
// Throws "TypeError: Message is not a constructor"
var helloMessage = new Message('Hello World!');
具有动态上下文的回调
箭头函数context
在声明时静态绑定,无法使其动态化。将事件侦听器附加到 DOM 元素是客户端编程中的一项常见任务。一个事件以 this 作为目标元素触发处理函数。
var button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log(this === window); // => true
this.innerHTML = 'Clicked button';
});
this
是在全局上下文中定义的箭头函数中的窗口。当点击事件发生时,浏览器尝试调用带有按钮上下文的处理函数,但箭头函数不会改变其预定义的上下文。this.innerHTML
相当于window.innerHTML
并且没有意义。
您必须应用一个函数表达式,它允许根据目标元素进行更改:
var button = document.getElementById('myButton');
button.addEventListener('click', function() {
console.log(this === button); // => true
this.innerHTML = 'Clicked button';
});
当用户点击按钮时,this
处理函数中就是按钮。因此this.innerHTML = 'Clicked button'
正确修改按钮文本以反映单击状态。
参考