3

所以我真的浏览了整个互联网,发现了许多在 javascript 中设置原型继承的不同方法。

他们中的一些人使用call().
他们中的一些人使用这个 sytnax: var rabbit.prototype = new Animal
其中一些在更改原型后更改了构造函数,有些则没有。
有些设置了一个有助于设置继承的小功能。

有人可以对此有所了解吗?有很多关于这个的帖子,但好的帖子已经有 2 年以上的历史了,它们在我心中造成了很大的混乱。
我想一劳永逸地知道如何在javascript中真正正确地设置原型继承。

要是简单点就更好了!

4

3 回答 3

4

在实现了几种不同的 javascript 继承方式之后,当我想为浏览器 rpg 构建一个 javascript 游戏引擎时,这最终是我所采用的:

播放器基类:

function Player(name, type, gender, experience, avatar){
    this.name = name;
    this.type = type;
    this.gender = gender;
    this.experience = experience;
    this.avatar = avatar;

    this.stats ={//getter, setter}
    //lots more code
}

向播放器类添加方法

Player.prototype.decrease_life = function(decrement){} 
//note that the keyword this in the decrease_life function will 
//refer to the player that the method is called on.

现在播放器类的继承:

function Mage(name, type, gender, exp, avatar){
    Player.apply(this, [name,type,gender,exp,avatar]); 
    //apply allows you to specify what the keyword 
    //this refers to in the Player super class.
}
Mage.prototype = new Player;

最后我们创建一个播放器:

current_player =  new Mage(name,type,gender,0,avatar);

这使我们现在可以这样做:

current_player.decrease_life(20); //The mage loses 20 life!

或者这样做:

current_player.stats.get(); 
//returns the mages stats, it does that because we used apply, and 
//this.stats in the player class is referring to our mage now

正如其他人所提到的,javascript 继承没有最佳实践。我发现上面最接近地模仿了您期望继承在 Java 或 C++ 中的工作方式,它们具有更典型的继承结构。

于 2013-04-15T17:30:21.233 回答
2

关于原型继承的重要一点是你继承自对象而不是类。所以这个想法是tomsBankAccount继承 off bankAccount,这可能会通过基于类的语言的实例化来完成。当你想要一个“类”的“实例”时,这将通过一个实现公共特性的对象来完成,它是任何想要这些特性的对象的原型。

这是一个未经测试且错误的具体示例。但这是错误的,我会谈到。

var bankAccount = {
    withdraw: function(amount) { this.balance -= amount },
    deposit: function(amount) { this.balance += amount }
}

var account1 = {
    balance: 50
}

account1.prototype = bankAccount
account1.deposit(100)
alert(account1.balance)  // Displays 150

所以一个对象有它自己的东西,比如balance字段,但将通用功能委托给 bankAccount 对象。所以继承的等价物是决定一个常见的对象和原型。

实际上,上面的代码被破坏了。JavaScript 不允许您仅对任何旧对象进行原型制作,或者至少JavaScript 不允许。它强制原型只从从返回的对象中完成,constructor functions当你调用它们时,它们在 JavaScript 中具有特殊的语法,即new关键字。

您可能已经看到看起来像这样的代码(同样,未经测试):

function BankAccount(balance) {
    this.balance = balance
    this.withdraw = function(amount) { this.balance -= amount }
    this.deposit = function(amount) { this.balance += amount }
}

var account1 = new BankAccount(50)
account1.deposit(100)
alert(account1.balance)  // Same result as last time

您还会注意到它们以大写字母开头。基本上就是这样。this很奇怪——它带有对包含函数的对象的引用。所以携带deposit方法的对象也携带了balance属性,这就是为什么我们可以从方法中访问balancevia this

但是上面的代码不是惯用的 JavaScript。一旦你掌握了窍门,就会有一些事情要记住。例如,上面为每个对象构造重新分配了新方法,这显然不是很快。这可以通过将方法分配给函数构造函数的原型来解决。还有通过 JavaScript 的闭包“私有化”属性的能力。

您可能会怀疑 JavaScript 用于处理对象的类似 Java 的表示法完全具有误导性,因为它的底层如此不同……我同意。

于 2013-04-15T17:53:39.203 回答
1

没有真正统一的“最佳方式”来做到这一点。2 岁的“好答案”仍然是相关的(如果它们很好,我个人会丢弃任何试图模拟一个类的东西),因为 javascript(EcmaScript)已经很老了(十多年了)。

call用于传递什么this

至于原型继承:我真的很喜欢YUI 剧院的“crockford on javascript”。你会想看“第三幕:发挥终极作用

设置原型的最简单方法是:
objectIdentifier.prototype.methodIdentifier = function(args){ /* your code*/ }

有许多不同的“构造模式”,其中大多数都在特定的给定情况下使用。考虑一段代码将要做什么以及使用它的频率通常是一个好主意。您还想查看一些流行的库,例如 JQuery,并查看它们的模式。

希望这可以帮助!

于 2013-04-15T17:07:17.693 回答