1、普通函數
先說說普通函數中的this,各式各樣的情況下判斷this的指向,可以說是非常刁鉆瞭。判斷的時候,隻要記住【this 永遠指向調用它的對象,new的時候,指向new出來的對象。】這句話就夠瞭。
看幾個例子:
//例1 var obj = { name: 'latency', sayName: function(){ console.log('name:',this.name); } } obj.sayName() //name: latency
例1這個例子很好理解,sayName() 方法是 obj 調用的,所以其中的this指向obj。
//例2 var name = 'cheng'; var obj = { name: 'latency', sayName: function(){ return function(){ console.log('name:',this.name); } } } obj.sayName()() //name: cheng
在例2中,打印出來對的this.name不是obj的name,而是window對象的name屬性。這是因為sayName()函數中有個閉包,閉包中的this指向調用這個閉包的對象,也就是window對象,寫成下面這樣可能更好理解:
var fun = obj.sayName(); fun() //name: cheng fun()方法是window對象調用的,其this指向window對象
接下來看一個復雜一點的例子:
//例3 var fun = function (a){ this.a = a; return function(b){ console.log('a+b:', this.a + b); } }((function(a,b){return a})(1,2)) fun(3) //a+b: 4
在例3中,首先要明確fun是什麼,仔細看代碼第7行,我們發現fun是一個立即執行的函數,它的參數也是一個立即執行的函數。
(function(a,b){return a})(1,2) 執行的結果是1,所以fun實際上是下面這樣var fun = (function(a){……})(1)
在fun定義的時候,就已經開始執行瞭,執行結果如下:
var fun = function (a){ //a = 1 this.a = a; //this.a = 1 return function(b){ console.log('a+b:', this.a + b); } }(1)
當執行到fun(3)的時候,fun中的閉包函數開始執行,傳入參數b=3,由於此時調用閉包函數的是fun,所以閉包中的this指向fun,從而得出 this.a + b 的值為4。
以上是普通函數中的this,下面來看箭頭函數中的this。
2、箭頭函數
對於箭頭函數的this,也隻需要記住一句話【箭頭函數沒有自己的 this,當在內部使用瞭 this時,它會指向最近一層作用域內的 this】
上例子,可以把例2改成箭頭函數,讓它的表現符合我們的預期
//例4 var obj = { name: 'latency', sayName: function(){ return () => { console.log('name:', this.name); } } } obj.sayName()() //name: latency
在例4中,return的是一個箭頭函數,沒有把this綁定到自己的內部,使用this時,指向的是上一層的obj。
//例5 var name = 'cheng'; function delay(){ setTimeout(function(){ console.log('name:', this.name); }, 100) } function arrowDelay(){ setTimeout(() => { console.log('name:', this.name); }, 100) } delay.call({name: 'latency'}) //name: cheng arrowDelay.call({name: 'latency'}) //name: latency
這個例子就可以很清楚的看出箭頭函數和普通函數中this的區別。
根據上面兩個例子,我們可以總結出,在函數中需要使用閉包的時候,用箭頭函數就很方便瞭,不需要像以前一樣使用hack,類似 var context = this;
接下來把例1改成箭頭函數來實現,看看結果:
//例6 var name = 'cheng'; var obj = { name: 'latency', sayName: () => { console.log('name:', this.name) } } obj.sayName() //name: cheng
由於sayName()整個函數就是一個箭頭函數,沒有自己的this,所以this指向的最近一層作用域內的this,也就是window對象。這種情況下,就不適合用箭頭函數來實現瞭。
再看一個例子
//例7 var obj = { name: 'latency', sayName: function(){ return () => { return () => { return () => { console.log("name:", this.name); }; }; }; } } obj.sayName()()()() //name: latency
這個例子可以更好地幫助我們理解【箭頭函數沒有自己的 this,當在內部使用瞭 this時,它會指向最近一層作用域內的 this】這句話。這個例子定義瞭三個箭頭函數,它們都沒有綁定this到自己的內部,或者說沒有改變this的指向,所以this始終指向obj。