在这种情况下实现JavaScript的inheritance

我明白这是低调发布有关编程语言的问题,但我真的不能把我的头围绕在这一个,这是真正的士气低落。

我在节点js写一个游戏,我想从这个类inheritance…我不知道如何,语法抛出我和这个东西的教程似乎做了千千万万的方法与我的方法不同,与一个构造函数和所有。

基本上我的问题是如何inheritance下面的代码。

/* Character class*/ var character = function(startX) { var x = startX, swipe = 0; var getX = function() { return x; }; var getSwipe = function(){ return swipe; }; var setX = function(newX) { x = newX; }; var setSwipe = function(newSwipe){ swipe = newSwipe; }; return { getX: getX, getSwipe: getSwipe, setX: setX, setSwipe: setSwipe }; } exports.Character= Character; 

使用这种forms编写的代码(如果你不使用new的代码,并且你有真正的私有数据),主要的绊脚石就是Character没有任何可以在实例之间共享的东西。 因此,虽然可以使用由Character生成的对象作为其他对象的原型,但不能将其用作多个派生对象的原型。

下面是如何编写一个函数( Villian ,比如说),该函数生成的对象都以自己的底层Character对象为原型:

 function Villian(startX) { var rv = Object.create(Character(startX)); rv.doEvilThing = function() { }; return rv; } 

Villian创build一个新的Character对象,并将其指定为Villian创build的对象的原型。 当然,这意味着每次调用Villian都会创build两个对象,而不仅仅是一个对象,如果存在可以在Villian之间重用的Character部分的Villian

你可以让Villian直接从Character扩展对象:

 function Villian(startX) { var rv = Character(startX); rv.doEvilThing = function() { }; return rv; } 

那只能创造出一个客体,而且不能区分它的“ Villian和“ Character ”。


如果Character是这样写的,因为你希望xswipe是真正的私有的(尽pipe因为两者都有setter和getter,所以我没有看到太多的理由),你可能想要使用将会是ES6 私有属性的基础,这与您当前使用的模式不同,它对共享的原型对象很友好。

我已经写了一篇关于如何在不等待新的ES6function的情况下如何几乎可以做到这一点的文章 。 简而言之:ES6将引入新的“ Name ”对象,它们不是string,但可以用作属性的名称。 引用该属性时,可以使用该对象而不是名称。 例如:

 var x = new Name(); // Create the private name object this[x] = value; // Put a property on the object with that name 

专用Name对象是不透明的,默认情况下用它们创build的属性是不可枚举的。

这是整体模式。 (我试图坚持你的编码风格,对变化道歉。)请注意,这些CharacterVillian需要你使用new ,不像你上面的Character 。 下面我展示如何做到这一点没有new (这是一个小的改变)。

 var Character = (function() { var x = new Name(); // The *name* for our `x` property var swipe = new Name(); // The *name* for our `swipe` property /* Character class*/ var Character = function(startX) { this[x] = startX; this[swipe] = 0; }; Character.prototype.getX = function() { return this[x]; }; Character.prototype.getSwipe = function(){ return this[swipe]; }; // ...etc... return Character; })(); var Villian = (function() { /* Villian class*/ var Villian = function(startX) { Character.call(this, startX); }; Villian.prototype = Object.create(Character.prototype); Villian.prototype.doEvilThing = function() { // ... }; return Villian; })(); 

请注意,我们现在在原型上有各种方法,属性确实是属性(而您使用的模式是私有的,但不是属性),但是由于我们的范围函数外部没有任何代码可以访问Name对象对他们来说,没有外部代码可以使用这些属性。

在ES5和更早版本(例如今天),你需要一个函数来代替ES6的Name 。 我在文章中给出的一个使用非重复的随机string:

 var Name = function() { var used = {}; function Name() { var length, str; do { length = 5 + Math.floor(Math.random() * 10); str = "_"; while (length--) { str += String.fromCharCode(32 + Math.floor(95 * Math.random())); } } while (used[str]); used[str] = true; return new String(str); // Since this is called via `new`, we have to return an object to override the default } return Name; }(); 

你可以做同样的事情,而不是new 。 唯一改变的是实际的CharacterVillian函数,但是为了清晰起见,我将包含整个内容:

 var Character = (function() { var x = new Name(); // The *name* for our `x` property var swipe = new Name(); // The *name* for our `swipe` property /* Character class without using `new` */ var Character = function(startX) { var c = Object.create(Character.prototype); c[x] = startX; c[swipe] = 0; return c; }; Character.prototype.getX = function() { return this[x]; }; Character.prototype.getSwipe = function(){ return this[swipe]; }; // ...etc... return Character; })(); var Villian = (function() { /* Villian class without using `new` */ var Villian = function(startX) { var v = Object.create(Villian.prototype); Character.call(v, startX); return v; }; Villian.prototype = Object.create(Character.prototype); Villian.prototype.doEvilThing = function() { // ... }; return Villian; })(); 

如果你想要一个更传统的inheritance方法,为什么不修改你的字符函数来利用函数原型呢?

 var Character = function(startX) { this.x = startX; this.swipe = 0; } Character.prototype.getX = function() { return this.x; }; Character.prototype.getSwipe = function(){ return this.swipe; }; Character.prototype.setX = function(newX) { this.x = newX; }; Character.prototype.setSwipe = function(newSwipe){ this.swipe = newSwipe; }; function Villian(startX, villianStuff){ //pull in the base Character's stuff Character.call(this, startX); //set up the sub "class"'s stuff this.villianStuff = villianStuff; } //inherit all of those public Character functions Villian.prototype = Object.create(Character.prototype); //now add whatever new Villian stuff you need Villian.prototype.whatever = function() { }; var c1 = new Character(), c2 = new Character(), v1 = new Villian();