大家好,我最近正在学习JavaScript的继承。我创建了一个Child
函数,并使其继承了Human
函数。我先创建一个child
的{{1}}实例,然后再创建Child
。
我想知道为什么输出仅具有console.log(child)
属性,而没有Child
属性。
我想这是因为属性描述符,特别是Human
,但我无法弄清楚。谁能帮我吗?
enumerable
运行上述代码后,尽管const Child = function() {
this.name = "child"
}
const Human = function() {
this.move = "walking";
}
Child.prototype = new Human();
Child.prototype.constructor = Child;
const child = new Child();
console.log(child);
给出了“行走”的信息,但我只看到{name:“ child”}。
答案 0 :(得分:0)
简而言之,就是在move
实例上找不到Child
,但是在原型上它是从Human
继承的。
让我们分析您的代码。
const Child = function() {
this.name = "child"
}
const Human = function() {
this.move = "walking";
}
这些是不言自明的,您创建了两个构造函数。它们无关(还)。
Child.prototype = new Human();
Child.prototype.constructor = Child;
这是继承部分。 Child.prototype = new Human();
将创建Human
的实例,并将其分配给Child.prototype
,因为该实例具有成员move
,该成员已分配给Child.prototype
,而您得到本质上为Child.prototype = { move: 'walking' }
或Child.prototype.move = 'walking'
的东西(虽然不准确,但足够接近)
然后,将Child
本身分配为prototype.constructor
。
看到怪异行为的原因是您期望move
是实例成员,但它是原型成员。这种影响的一个更严重的缺点是,更改child.move
会同时对所有所有子实例进行更改,而这并不是您期望实例成员提供的。
由于这个原因,不建议像您一样通过实际创建实例来进行继承,而应像这样使用Object.create()
:
Child.prototype = Object.create(Human.prototype);
Child.prototype.constructor = Child;
此外,您的Child
函数应调用父级构造函数,以维护父级的逻辑和成员。像这样:
const Child = function() {
Human.call(this); // call to parent constructor
this.name = "child";
}
完整代码:
const Human = function() {
this.move = "walking";
}
const Child = function() {
Human.call(this);
this.name = "child"
}
Child.prototype = Object.create(Human.prototype);
Child.prototype.constructor = Child;
const child = new Child();
console.log(child);
一旦您了解了原型链的工作原理,请记住,创建了ES6类是为了更优雅,更易读的代码来处理这些情况:
class Human {
constructor() {
this.move = "walking";
}
}
class Child extends Human {
constructor() {
super();
this.name = "child";
}
}