简体   繁体   English

工厂函数原型

[英]Factory functions prototype

Learning constructors I came with this question:学习构造函数我提出了这个问题:

Why not to use just normal functions returning an object instead of constructors?为什么不使用返回 object 而不是构造函数的普通函数?

Reading a bit, I found about factory functions (ff).读了一下,我发现了工厂函数(ff)。 The differences with constructors are:与构造函数的区别是:

  • The use of this that replaces the object literal { } ,使用this替换 object 文字{ }
  • The use of new replacing the return of the object.使用new return的object。

But that's not enough simplification I believe, it's just a bit tidier, but not much.但我相信这还不够简化,它只是有点整洁,但不多。

Take this example:举个例子:

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

We can easily write a constructor with same function.我们可以很容易地编写一个具有相同 function 的构造函数。

Now, I know one of the differences might be the prototype.现在,我知道其中一个差异可能是原型。 So here is my question:所以这是我的问题:

  • What are the key differences between ff and constructors? ff 和构造函数之间的主要区别是什么? Is the prototype a difference between factory functions and constructors?原型是工厂函数和构造函数之间的区别吗?

The prototype object that is created together with the function is indeed making the difference.与 function 一起创建的原型 object 确实有所作为。 When you call the function with new , the this object will get that prototype object as its prototype.当您使用new调用 function 时, this object 将得到该原型 object 作为其原型。 So the prototype chain for that new object is one step longer than what you get with the factory function.因此,新 object 的原型链比工厂 function 的原型链长了一步。

instanceof实例

The language offers the instanceof operator and the constructor property, which are useful when you use constructors, as they give information about the instance's constructor.该语言提供了instanceof运算符和constructor属性,这在您使用构造函数时很有用,因为它们提供了有关实例构造函数的信息。 In the case of an object literal (as used in your box function), that determines that the constructor is Object and not box .对于 object 文字(在您的box函数中使用),确定构造函数是Object而不是box

To bring the two versions of the functions a bit closer together, so that only the essential differences are highlighted, you could write them as follows:为了使两个版本的函数更接近一点,以便仅突出显示本质上的区别,您可以将它们编写如下:

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;
}

The constructor could look like this:构造函数可能如下所示:

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
}

Notice the difference in the prototype chains (run the snippet) and the usefulness of instanceof :注意原型链(运行代码片段)和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);

Methods方法

So far I ignored the fact that the volume function could be reused instead of defined separately for each instance.到目前为止,我忽略了一个事实,即volume function 可以重复使用,而不是为每个实例单独定义。 You can in both cases define the volume function as a (more) global function.在这两种情况下,您都可以将volume function 定义为(更多)全局 function。 Note that you now could use the this keyword, since normally you would call volume as instance.volume() :请注意,您现在可以使用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;
}

Still, you have the explicit obj.volume = volume assignment.尽管如此,您仍然有明确的obj.volume = volume分配。 In the constructor pattern, you don't need to create that instance property.在构造函数模式中,您不需要创建该实例属性。 It is enough the define the method on the prototype object:在原型 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 };

So, actually you only have one reference to the method.所以,实际上你只有一个对该方法的引用。

Class syntax Class 语法

Finally, there is the class syntax, which is an alternative to use constructors:最后,还有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;
    }
}

In this syntax volume is also defined on the prototype, not on the instance.在这个语法中, volume也是在原型上定义的,而不是在实例上。

Downsides to using constructors使用构造函数的缺点

So far, the comparison was favourable to using constructors (in my opinion).到目前为止,比较有利于使用构造函数(在我看来)。

But:但:

  • The use of the this object can be avoided completely by using factory functions.使用工厂函数可以完全避免使用this object。 Using this can be confusing (as the many questions on that topic on Stack Overflow demonstrate).使用this可能会令人困惑(正如 Stack Overflow 上关于该主题的许多问题所展示的那样)。 Some coders feel this is good reason to abandon constructors.一些程序员认为这是放弃构造函数的好理由。
  • Creating longer prototype chains can impact performance negatively and sometimes make simple tasks look complicated.创建更长的原型链会对性能产生负面影响,有时会使简单的任务看起来很复杂。 For the above example there is no such problem, but the typical examples for using Object Oriented Programming, where you have a Being from which Animal is derived, from which Mammal is derived, from which...etc, etc, can get confusing.对于上面的示例,没有这样的问题,但是使用 Object 面向编程的典型示例,其中您有一个从中派生AnimalBeing ,从哪个Mammal派生,从哪个...等等等等,可能会让人感到困惑。 A flat data structure can then feel like a relief.一个扁平的数据结构可以让人感到如释重负。

YES, Prototype is a difference between the so called factory functions and constructors.是的,原型是所谓的工厂函数和构造函数之间的区别。

In the sample code that you had given, you won't be able to access the prototype of box , even if that is added.在您提供的示例代码中,您将无法访问box的原型,即使添加了该原型也是如此。 When you call a function with new keyword, the first job that it would do internally is to create an object and create its prototype chain based on the references that you given via box.prototype and after setting that up the process will return the object created.当您使用new关键字调用 function 时,它在内部执行的第一项工作是创建 object 并根据您通过box.prototype提供的引用创建其原型链,并且在设置完该过程后,该过程将返回 ZA8CFDE6331BD59EB66ZC94 . But here in your code, the access has been restricted to the object that you are returning and it will override the return of the originally created object.但在您的代码中,访问权限仅限于您返回的 object,它将覆盖最初创建的 object 的返回。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM