淺析js之this --- 一次性搞懂this指向


  ES5函數調用三種形式:

func(p1, p2)
obj.child.method(p1, p2)
func.call(context, p1, p2) // 先不講 apply

  前兩種都是語法糖,可以等價地變為 call 形式:轉換代碼

func(p1, p2) 等價於

func.call(undefined, p1, p2)

 

obj.child.method(p1, p2) 等價於

obj.child.method.call(obj.child, p1, p2)

  

func.call(context, p1, p2)

  this,就是上面代碼中的 context。就這么簡單。

  this 是你 call 一個函數時傳的 context,由於你從來不用 call 形式的函數調用,所以你一直不知道。

  

瀏覽器里有一條規則:

  如果你傳的 context 就 null 或者 undefined,那么 window 對象就是默認的 context(嚴格模式下默認 context 是 undefined)

因此上面的打印結果是 window。

  

[ ] 語法

function fn (){ console.log(this) }

var arr = [fn, fn2]

arr[0]() // 這里面的 this 又是什么呢?

我們可以把 arr[0]( ) 想象為arr.0( ),雖然后者的語法錯了,但是形式與轉換代碼里的 obj.child.method(p1, p2) 對應上了,於是就可以愉快的轉換了:

 arr[0]()

假想為    arr.0()

然后轉換為 arr.0.call(arr)

那么里面的 this 就是 arr 了 :

 

總結

 

  1. this 就是你 call 一個函數時,傳入的 context。

  2. 如果你的函數調用形式不是 call 形式,請按照「轉換代碼」將其轉換為 call 形式。

   

 

  1. 如果一個函數中有this,但是它沒有被上一級的對象所調用,那么this指向的就是window,這里需要說明的是在js的嚴格版中this指向的不是window,非嚴格模式為undefined。

  2. 如果一個函數中有this,這個函數有被上一級的對象所調用,那么this指向的就是上一級的對象。

  3. 如果一個函數中有this,這個函數中包含多個對象,盡管這個函數是被最外層的對象所調用,this指向的也只是它上一級的對象。 

    例:

 

var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();

盡管對象b中沒有屬性a,這個this指向的也是對象b,因為this只會指向它的上一級對象,不管這個對象中有沒有this要的東西。

  4.還有一種比較特殊的情況:這里this指向的是window,this永遠指向的是最后調用它的對象   

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();   //this指向window

  5. 構造函數版this:

function Fn(){
    this.user = "Caraxiong";
}
var a = new Fn();
console.log(a.user); //Caraxiong
 
        

  這里之所以對象a可以點出函數Fn里面的user是因為new關鍵字可以改變this的指向,將這個this指向對象a.調用這個函數Fn的是對象a,那么this指向的自然是對象a,那么為什么對象Fn中會有user,因為你已經復制了一份Fn函數到對象a中,用了new關鍵字就等同於復制了一份。

  6.當this碰到return時

function fn()  
{  
    this.user = 'Caraxiong';  
    return {};   //返回一個對象
}
var a = new fn;  
console.log(a.user); //undefined
function fn()  
{  
    this.user = 'Caraxiong';  
    return function(){};    //返回一個對象
} var a = new fn; console.log(a.user); //undefined
function fn()  
{  
    this.user = 'Caraxiong';  
    return 1;   //非對象
}
var a = new fn;  
console.log(a.user); //Caraxiong

function fn()  
{  
    this.user = 'Caraxiong';  
    return undefined;   //非對象
} 

var a = new fn;
console.log(a.user);
//Caraxiong

如果返回值是一個對象,那么this指向的就是那個返回的對象,

如果返回值不是一個對象那么this還是指向函數的實例。

 

注:還有一點就是雖然null也是對象,但是在這里this還是指向那個函數的實例,因為null比較特殊。

function fn()  
{  
    this.user = 'Caraxiong';  
    return null;
}
var a = new fn;  
console.log(a.user); //Caraxiong

  7. ES6中的this指向

  1.  函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
  2. 不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。
  3. 不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用Rest參數代替。
  4. 不可以使用yield命令,因此箭頭函數不能用作Generator函數。
  5. function Timer() {
      this.a1 = 0; this.a2 = 0; // 箭頭函數 setInterval(() => this.a1++, 1000); // 普通函數 setInterval(function () { this.a2++; }, 1000); } var timer = new Timer(); setTimeout(() => console.log('a1: ', timer.a1), 3100); setTimeout(() => console.log('a2: ', timer.a2), 3100); // a1: 3 // a2: 0

    上面代碼中,Timer函數內部設置了兩個定時器,分別使用了箭頭函數和普通函數。前者的this綁定定義時所在的作用域(即Timer函數),后者的this指向運行時所在的作用域(即全局對象)。

  6. this指向的固定化,並不是因為箭頭函數內部有綁定this的機制,實際原因是箭頭函數根本沒有自己的this,導致內部的this就是外層代碼塊的this。正是因為它沒有this,所以也就不能用作構造函數。
  7. 另外,由於箭頭函數沒有自己的this,所以當然也就不能用call()apply()bind()這些方法去改變this的指向

注:

  1. new操作符會改變函數this的指向問題,為什么this會指向a?
    1. 首先new關鍵字會創建一個空的對象,然后會自動調用一個函數apply方法,將this指向這個空對象,這樣的話函數內部的this就會被這個空的對象替代。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM