В вашем примере конструктор Box
выполняется только при установке объекта NewBox.prototype
.
Вы можете обойти это, вызвав функцию конструктора Box
внутри NewBox
с помощью Function.prototype.apply
метод, чтобы установить значение this
и переслать все значения аргумента, например:
//..
var NewBox = function() {
Box.apply(this, arguments);
this.newThing = true;
};
//..
var a = new NewBox();
var b = new NewBox();
// assuming your `generateUniqueId` function
// increments a number
alert(a.id); // will alert 1
alert(b.id); // will alert 2
Теперь каждый раз, когда вызывается конструктор NewBox
для создания новогоэкземпляр объекта (new NewBox();
), он вызовет функцию Box
, чтобы применить к нему всю свою логику.Это поможет вам избежать повторения логики родительского конструктора снова и снова.
Используется apply
, вызов функции «родительского» конструктора, устанавливающей значение this
для экземпляра объекта, который создается конструктором NewBox
, и мы передаем все аргументы, предоставленные этой функции.
В вашем примере также показана распространенная проблема: когда вы выражаете отношения наследования через NewBox.prototype = new Box();
, вызывается конструктор Box
и у него есть побочные эффекты, этот новый объект будет инициализирован, а ваша функция generateUniqueId
будетвыполняется впервые, если вы хотите избежать этого, вам нужно либо использовать временный конструктор, просто чтобы создать новый объект, наследуемый от Box.prototype
, либо использовать новый метод ECMAScript 5 Object.create
для той же цели,например:
function inherit(o) {
function Tmp() {}
Tmp.prototype = o;
return new Tmp();
}
//.....
NewBox.prototype = inherit(Box.prototype);
Или:
NewBox.prototype = Object.create(Box.prototype);
Таким образом, вы выражаете ту же иерархию наследования, не запуская конструктор Box
в первый раз, избегая любого побочного эффекта, который онможет вызвать.
Наконец, но не в последнюю очередь, когда вы заменяете свойство прототипа функции всегда рекомендуетсявосстановить свойство constructor
этого нового объекта-прототипа, в противном случае он будет указывать на неправильную функцию.
В вашем примере, поскольку вы заменяете NewBox.prototype
новым экземпляром Box
, *Свойство 1043 * будет указывать на Box
, (на ваши экземпляры влияют, например, a.constructor === Box; // true
) вместо NewBox
, как и следовало ожидать, нам нужно установить его обратно, например:
NewBox.prototype = someObject; // as any of the examples above
NewBox.prototype.constructor = NewBox;
Вы можете абстрагировать эти детали в функцию, как я делал в функции inherit
выше:
function inherits(child, parent) {
var obj, Tmp = function () {};
Tmp.prototype = parent.prototype;
obj = new Tmp();
child.prototype = obj;
child.prototype.constructor = child;
}
//...
// instead of setting the `NewBox.prototype` manually
inherits(NewBox, Box); // "NewBox inherits from Box"
//...