Javascript 原型继承和Object.create

Javascript 原型继承和Object.create,javascript,Javascript,我想当涉及JavaScript原型继承时,我完全理解我在做什么。原来是个残忍的情妇。下面是一个我用口袋妖怪(是的,口袋妖怪…)演示不同进化如何相互继承的例子 function Squirtle(firstPower) { this.firstPower = firstPower; } Squirtle.prototype.useFirstPower = function () { console.log("Using " + this.firstPower); } functio

我想当涉及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.prototype
prototype
方法和
Sqruitle.prototype
的方法。我假设在
Wartortle
构造函数中使用
Squirtle.call(…)
将允许我继承所有方法。显然不是。我觉得我比以往任何时候都更迷茫于这些东西

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

编辑


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

如果你想让你的水枪成为一个水枪,你不应该创建一个新的对象吗

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
的原型,您将赋予所有Squirtle新的功能

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

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

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

如果你想让你的喷射器成为一个瓦索尔,你不应该创建一个新的对象吗

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
的原型,您将赋予所有Squirtle新的功能

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

console.log(mySquirtle.prototype);
=> undefined
因此,您可以直接将方法添加到对象中,但随后您将在对象上定义大量重复的函数,而不是在一个原型上定义

这就是“正常”固有力的工作原理:

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");
现在可以分别创建squirtle和Warortle对象,每个Warortle实例都继承squirtle的方法

现在,如果您有一个squirtle对象,并希望将其转换为一个Warortle对象,则基本上有两个选项:

1) 编写一个转换函数:

function transform(squirtle, secondPower) {
    return new Wartortle(squirtle.firstPower, secondPower);
}
2) 或者操纵
\uuuu proto\uuuu
属性,据我所知,这是将对象真正更改为另一个构造函数实例的唯一方法:

squirtle.__proto__ = Wartortle.prototype;
squirtle.secondPower = "awsome secone power";
不过我还是坚持第一种方法,因为并非所有地方都支持
\uuuu proto\uuuu

这就是“正常”固有性的工作原理:

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");
现在可以分别创建squirtle和Warortle对象,每个Warortle实例都继承squirtle的方法

现在,如果您有一个squirtle对象,并希望将其转换为一个Warortle对象,则基本上有两个选项:

1) 编写一个转换函数:

function transform(squirtle, secondPower) {
    return new Wartortle(squirtle.firstPower, secondPower);
}
2) 或者操纵
\uuuu proto\uuuu
属性,据我所知,这是将对象真正更改为另一个构造函数实例的唯一方法:

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


不过我还是坚持第一种方法,因为并非所有地方都支持
\uuu proto\uuuu

那么
myquirtle
应该继承
Wartortle
还是反过来?因为你有点搞混了。您还设置了对象的
prototype
属性,这是无用的,因为只有函数才具有该属性。@basilikum
Wartortle
将是
Squirtle
的进化版本。。。因此,
Wartortle
应该具有与
Squirtle
相同的方法。但是您正在尝试访问Squirtle对象中的
usessecondpower
,这是Wartortle的方法吗?还是将创建的对象从Squirtle转换为Wartortle?@basilikum的想法是将对象从
Squirtle
转换为
Wartortle
,并使所有方法都可用于新对象。
MyQuirtle
是否应该从
Wartortle
继承?因为你有点搞混了。您还设置了对象的
prototype
属性,这是无用的,因为只有函数才具有该属性。@basilikum
Wartortle
将是
Squirtle
的进化版本。。。因此,
Wartortle
应该具有与
Squirtle
相同的方法。但是您正在尝试访问Squirtle对象中的
usessecondpower
,这是Wartortle的方法吗?还是将创建的对象从Squirtle转换为Wartortle?@basilikum的想法是将对象从
Squirtle
转换为
Wartortle
,并为新对象提供所有方法。我尝试了这一方法,虽然这一方法有效,但我对转换所讨论的原始对象感到好奇。请记住,
\uuuuuuuuuuuuuuuuuuuuu
是一个特定于Firefox的实现,因此这不会在任何地方都起作用。在Chrome中失败,我相信Safari。
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。但你真的不应该使用它。我只是在Chrome上运行了这个示例,但失败了。我尝试了这个,虽然这个方法有效,但我很好奇是否能转换所讨论的原始对象。请记住,
\uuuuuu proto\uuu
是一个特定于Firefox的实现,所以这不会在任何地方都有效。在Chrome中失败,我相信Safari。
\uuuu proto\uuu
在中受支持