JavaScript普通函數中的this指向判斷,箭頭函數的this有什麼不同?

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。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *