- 函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
- 不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。
- 不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用 rest 參數代替。
- 不可以使用yield命令,因此箭頭函數不能用作 Generator 函數。
上面四點中,第一點尤其值得注意。this對象的指向是可變的,但是在箭頭函數中,它是固定的。
var id = 21;
function foo() {
setTimeout(function() {
console.log('id:', this.id);
}, 100);
}
function foo1() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
foo.call({ id: 42 });// 21 普通函數 foo函數中this指向window
foo1.call({id:42});// 42 箭頭函數 foo1函數中this指向{id:42}對象
箭頭函數可以讓setTimeout里面的this,綁定定義時所在的作用域,而不是指向運行時所在的作用域。下面是另一個例子。
function Timer() { // 構造函數不能使用 箭頭函數
this.s1 = 0;
this.s2 = 0;
// 箭頭函數
setInterval(() => this.s1++, 1000);
// 普通函數
setInterval(function () {
this.s2++;
}, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0
上面代碼中,Timer
函數內部設置了兩個定時器,分別使用了箭頭函數和普通函數。前者的this
綁定定義時所在的作用域(即Timer函數),后者的this
指向運行時所在的作用域(此例是window,普通函數中this.s2即為window.s2==undefined)。所以,3100 毫秒之后,timer.s1
被更新了 3 次,而timer.s2
一次都沒更新。
箭頭函數的不適用點:
由於箭頭函數使得this從“動態”變成“靜態”,下面兩個場合不應該使用箭頭函數。
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就會動態指向被點擊的按鈕對象。
另外,如果函數體很復雜,有許多行,或者函數內部有大量的讀寫操作,不單純是為了計算值,這時也不應該使用箭頭函數,而是要使用普通函數,這樣可以提高代碼可讀性。