原型继承和Object.create

Prototypal inheritance and Object.create

本文关键字:create Object 继承 原型      更新时间:2023-09-26

当谈到JavaScript原型继承时,我想我完全明白自己在做什么。原来是个残忍的情妇。下面是我用口袋妖怪(是的,口袋妖怪…)来展示不同进化如何相互继承的例子。

function Squirtle(firstPower) {
    this.firstPower = firstPower;
}
Squirtle.prototype.useFirstPower = function () {
    console.log("Using " + this.firstPower);
}
function Wartortle(firstPower, secondPower) {
    Squirtle.call(this, firstPower);
    this.secondPower = secondPower;
}
Wartortle.prototype.useSecondPower = function () {
    console.log("Using " + this.secondPower);
}
var mySquirtle = new Squirtle("water squirt");
mySquirtle.useFirstPower(); //works
//squirtle evolved
mySquirtle.prototype = Object.create(Wartortle.prototype);
mySquirtle.useSecondPower(); //no method found

这里期望的效果是保持Wartortle.prototypeprototype方法和Sqruitle.prototype的方法。我假设在Wartortle构造函数中使用Squirtle.call(...)将允许我继承所有方法。显然不是。我觉得我对这些东西比以往任何时候都更失落。

如何正确继承并保留超级构造函数和子构造函数的所有方法??我在这里做错了什么?

编辑

如下所述,我可以使用new Wartortle创建一个新对象,但我认为我所追求的是将原始对象全部扩充在一起。这是怎么回事?

这就是"正常"惯性的工作方式:

function Squirtle(firstPower) {
    this.firstPower = firstPower;
}
Squirtle.prototype.useFirstPower = function () {
    console.log("Using " + this.firstPower);
}
function Wartortle(firstPower, secondPower) {
    Squirtle.call(this, firstPower);
    this.secondPower = secondPower;
}
//Wartortle inherits from Squirtle
Wartortle.prototype = Object.create(Squirtle.prototype);
//Wartortle methods
Wartortle.prototype.useSecondPower = function () {
    console.log("Using " + this.secondPower);
}
var mySquirtle = new Squirtle("water squirt");
var myWartortle = new Wartortle("water squirt plus", "ice blast");

现在,您可以分别创建喷射和wartortle对象,每个wartortle实例都继承了喷射的方法。

现在,如果你有一个喷射物体,并想把它转换成一个战斧物体,你基本上有两个选择:

1) 编写一个转换函数:

function transform(squirtle, secondPower) {
    return new Wartortle(squirtle.firstPower, secondPower);
}

2) 或者操作__proto__属性,据我所知,这是真正将对象更改为另一个构造函数实例的唯一方法:

squirtle.__proto__ = Wartortle.prototype;
squirtle.secondPower = "awsome secone power";

不过,我会坚持第一种方法,因为__proto__并不是所有地方都支持的。

如果你想让你的喷射器成为战斧,你不应该创建一个新对象吗?

mySquirtle = new Wartortle("water squirt", "water gun");
mySquirtle.useSecondPower();
=> Using water squirt
=> Using water gun

编辑

要转换喷射器,您可以将其分配给对象本身一个新的原型,并设置第二次幂:

mySquirtle.__proto__ = Wartortle.prototype;
mySquirtle.secondPower = "water gun";

Edt 2

更改对象的问题是原型是为函数而设,而不是为使用new创建的对象而设。因此,如果你要改变Squirtle的原型,你将赋予所有喷射器新的力量。

对象有对其原型的引用,但本身没有原型:

console.log(mySquirtle.prototype);
=> undefined

因此,您可以直接将方法添加到对象中,但随后将在对象上定义许多重复的函数,而不是在一个原型上定义。