2013-01-10 65 views
2

基本上,我使用一個稱爲Joose的元類框架,它允許我使用更優雅的類語法 - 但我不知道如何去引用範圍對象來自類聲明的更深層次的方法。我也用require.js爲dependemcy管理...Javascript範圍引用外部對象

下面是一個例子類定義:

define([ 
     'jquery', 
     'handlebars', 
    ], function($, Handlebars){ 

     var MyClass = Class("MyClass", { 

     //inheritance   
     isa: SuperClass, 

     //instance vars 
     has: { 

      hello:{ 
       is: 'r', 
       init: 'Hi There!', 
      }, 

      someVarToBeSetUsingAjax:{ 
       is: 'rw', 
       init: false, 
      }, 
     }, 

     //methods 
     methods: { 

      init: function() { 

       var self = this; 
       self.getAjaxVar(); 

      }, 

      getAjaxVar: function() { 

       var self = this; 

       //HOW CAN I REFERENCE 'self' THROUGHOUT MY OBJECT? 

       $.get('ajax/test.html', function(response) { 
       self.someVarToBeSetUsingAjax = response.value; 
       }); 
      }, 

      //lots more methods... 

     } 
    }); 

    return MyClass; 

}); 

好了,我的問題是 - 在AJAX功能我必須寫變種自我=這讓我的對象進入AJAX調用的範圍 - 沒有問題。但是,我發現自己正在爲我的課程聲明中的幾乎每一種方法都這樣做!我如何以一種乾淨而有效的方式在所有方法中引用自我?我知道你可以通過設置一個參數來在AJAX中使用範圍,假設它不僅僅是AJAX,還有其他一些將範圍關閉到外部的函數。

謝謝。

回答

1

每次嵌套函數時,都必須考慮this。但是如果你不嵌套一個函數,或者這個函數不使用this你不需要考慮它。

 init: function() { 
      var self = this; 
      self.getAjaxVar(); 
     }, 

所以在這種情況下沒有必要。這是完全一樣的:

 init: function() { 
      this.getAjaxVar(); 
     }, 

但在這裏:

 getAjaxVar: function() { 
      var self = this; 

      $.get('ajax/test.html', function(response) { 
      self.someVarToBeSetUsingAjax = response.value; 
      }); 
     }, 

您創建一個內部函數,並且要的this原始值的參考,所以你必須別名thisself使其可訪問。

沒有辦法將this修復爲您班上各處的值。


這就是說,你確實有一些選擇。

Function.prototype.bind()可以提供幫助。

var func = function() { return this.name }; 
var obj = { name: 'Bob' }; 
var boundFunc = func.bind(obj); 
boundFunc(); // 'Bob' 

bind將返回一個新的功能與this總是被設置爲一個特定的對象。

所以:

 getAjaxVar: function() { 
      $.get('ajax/test.html', function(response) { 
      this.someVarToBeSetUsingAjax = response.value; 
      }.bind(this)); 
     }, 

注意這不是在所有的瀏覽器都支持,您可能需要爲舊的墊片。或者只是習慣self = this


我想給咖啡腳本一個小點頭,因爲它支持函數的聲明,在運行時不會改變上下文。

obj = { 
    name: "bob" 
    sayHello: -> 
    doSomeAjax({ 
     success: => 
     alert "successfully made " + this.name + " say hello!" 
    }) 
} 

obj.sayHello() 

->使功能正常。但胖箭頭=>將在函數內部和外部保留this的值。實例方法中的回調非常方便。當編譯爲JS時,它基本上爲你做了一個self = this別名,在內部函數中每次使用self來引用this。這很漂亮。

儘管在普通的JS中,最常見的模式是簡單的self = this,堅持下去。

+0

是的,我知道第一點,我只是想說明。感謝您的幫助,但我想我只需要習慣它! –

+0

標記爲正確,因爲它是最徹底的 –

1

答案是使用this。你只需要創建一個閉包(當你有一個函數將被稱爲外部對象的時候,你可以使用這個閉包(當你在這裏從ajax調用返回時)。

沒有其他的。方法來創建一個封閉


要清楚(因爲有些人會在任何輕微的技術揮手跳),你不「需要」來創建一個封閉但我認爲你應該 - JavaScript是設計用於閉包工作,它們工作良好,並且其他JavaScript程序員也很好理解它們。

+0

@Bergi - 因此沒有其他的方法來做閉包(你的第一個評論)。 – Hogan

+0

糟糕,我必須誤讀爲「*沒有其他方式[達到此目的] *比*創建封閉。*」 – Bergi

+0

@Bergi - NP,因爲您可以看到您的評論促使我創建第二個這是對我最初的答案的巨大改進。 :) – Hogan

0

我發現自己正在爲我的課程聲明中的幾乎每一種方法都這樣做!我如何以一種乾淨而有效的方式在所有方法中引用自我?

你不行。只有在調用該方法時才知道self的值(this引用的實例)。

如果你在構造函數中聲明瞭這個變量(你的init方法?)並且在那裏創建了所有的回調函數,那麼你只能解決這個問題並使用一個通用的self變量。也許不是最內存高效的方法,但:

return Class("MyClass", { 
    // … 

    methods: { 
     init: function() { 
      var self = this; 
      this.ajaxVarCallback = function(response) { 
       self.someVarToBeSetUsingAjax = response.value; 
      }; 
      // and other functions that use "self" 

      this.getAjaxVar(); 
     }, 
     getAjaxVar: function() { 
      $.get('ajax/test.html', this.ajaxVarCallback); 
     }, 
     // … 
    } 
}); 
0

除了始終保持MyClass的所有實例範圍(或作爲一個全局變量),我沒有看到任何解決方案。但是,你可以破除不必使用Function.prototype.bind無處不在聲明self

$.get('ajax/test.html', function(response) { 
    this.someVarToBeSetUsingAjax = response.value; 
}.bind(this)); 

這不限於$獲得(),你可以用它無處不在,你正在使用的回調函數。