Почему конструктор объекта A выполняется, хотя мы меняем его вручную на другой конструктор при создании объектов с использованием нового ключевого слова?

function Animal() { console.log("Animal")}
function Bird() { console.log("Bird")}
function Dog() { console.log("Dog")}

Bird.prototype = Object.create(Animal.prototype);
Dog.prototype = Object.create(Animal.prototype);


 duck = new Bird();
 beagle = new Dog();

В приведенном выше кодексе мы наследуем Bird and Dog от Animal. Их прототип будет животным. Поэтому по умолчанию Bird.constructor будет указывать на Animal constructor.

Когда выполняется новая Bird (). Я ожидаю, что «Animal будет зарегистрирован на консоли», но Bird зарегистрирован. Так как конструктор Animal. Конструктор животных должен быть выполнен правильно? Исправьте мое понимание

Всего 2 ответа


Вы путаете наследование вызовами конструктора. Когда ты сказал:

duck = new Bird();

вы делаете явный вызов функции конструктора Bird поэтому, конечно, Bird будет стрелять.


Хотя Object.create() является удобным способом наследования одного объекта на другом, вам все равно придется вручную настроить цепочку конструкторов. Хороший способ понять это - когда оба конструктора принимают аргументы (показано ниже).

См. Комментарии inline:

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


Заявление

Bird.prototype = Object.create(Animal.prototype);

делает объект-прототип конструктора Bird новым объектом, собственным прототипом которого является прототип Animal , а не сам конструктор Animal .

таким образом

duck = new Bird()

создает новый объект, конструктором которого является Bird , прототипом которого является прототип Bird , который, в свою очередь, наследуется от прототипа Animal .

Таким образом, ваш прототип Animal может иметь метод, называемый eat() , поэтому вызов

duck.eat("fish")

было бы эффективным вызовом метода eat() на прототипе Animal . Зачем? Хорошо, что нет «есть» собственность прямо на объект duck , и ни один из прототипа Bird , но есть свойство «есть» на прототипе Animal .


Есть идеи?

10000