В JavaScript простираются от конструктора


Допустим, у меня есть это:

function Foo(){
   this.name = "fooos";
};

Теперь позже в скрипте у меня есть ссылка на Foo, и что добавить свойства Foo при создании экземпляра. Я мог бы сделать что-то вроде этого:

Foo.prototype.myProp = 3;

foo = new Foo();

expect(foo).to.have.property('name');
expect(foo).to.have.property('myProp');

Это прекрасно работает, пока мне не нужно присоединить объект к прототипу, например:

Foo.prototype.myProp = { bar : 3 };

Проблема в том, что теперь экземпляры будут делиться состоянием на bar (поскольку ' bar-это просто Ссылка):

foo = new Foo();
foo2 = new Foo();

foo.myProp.bar = 5;
expect(foo2.myProp.bar).to.equal(5);

Что нежелательно. Однако если объект добавляется внутри конструктора экземпляры делают это не делить государство.

Есть ли способ обойти это? У меня нет доступа к конструктору, чтобы управлять им. Мне нужно прикрепить объект к экземпляру из прототипа.

2 2

2 ответа:

Свойства не обязательно должны быть на прототипах, вы можете просто добавить их непосредственно в экземпляры:

var f = new Foo();
f.myProp = { bar: 3 };

Я это знаю. Это не то, чего я хочу.

Единственный способ, который я могу придумать, чтобы сделать это через прототип с свойством (не метод; @meager имеет решение с помощью метода) - это уродливый Хак, где вы определяете свойство на прототипе с Object.defineProperty (ES5-only), а затем переопределяете его при первом доступе, например это:

Object.defineProperty(Foo.prototype, "myProp", {
    get: function() {
        var obj = { bar: 3 };
        Object.defineProperty(this, "myProp", {
            get: function() {
                return obj;
            },
            set: function(value) {
                obj = value;
            }
        });
        return obj;
    }
});

Живой Пример | Источник

Я бы так и сделал. нет рекомендую это. :- )


Альтернативой было бы бросить фасад перед Foo, как это:

var OriginalFoo = Foo;
Foo = function() {
    OriginalFoo.apply(this, arguments);
    this.myProp = { bar: 3 };
};
Foo.prototype = Object.create(OriginalFoo.prototype);

Это, конечно, относится только к объектам, созданным с помощью new Foo после этот код выполняется.

Вы не можете сделать это, основываясь на вашем ограничении необходимости пройти через прототип. Прототип является общим, вы не можете дать каждому экземпляру уникальный объект через прототип. Это практически невозможно по определению того, что такое прототип.

Ближе всего было бы добавить метод доступа, который лениво добавляет свойство к конкретному экземпляру, но это довольно далеко от вашего ask:

Foo.prototype.getMyProp = function () {
  this.myProp = this.myProp || { bar: 3; }
  return this.myProp
}

foo = new Foo();
foo2 = new Foo();

foo.getMyProp().bar = 5
expect(foo2.getMyProp().bar).to.equal(3);