2015-09-05 87 views
1

假設我有一個Posts類。訪問原型父項

我可以這樣做:

Posts.prototype.foo = function() { 
    console.log(this); 
} 

當我打電話post1.foo()(與post1作爲Posts類的實例),由控制檯輸出的this將等於post1

現在考慮以下情形:

Posts.prototype.baz = { 
    foo: function() { 
    console.log(this); 
    }, 
    bar: [1,2,3,4] 
} 

現在,當我做post1.baz.foo()this值不再post1,而是{foo: ..., bar: ...}

我的問題是:在第二種情況下,如何從foo內訪問post1

回答

2

你都撞在一個有趣的問題。你正在做的不是Javascript中的常見模式(爲原型分配一個嵌套對象),表面上它看起來應該起作用。

Javascript this有兩種解決方法。如果您正在使用new實例化一個函數,則this將成爲對該實例化對象的引用(如您所知)。

但是,this也可以解析爲父對象。也就是說,該代碼將記錄'bar'

var obj = { 
    prop: 'bar', 
    log: function() { console.log(this.prop); } 
}; 
obj.log(); 

因爲this被引用對象的功能在裏面。這就是你的情況。範圍正在比您想要的更早解決。另外:如果函數沒有嵌套在一個對象中,並且你沒有使用new,那麼this將成爲全局對象(window在瀏覽器中)。

正確的方式做,這可能是在構造函數中的帖子,在這裏你可以設置this.whatever並將其綁定到實例。此方法最常用於「私有」變量,但在需要向您的類中添加計算數據時也很有用,或者在您的情況下聲明特定範圍。

function Posts() { 
    var self = this; 

    this.baz = { 
     foo: function() { 
      console.log(self); 
     }, 
     bar: [1,2,3,4] 
    } 
} 

你也可以這樣做:

... 
    this.baz = { 
     foo: function() { 
      console.log(this); 
     }.bind(this), 

您可能需要採取在你爲什麼需要在類原型嵌套對象一探究竟。你能把它分解成所有平面原型方法嗎?它是不是需要在每個類實例上實例化的數據,並且可以在其他地方拔出?

+0

很好的答案,謝謝!我可能會把它分解成平面原型方法。我其實認爲這樣做會更「乾淨」,因爲我不會污染班級的名字空間。但後來我碰到這個問題... – Sacha

+0

另外,我不能修改'Posts'類本身,所以我想我不能使用你的其他解決方案。 – Sacha

+0

根據您的使用情況,另一個可能的解決方案是製作一個包含它的包裝類(您控制的)。修改別人的原型往往會導致歷史上的問題。 –

0

如果您可以更改如何調用此方法,則可以在baz內訪問this。例如:

post1.baz.foo.call(post1); 

會讓this文章類的你foo的功能實例內將console.log正確的對象。

Demo.

1

無論何時您擁有「this」關鍵字,它所綁定的對象取決於呼叫站點。只在通話現場。這裏有更深的討論you don't know js。我強烈建議你閱讀。但是,如果你讓我在簡化它,認爲它是這樣的:

當你執行一個功能,它大致是,如果你在做以下操作:

//default binding 
fn() ~ fn.call(window) 
// the default binding of this, is window, or undefined in strict mode. 

但是,您可以調用函數,具有

//implicit binding 
obj.fn() ~ fn.call(ojb) 
// in this case you are implicitly binding this as the obj 

或者,如果你想成爲明確的,使用callapply

//explicit bining 
fn.call(obj) 
//this is explicitly binding obj as this. 

這些的優先級是explicit> implicit> default。

在你的情況下,你正在運行post1.baz.foo():你的呼叫站點是.baz。對於規則2,您綁定了thisbaz。你想要的是明確的,並致電post1.baz.foo.call(post1);

淺見如下

這實在是太醜了壽,所以我覺得你的痛苦。其原因如此複雜,是因爲您正在針對穀物的語言工作。這可能是因爲你正在嘗試以java方式進行繼承。

最後,還有一個綁定,但避免它:new。如果可以,永遠不要使用新的。 JS不是Java,新的行爲非常混亂。如果你想實例化新的對象,使用Object.create。

+0

謝謝,我會查看該帖子。我想我主要了解這個呼叫站點的問題,我只是覺得可能有某種聰明的syntaxic解決方法。 – Sacha