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

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

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

我当前的实现如下所示 (simplified):

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"]);

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

我使用创建了 50,000 个此类对象的循环进行了快速性能检查。 performance.now() 告诉我它花了超过 1 秒的时间——看起来不错,但不是太令人印象深刻。

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

据我了解工厂函数,它们的重点是不需要创建函数本身的新实例。相反,它只是 returns 一个新创建的对象。

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

然后,您可以使用 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"]);