Javascript `this`

Javascript 的 `this` 是指什麼?

我們之前談過 scopes 和 closures. this 指的是當下這個 scope 的物件. 在瀏覽器裡最上層 scope 的物件是 window. 在 node.js 裡最上層是 global objects.

Javascript 是一個很自由的語言. 你可以用 functional programming 或者是 object oriented programming 的方式來撰寫. 用 functional programming 寫法通常是變數和 callbacks 傳來傳去, 用 closure 來存資料. this 通常用不太到. 但是 OOP 方式來撰寫的話就是一定要用到 this 了.

因為基本上這是一個 node.js 的教學, 所以我不會題太多 this 在 browser 端該如何運作. 從下面的範例裡我們可以看一下 this 和之前提到的 scope 有什麼關係.

var something, another;

something = {

  x : 'x',

  print : function( callback ){
    callback && callback.call( this );
    console.log( this.x );
  }
};

another = {

  x : 'a',

  set_x : function(){
    this.x = 'b';
  }
};

// situation a
something.print( function(){
  another.set_x();
});

// situation b
something.print( another.set_x );

// situation c
something.print( function(){
  another.set_x.call( this );
});
結果
x
b
b

所以為何在 situation b 可以用 another 來設定 something 裡面的 x 呢? 那是因為我們在 somethingprint method 裡用了 call 並帶入了一個參數 this. 這樣一來 somethingcallback 就是屬於同一個 scope. 在 situation a 我們傳入了一個匿名函式當作 callback 並在這個匿名函式裡面呼叫 another.set_x. 因為一個 function 就會產生一個新的 scope. 所以 callback 裡的 this 指到的不是 another 而是那個匿名函式. 要讓他正常運作的話只要像 situation c 一樣在匿名函式裡再用 call 一次來讓匿名函式和 another 屬於同一個 scope 就可以了.


常見錯誤

有一種常見的錯誤是當我們想在不同 scope 裡使用 this, 而 this 卻指向不是我們要的 object. 所以我們呼叫的函式或是 property 常常會變成 undefined. 這時只要在上層的 scope 裡把 this 指向一個變數, 舉例來說 self. 這樣就可以在不同的 scope 裡來用 self 來代替 this 了.

var example = {

  name : 'who',

  wrong : function(){
    setTimeout( function(){
      console.log( this.name );
    }, 0 );
  },

  right : function(){
    var self = this;

    setTimeout( function(){
      console.log( self.name );
    }, 0 );
  }
};

example.wrong();
example.right();
結果
undefined
who

這篇文章 Javascript call 以及 apply 有比較深入的介紹.


Related posts