2011-06-10 16 views
1

考慮下面的代碼:「特權」的方法調用成員方法問題

function Dog() 
{ 
    this.foo = function() {}; 

    this.walk = function() 
    { 
     if(canWalk()) 
     { 
      alert('walking'); 
      return; 
     } 

     alert('I have no legs!'); 
    } 

    canWalk = function() 
    { 
     this.foo(); 
     return false; 
    } 
} 

var instance = new Dog(); 
instance.walk(); 

有與「特權」 canWalk()方法假設this指針指向的Dog的實例代碼中的錯誤。它實際上似乎指向令我困惑的全球對象!我讀過,由於閉包,我可以在構造函數的範圍內獲取對this的引用,然後在我的「特權」方法中使用該引用,但這看起來像是一種破解。

我只是幾乎不知道在各種情況下的指針this的行爲。我明白,「附加」到對象的方法將收到指向附加對象的this。例如,foo.doStuff()將有一個指向foo實例的this

令人不安的是,雖然我認爲自己很聰明,並在我的OBJECT上創建了「特權」方法,但看起來我正在將函數轉移到全局範圍!也許有一種叫做init()的全局方法(很可能)來自另一個庫或文件,而不是我自己創建的。如果我然後用一個名爲init()的「特權」方法定義了一個很好的小封裝對象,我將替換其他全局方法init()

我的問題是,創建「特權」方法(和領域爲這個問題)的最佳做法是範圍的對象,他們打算屬於?對於我的示例對象,還有其他哪些方法可以提供私有或特權方法,同時還可以正確使用範圍。我不是在尋找滿足要求的晦澀解決方案,而是尋求最佳實踐。

+0

我無法弄清楚如何編輯我原來的職位,但我意識到我犯了一個不幸的錯誤,並沒有粘貼正確的示例代碼。 這裏有一個來自canWalk()方法的「foo」方法的調用,所以canWalk()基本上調用了this.foo()。 對不起混淆 – 2011-06-10 23:23:09

+0

啊,我明白了。在這種情況下,'this'可能指向'canWalk'函數。在我的例子中,如果你使用'self.foo',你會沒事的。並且可能有編輯按鈕:) – Halcyon 2011-06-10 23:24:46

+1

@Steve您可以通過點擊文本左下角藍色標籤下方的「編輯」編輯自己的帖子。我試着用你所描述的更新代碼,但有點不清楚。 – ErikE 2011-06-10 23:33:00

回答

4

請勿使用this。將var self = this;放在您的Dog功能的頂部,並使用self。這樣,你將永遠有一個'安全'參考狗。

在你的例子中this應該指向Dog,除非我也錯過了一些東西。

至於你的特權方法,你忘了定義變量。加入var canWalk;

還有另一種方法:關閉。我舉一個例子:

function create_dog() { 
    function canWalk() { 
     return false; 
    } 
    function walk() { 
     if (canWalk()) { 
      alert("walking"); 
      return; 
     } 
     alert("I have no hands!"); 
    } 
    return { 
     "walk": walk // points to the function walk() 
    }; // this the API of dog, like public functions (or properties) 
} 
var dog = create_dog(); 
dog.walk(); 

現在你不需要thisnew。另外你可以這樣做:

function create_dog() { 
    function canWalk() { 
     return false; 
    } 
    function walk() { 
     if (canWalk()) { 
      alert("walking"); 
      return; 
     } 
     alert("I have no hands!"); 
    } 
    var dog = { 
     "walk": walk 
    }; 
    return dog; 
} 
var dog = create_dog(); 
dog.walk(); 

所以你可以在你的priveledges函數中引用dog如果你不打算使用原型,我會建議閉包方法。

順便說一句。爲了避免混淆:

function my_func() {} 

var my_func = function() {}; 

是等價的。如果你在兩個函數之間有一個循環引用,並且你想強制執行define-before-use,那麼後者會很有用。

+0

+1很好的回答,展示瞭如何以兩種完全不同的方式來完成同樣的事情。 – 2011-06-10 23:25:17

+0

你爲什麼要改掉'new Dog'並創建一個對象? – ErikE 2011-06-10 23:34:28

+0

如果你不使用原型,使用'new'沒有什麼優勢。完全封閉的方法是可用的,只是不要嘗試做任何繼承。 – Halcyon 2011-06-10 23:50:21

1

首先,您需要在canWalk前面有一個var。這樣,canWalk函數就侷限於dog()的範圍,而不是一個隱式的全局函數。

this指向函數的「所有者」。當使用new運算符時,函數會創建它自己的作用域。因此,在dog()的主體內,this指向狗實例對象。在您的walk函數中,this也指狗實例,因爲您將walk函數設置爲dogthis.walk = function() { ... })的實例。但是,在canWalk中,沒有所有者,因此this指向全局對象window

我意識到,我的解釋可能會造成混亂,所以這裏是我的解釋代碼註釋的版本:

var obj = { 
    'f': function() { 
     // this === obj, because obj "owns" this function 
     // In other words, this function is callable by obj.f() 
    }, 
    'o': { 
     'f': function() { 
      // this === obj.o, because obj.o "owns" this function 
      // In other words, this function is callable by obj.o.f() 
     } 
    } 
}; 

// The new operator essentially sets "this" within the 
// function to an empty object and returns that object 
var instance = new Dog(); 

function Dog() { 
    // this === instance, because of the "new" operator 

    // For demonstration 
    var self = this; 

    this.walk = function() { 
     // this === instance === self, because self/instance "owns" this function 
     // In other words, this function is callable by self.walk() 
    }; 

    var canWalk = function() { 
     // What's the owner of this object? Nothing, 
     // so it defaults to the global object, window 
     // this === window 

     // Instead, we can access the Dog instance by 
     // using the "self" variable we set earlier. 
     // self === instance 
    }; 
} 

。希望清除的東西了。

+0

這是對這兩種情況的一個很好的解釋。我只涉及'canWalk'的隱式全局範圍,所以我刪除了我的答案。 +1 – 2011-06-10 23:37:16

+0

另一個很好的解釋和事物的介紹。我有點尷尬,我錯過了我沒有在前面使用'var'的事實。 – 2011-06-11 05:00:56

1

正如你所收集的,直接調用canWalk就意味着'this'關鍵字被設置爲該函數調用的全局對象。

如果你想運行當前的狗的環境下通話,你可以明確地這樣做是這樣的:

canWalk.call(this)

+0

我找到了call()解決方案,但決定不使用它,因爲它感覺不正確,它有一種氣味讓我覺得我應該尋找設計更改。儘管如此,記住call()選項是件好事。 – 2011-06-11 05:02:08