Вы путаете наследование с вызовами конструктора.Когда вы говорите:
duck = new Bird();
, вы делаете явный вызов функции конструктора Bird
, поэтому, конечно, Bird
сработает.
Хотя Object.create()
- это удобный способ наследования одного объекта от другого, вам все равно придется вручную настроить цепочку конструктора.Хороший способ понять это, когда оба конструктора принимают аргументы (показано ниже).
См. Встроенные комментарии:
function Animal(gender) {
// The argument allows the instance property to initialize.
// gender will be a property of Animal and will be inherited
// by anything that inherits from Animal later. But, that
// doesn't change the fact that the Animal constructor
// must be called and passed the gender for the Animal
// to be properly initialized.
this.gender = gender;
// Get the caller of this function (non-standard technique - just used for demo).
// If the caller is null, it means that Animal was called directly. If not,
// we can get the name of the calling function:
var caller = Animal.caller ? Animal.caller.name : "Animal";
// Report of newly constructed Animal
console.log("Animal is a " + this.gender + ". (called by: " + caller + ")");
}
function Bird(gender, canFly) {
// Because a bird inherits from an Animal, you have
// to manually ensure that when a new Bird is created
// the Animal constructor gets called. You can see
// why this is necessary as we have a situation where
// the prototype's constructor is expecting an argument
// that we've received when the constructor of the
// derived object was called. We certainly don't want
// to have to rewrite the code that sets the gender, so
// we call the prototype's constructor and pass it what
// it is expecting and allow it to do some of the object
// initialization for us:
Animal.prototype.constructor.call(this, gender);
// Arguments meant for the current constructor are handled
// in the current constructor
this.canFly = canFly
// The inherited properties are available:
console.log("Bird is a " + this.gender + " and it can fly: " + this.canFly);
}
// This just causes Bird to inherit from Animal. This alone
// doesn't cause the Animal constructor to fire when new Bird()
// is executed.
Bird.prototype = Object.create(Animal.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Bird work properly
Bird.prototype.constructor = Bird;
// Just a test to show that making an Animal properly
// requires that the Animal constructor be called and
// passed a gender.
console.log("--- Creating New Animal ---");
var generic = new Animal("male");
// You are explicitly invoking the Bird constructor here.
// It's going to fire that function. That function, in turn,
// is configured to invoke the prototype object's constructor.
// The gender property will be handled by the Animal constructor
// and the canFly will be handled by the Bird constructor.
console.log("--- Creating New Bird ---");
duck = new Bird("female", false);
// ************************************************
function Falcon(gender, canFly, trained){
// We'll pass the arguments needed by the parent object to it
Bird.prototype.constructor.call(this, gender, canFly);
// And set current instance properties right here
this.trained = trained;
console.log("Bird is a " + this.gender + ", can fly: " + this.canFly + " and is trained: " + this.trained);
}
Falcon.prototype = Object.create(Bird.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Falcon work properly
Falcon.prototype.constructor = Falcon;
console.log("--- Creating New Falcon ---");
let f = new Falcon("female", true, false);