javascript - 为什么即使我们在使用 new 关键字创建对象时手动将其更改为另一个构造函数,也会执行 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();
在上面的代码中——我们从 Animal 继承了 Bird 和 Dog。他们的原型将是动物。所以默认情况下 Bird.constructor将指向 Animal 构造函数。
执行 new Bird() 时。我希望“动物被登录到控制台”,但鸟被记录了。由于构造函数是Animal。应该执行动物构造函数吗?纠正我的理解
解决方案
您将继承与构造函数调用混淆了。当你说:
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);
推荐阅读
- python-3.x - 将具有多列的数据框转换为只有 3 列的数据框
- javascript - 使用返回 Observable 过滤具有多个对象数组的响应
- jquery - 单击“阅读更多”时计算高度并将动画添加到完整描述中
- json - LISP:如何使用 cl-json 正确编码斜杠(“/”)?
- mapbox - Mapbox gl draw为多边形添加名称
- javascript - 如何从本地存储中的数组中删除某些项目?
- azure - 使用证书获取令牌时,对象引用未设置为对象的实例
- powershell - 如何使用 Powershell 按顺序打印 PDF 文件?
- node.js - node-canvas registerFont 部署后找不到字体文件(在本地工作)
- flutter - 如何在调用构建方法之前等待异步方法完成加载数据?