天天看點

JavaScript箭頭函數

代碼摘錄自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,那就不要用箭頭函數