1

我知道发布有关编程语言的问题会被看不起,但是我似乎真的无法解决这个问题,这真的让我士气低落。

我正在用 node js 编写一个游戏,我想从这个类继承......我不知道是怎么回事,语法让我失望,而且这些东西的教程似乎有上千种方式,与我的方法完全不同,有一个构造函数和所有。

基本上我的问题是如何对下面的代码进行子类化。

/* 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;
4

2 回答 2

3

使用以这种形式编写的代码(您没有使用new并且您拥有真正的私有数据),主要的绊脚石是Character没有可以在实例之间共享的任何内容。因此,虽然您可以将生成的对象Character用作其他对象的原型,但您不能拥有一个 Character对象并将其重用为多个派生对象的原型。

以下是如何编写一个函数(Villian例如)生成对象,每个对象都将自己的底层Character对象作为原型:

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

    rv.doEvilThing = function() {
    };

    return rv;
}

Villian创建一个新Character对象并将其分配为对象Villian创建的原型。当然,这意味着每次调用Villian都会创建两个对象,而不是像Character我们可以在 s 之间重用的部分那样只创建一个对象Villian

您可以直接Villian从以下位置扩展对象Character

function Villian(startX) {
    var rv = Character(startX);

    rv.doEvilThing = function() {
    };

    return rv;
}

那只创建一个对象,并没有区分它Villian的方面和Character方面。


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

我已经写了一篇文章,介绍如何在不等待新的 ES6 特性的情况下今天几乎可以做到这一点。简而言之:ES6 将引入新的 " Name" 对象,它们不是字符串,但可以用作属性的名称。引用属性时,可以使用该对象而不是名称。例如:

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

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

这是整体模式。(我在这里尝试坚持您的编码风格,对变化表示歉意。)请注意,这些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. 我在文章中给出的只是使用不重复的随机字符串:

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;

})();
于 2013-10-10T05:57:03.597 回答
1

如果您想要更传统的继承方法,为什么不修改您的角色函数以利用函数原型?

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();
于 2013-10-10T06:05:35.990 回答