JavaScript:函数是否应该能够使用Object.create()创建自己的实例

JavaScript: Should a function be able to create instances of itself with Object.create()

本文关键字:create 创建 实例 自己的 Object 函数 是否 能够使 JavaScript      更新时间:2023-09-26

我的用例如下:我想创建一个生产各种数据传输对象(DTO)的工厂。它们必须易于序列化,并且必须有一些额外的方法。

我当前的实现方式如下(简化):

window.Dto = function(type, properties)
{
    var
        self = this,
        values = {},
        object = Object.create(self);
    properties.forEach(function(prop){
        Object.defineProperty(object, prop, {
            get: function() { return values[prop]; },
            set: function(value) { values[prop] = value; },
            enumerable: true
        });
    });
    this.getType = function()
    {
        return type;
    };
    this.doSomeMagic = function()
    {
        // ...
    };
    return object;
};
// creating a DTO of the Transport.Motorized.Car class
var carObject = new Dto("Transport.Motorized.Car", ["vendor", "model", "color", "vmax", "price"]);

(注意:我不想为这些对象中的每一个创建显式类,因为它们有很多,并且是从服务器端导出的。此外,您在上面看到的properties参数实际上是一个带有验证约束等的元数据映射。)

我用一个循环做了一个快速的性能检查,其中创建了50000个这样的对象。performance.now()告诉我,它花了1秒多一点——这看起来不错,但并不太令人印象深刻。

我的问题主要是:工厂从自己的原型创建一个实例(如果我正确理解代码的作用)并返回它可以吗?它会有什么副作用?有更好的方法吗?

就我对工厂函数的理解而言,它们的全部意义在于不需要创建函数本身的新实例。相反,它只是返回一个新创建的对象。

因此,我不使用新创建的实例的实例属性(通过this)(通过new运算符),而是只创建一个对象(让我们称之为factoryProto),并将所有"实例"方法分配给该对象。

然后,您可以使用factoryProto作为新object:的[[Prototype]]

window.Dto = function(type, properties) {
    var factoryProto = {
          getType: function() {
            return type;
          },
          doSomeMagic: function() {
              // ...
          }
        },
        values = {},
        object = Object.create(factoryProto);
    properties.forEach(function(prop) {
        Object.defineProperty(object, prop, {
            get: function() { return values[prop]; },
            set: function(value) { values[prop] = value; },
            enumerable: true
        });
    });
    return object;
};
// creating a DTO of the Transport.Motorized.Car class
var carObject = Dto("Transport.Motorized.Car", ["vendor", "model", "color", "vmax", "price"]);

如果你想从原型链中完全获利,你可以在工厂函数之外定义factoryProto。为了跟踪type,可以将其添加为不可枚举的object属性:

window.Dto = (function() {
    var factoryProto = {
        getType: function() {
          return this.type;
        },
        doSomeMagic: function() {
            // ...
        }
    };
    return function(type, properties) {
        var values = {},
            object = Object.create(factoryProto);
        properties.forEach(function(prop) {
            Object.defineProperty(object, prop, {
                get: function() { return values[prop]; },
                set: function(value) { values[prop] = value; },
                enumerable: true
            });
        });
        Object.defineProperty(object, 'type', {
          value: type,
          enumerable: false
        });
        return object;
    };
})();
// creating a DTO of the Transport.Motorized.Car class
var carObject = Dto("Transport.Motorized.Car", ["vendor", "model", "color", "vmax", "price"]);