我正在研究一些JavaScript代碼,這些代碼將用於爲我們的企業級軟件構建「類」(特別是「查看模型」)的構造函數。我正在做的一件事是建立一個代碼強制設計模式,在這個模式中,實現者將明確定義他們希望由類的實例公開哪些函數,代碼將它們添加到構造函數的prototype
中,如反對該類的每個實例的屬性。這當然有一個好處,那就是每個類型只有一個這樣的函數的實例,而不是每個實例的實例。使用綁定來強制原型函數的上下文
Here's a CodePen of most of my examples.
的問題是,在一定條件下,我處理binding loss問題。例如,對於此構造:
function Foo(myName) {
this.firstName = myName;
}
Foo.prototype.greet = function(yourName) {
alert("Hello, " + yourName + ". I am " + this.firstName + ".");
}
...這將工作:
var sam = new Foo("Sam");
// Alerts "Hello, Denny. I am Sam."
sam.greet("Denny");
...但這不會:
var sad = new Foo("Sad");
// This changes the context of greet. :(
var sadGreet = sad.greet;
// Alerts "Hello, Denny. I am undefined."
sadGreet("Denny");
這是因爲當我們做var sadGreet = sad.greet
我們正在將greet
函數的上下文更改爲window
,因此在調用sadGreet("Denny")
時this.firstName
不存在。
所以,我想出了一個解決方案是覆蓋原型與調用原型的屬性,在Function.prototype.bind()
包裹它:
function Bar(myName) {
this.firstName = myName;
// Here's where the magic happens.
this.greet = Bar.prototype.greet.bind(this);
}
Bar.prototype.greet = function(yourName) {
alert("Hello, " + yourName + ". I am " + this.firstName + ".");
}
var happy = new Bar("Happy");
// Since each instance of Bar overwrites the context for greet, this will work. :)
var happyGreet = happy.greet;
// Alerts "Hello, Denny. I am Happy."
happyGreet("Denny");
我的問題是這樣的:我認爲Bar
是效率不如Foo
,但是這樣做是否會將greet
作爲prototype
方法聲明爲完全無效?在封面之下,它只是複製greet
作爲一個屬性,無論如何,或者是我的電話bind
只需添加一個「包裝」爲Bar.prototype.greet
?換句話說,這是否與Bar的上述定義完全相同?
function Bar(myName) {
this.firstName = myName;
// Here's where the magic happens.
this.greet = function(yourName) {
alert("Hello, " + yourName + ". I am " + this.firstName + ".");
}
}
如果您不僅可以回答問題,而且可以告訴我如何測試,那麼可以獲得積分獎勵!
關於效率問題通常是艱難對於SO而言,因爲它很難得到確鑿的回答。也就是說,我的主要反應是,我認爲'happyGreet(...)'通常是一個錯誤。如果一個函數在一個實例上,你可能不應該把它分配給一個變量,如果你這樣做,你應該''。bind'它在那裏的分配位置,或做'happyGreet.call(快樂,「丹尼」)' – loganfsmyth
@loganfsmyth感謝您的答覆,我同意。不幸的是,這只是「綁定損失」可能發生的幾個可能的例子之一 - 而且我不一定要控制這些構造函數的每個實現。 – Grinn
函數的執行上下文包含一個* this *參數,該參數通過調用函數**或使用* bind *來設置**。如果你改變你如何調用一個函數,他們可能會改變它* this *。或不。 – RobG