簡體   English   中英

工廠函數原型

[英]Factory functions prototype

學習構造函數我提出了這個問題:

為什么不使用返回 object 而不是構造函數的普通函數?

讀了一下,我發現了工廠函數(ff)。 與構造函數的區別是:

  • 使用this替換 object 文字{ }
  • 使用new return的object。

但我相信這還不夠簡化,它只是有點整潔,但不多。

舉個例子:

function box(x,y,z){
return { 
        x:x , y:y , z:z , 
        volume: function (){return x*y*z} 
        }
   }

我們可以很容易地編寫一個具有相同 function 的構造函數。

現在,我知道其中一個差異可能是原型。 所以這是我的問題:

  • ff 和構造函數之間的主要區別是什么? 原型是工廠函數和構造函數之間的區別嗎?

與 function 一起創建的原型 object 確實有所作為。 當您使用new調用 function 時, this object 將得到該原型 object 作為其原型。 因此,新 object 的原型鏈比工廠 function 的原型鏈長了一步。

實例

該語言提供了instanceof運算符和constructor屬性,這在您使用構造函數時很有用,因為它們提供了有關實例構造函數的信息。 對於 object 文字(在您的box函數中使用),確定構造函數是Object而不是box

為了使兩個版本的函數更接近一點,以便僅突出顯示本質上的區別,您可以將它們編寫如下:

function box(x,y,z) {
    let obj = {};
    obj.x = x;
    obj.y = y;
    obj.z = z;
    // Better reference the properties here, ...in case they are changed:
    obj.volume = function () { return obj.x * obj.y * obj.z } 
    return obj;
}

構造函數可能如下所示:

function Box(x,y,z) {
    // `this` is already initialised as a new object with a specific prototype
    this.x = x;
    this.y = y;
    this.z = z;
    this.volume = function () { return this.x * this.y * this.z }
    // `this` is returned by default, so no `return` is needed
}

注意原型鏈(運行代碼片段)和instanceof的用處的區別:

 function box(x,y,z) { let obj = {}; obj.x = x; obj.y = y; obj.z = z; obj.volume = function () { return obj.x * obj.y * obj.z } return obj; } function Box(x,y,z) { this.x = x; this.y = y; this.z = z; this.volume = function () { return this.x * this.y * this.z } } let a = box(1,2,3); let b = new Box(1,2,3); // Print prototype chains console.log("a-->" + Object.getPrototypeOf(a).constructor.name); let protB = Object.getPrototypeOf(b); console.log("b-->" + protB.constructor.name + "-->" + Object.getPrototypeOf(protB).constructor.name); // Print use of `instanceOf` console.log("a instanceof box?", a instanceof box); console.log("b instanceof Box?", b instanceof Box);

方法

到目前為止,我忽略了一個事實,即volume function 可以重復使用,而不是為每個實例單獨定義。 在這兩種情況下,您都可以將volume function 定義為(更多)全局 function。 請注意,您現在可以使用this關鍵字,因為通常您會將volume稱為instance.volume()

function volume { return this.x * this.y * this.z }

function box(x,y,z) {
    let obj = {};
    obj.x = x;
    obj.y = y;
    obj.z = z;
    obj.volume = volume; 
    return obj;
}

盡管如此,您仍然有明確的obj.volume = volume分配。 在構造函數模式中,您不需要創建該實例屬性。 在原型 object 上定義方法就足夠了:

function Box(x,y,z) {
    this.x = x;
    this.y = y;
    this.z = z;
    // No need here to define `volume`
}

Box.prototype.volume = function { return this.x * this.y * this.z };

所以,實際上你只有一個對該方法的引用。

Class 語法

最后,還有class語法,這是使用構造函數的替代方法:

class Box(x,y,z) {
    constructor(x,y,z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    volume() {
        return this.x * this.y * this.z;
    }
}

在這個語法中, volume也是在原型上定義的,而不是在實例上。

使用構造函數的缺點

到目前為止,比較有利於使用構造函數(在我看來)。

但:

  • 使用工廠函數可以完全避免使用this object。 使用this可能會令人困惑(正如 Stack Overflow 上關於該主題的許多問題所展示的那樣)。 一些程序員認為這是放棄構造函數的好理由。
  • 創建更長的原型鏈會對性能產生負面影響,有時會使簡單的任務看起來很復雜。 對於上面的示例,沒有這樣的問題,但是使用 Object 面向編程的典型示例,其中您有一個從中派生AnimalBeing ,從哪個Mammal派生,從哪個...等等等等,可能會讓人感到困惑。 一個扁平的數據結構可以讓人感到如釋重負。

是的,原型是所謂的工廠函數和構造函數之間的區別。

在您提供的示例代碼中,您將無法訪問box的原型,即使添加了該原型也是如此。 當您使用new關鍵字調用 function 時,它在內部執行的第一項工作是創建 object 並根據您通過box.prototype提供的引用創建其原型鏈,並且在設置完該過程后,該過程將返回 ZA8CFDE6331BD59EB66ZC94 . 但在您的代碼中,訪問權限僅限於您返回的 object,它將覆蓋最初創建的 object 的返回。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM