ES6中新引入了箭头函数,引入箭头函数有两个方面的作用:更简短的函数并且不绑定this。现在分别看下两个作用:
更简短的函数表达:
(参数1, 参数2, …, 参数N) => { 函数声明 }
//相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }
(参数1, 参数2, …, 参数N) => 表达式(单一)
// 当只有一个参数时,圆括号是可选的:
(单一参数) => {函数声明}
单一参数 => {函数声明}
// 没有参数的函数应该写成一对圆括号。
() => {函数声明}
不绑定this
在箭头函数出现之前,每个新定义的函数都有它自己的this:
1.构造函数=> this是新对象的实例/严格模式下为undefined
2.函数作为对象的方法调用=>this指向该对象
3.全局环境下定义的函数=>this指向window
function Person() {
// Person() 构造函数定义 `this`指向它的实例.
this.age = 0;
setInterval(function growUp() {
// 在非严格模式, growUp()函数定义 `this`指向全局对象window,
// 与在 Person()构造函数中定义的 `this`并不相同.
this.age++;
}, 1000);
}
var p = new Person();
现在我们来解决上述this不一致的问题:
方案一
在ECMAScript 3/5中,将this值分配给封闭的变量。
function Person() {
// Person() 构造函数定义 `this`指向它的实例.
var _this=this;
// 将Person的实例this保存到封闭的变量_this中
_this.age=0
setInterval(function growUp() {
_this.age++;
}, 1000);
}
var p = new Person();
方案二
创建[bind绑定函数],以便将预先分配的this
值传递到绑定的目标函数(上述示例中的growUp()
函数)。
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this
。因此,在下面的代码中,传递给setInterval
的函数内的this
与封闭函数中的this
值相同:
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| 正确地指向 p 实例
}, 1000);
}
var p = new Person();
当然,箭头函数也有其不适用的场景:
场景1
第一个场合是定义函数的方法,且该方法内部包括this。
const cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
上面代码中,cat.jumps()方法是一个箭头函数,这是错误的。调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat;如果写成上面那样的箭头函数,使得this指向全局对象,因此不会得到预期结果。
场景2
第二个场合是需要动态this的时候,也不应使用箭头函数。
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。