代碼摘錄自https://www.cnblogs.com/fundebug/p/6904753.html
文法
我們先來按正常文法定義函數:
function funcName(params) {
return params + 2;
}
funcName(2);
// 4
該函數使用箭頭函數可以使用僅僅一行代碼搞定!
var funcName = (params) => params + 2
funcName(2);
// 4
是不是很酷!雖然是一個極端簡潔的例子,但是很好的表述了箭頭函數在寫代碼時的優勢。我們來深入了解箭頭函數的文法:
(parameters) => { statements }
如果沒有參數,那麼可以進一步簡化:
() => { statements }
如果隻有一個參數,可以省略括号:
parameters => { statements }
如果傳回值僅僅隻有一個表達式(expression), 還可以省略大括号:
parameters => expression
// 等價于:
function (parameters){
return expression;
}
Arrow(箭頭函數)的this指向問題
普通的this: this總是代表它的直接調用者,沒找到直接調用者,則this指的是
window(匿名函數,定時器中的函數,由于沒有預設的宿主對象,是以預設this指
向window)
箭頭函數的this: 預設指向在定義它時綁定,繼承自父執行上下文,這裡要注意非函數的普通對象是沒有執行上下文的,但是有this和一般的函數不同,箭頭函數不會綁定this。 或則說箭頭函數不會改變this本來的綁定。當定義它的函數中this的指向改變,則他也跟着改變。
var b=11;
var obj={
b:22,
say:()=>{
console.log(this.b);
}
}
obj.say();//輸出的值為11,擷取的不是對象的this而是window的執.上下文this.
我們用一個例子來說明:
function Counter() {
this.num = 0;
}
var a = new Counter();
因為使用了關鍵字new構造,Count()函數中的this綁定到一個新的對象,并且指派給a。通過console.log列印a.num,會輸出0。
console.log(a.num);
// 0
我們來看一下輸出結果:如果我們想每過一秒将a.num的值加1,該如何實作呢?可以使用setInterval()函數。
function Counter() {
this.num = 0;
this.timer = setInterval(function add() {
this.num++;
console.log(this.num);
}, 1000);
}
var b = new Counter();
我們來看一下輸出結果:
// NaN
// NaN
// NaN
// ...
你會發現,每隔一秒都會有一個NaN列印出來,而不是累加的數字。到底哪裡錯了呢?
首先使用如下語句停止setInterval函數的連續執行:
clearInterval(b.timer);
我們來嘗試了解為什麼出錯:根據上一篇部落格講解的規則,首先函數setInterval沒有被某個聲明的對象調用,也沒有使用new關鍵字,再之沒有使用bind, call和apply。setInterval隻是一個普通的函數。實際上setInterval裡面的this綁定到全局對象的。我們可以通過将this列印出來驗證這一點:
function Counter() {
this.num = 0;
this.timer = setInterval(function add() {
console.log(this);
}, 1000);
}
var b = new Counter();
你會發現,整個window對象被列印出來。 使用如下指令停止列印:
clearInterval(b.timer);
回到之前的函數,之是以列印NaN,是因為this.num綁定到window對象的num,而window.num未定義。
那麼,我們如何解決這個問題呢?使用箭頭函數!使用箭頭函數就不會導緻this被綁定到全局對象。
function Counter() {
this.num = 0;
this.timer = setInterval(() => {
this.num++;
console.log(this.num);
}, 1000);
}
var b = new Counter();
// 1
// 2
// 3
// ...
通過Counter構造函數綁定的this将會被保留。在setInterval函數中,this依然指向我們新建立的b對象。
為了驗證剛剛的說法,我們可以将 Counter函數中的this綁定到that, 然後在setInterval中判斷this和that是否相同。
function Counter() {
var that = this;//這裡的this綁定到了b
this.timer = setInterval(() => {
console.log(this === that);//這裡的this如果不用箭頭函數則綁定window
}, 1000);
}
var b = new Counter();
// true
// true
// ...
總結
如果你想在一個新的函數内部用到目前的this,那就用箭頭函數來做。
而如果新的函數裡要用自己的this,那就不要用箭頭函數