JavaScript OOP:经典实现奇数

时间:2013-08-14 00:52:30

标签: javascript oop inheritance

好的,我已经修改了大部分技术来实现JavaScript OOP中的继承。 作为一名Java程序员,我对经典方法很感兴趣,但这就是问题所在;说我想创建Animal类(我知道它不是真正的类,但让我使用这个术语),如下所示:

function Animal(name){  
    this.name = name;
}
Animal.prototype.getName = function() {
    return this.name;
}

重要的是要注意,这是我的第一个意图中的具体类,我想实例化它,而不是仅仅将它用作超类。我可以创建几个Animal个实例,每个实例都有自己的名称。

扩展此类的一种可能方法是执行以下操作:

function Cat(name, owner) {
    this.name = name;
    this.owner = owner;
}
// ALTERNATIVE 1:
    Cat.prototype = Object.create(Animal.prototype);
// ALTERNATIVE 2: 
    Cat.prototype = new Animal('LOLA');
// END OF ALTERNATIVES
Cat.constructor.prototype = Cat;
Cat.prototype.jump = function() {
    alert(this.name + " jumping");
}

使用 ALTERNATIVE 1 我们只是继承了超类的方法,实际上我们需要重新定义Cat中的name属性。由于 ALTERNATIVE 2 实际上没有任何变化,我们在链中还有一个对象,它拥有一个非常无用的name属性:对于所有Cat个实例都是一样的。

这里的要点是我已经用自己的名字编写了Animal类,我只要将它扩展就把它扔掉。我想要的是继承属性和方法的方法,最重要的是,我希望能够重用Animal构造函数。

1 个答案:

答案 0 :(得分:0)

继承基础构造函数属性的传统方法如下:

function Cat(name, owner) {
    Animal.call(this, name); // call the base constructor
    this.owner = owner;
}

Cat.prototype = new Animal;
Cat.prototype.constructor = Cat;
Cat.prototype.jump = function () {
    alert(this.name + " jumping");
};

以上代码与其他语言的以下类相同:

class Cat extends Animal {
    constructor(name, owner) {
        super(name);
        this.owner = owner;
    }

    jump() {
        alert(this.name + " jumping");
    }
}

继承属性的新方法完全相同,除了我们用new Animal替换Object.create(Animal.prototype)。我们更喜欢新方式的原因是:

  1. 调用new Animal是不必要的开销。无论如何,Cat构造函数再次调用它。
  2. 调用new Animal可能不会返回空白对象。它可能会为对象添加一些属性。
  3. 我们还不知道用new Animal调用什么参数。因此,称之为没有任何意义。
  4. 因此,首选的继承方式是:

    function Cat(name, owner) {
        Animal.call(this, name); // call the base constructor
        this.owner = owner;
    }
    
    Cat.prototype = Object.create(Animal.prototype);
    Cat.prototype.constructor = Cat;
    Cat.prototype.jump = function () {
        alert(this.name + " jumping");
    };
    

    请注意,调用基础构造函数很重要,因为它可能会进行一些初始化,这是实例正常工作所必需的。

    如果您有兴趣以经典风格编写JavaScript代码,那么请查看描述原型类同构的following answer。以下代码取自以上答案:

    function CLASS(prototype, base) {
        switch (typeof base) {
        case "function": base = base.prototype;
        case "object": prototype = Object.create(base, descriptorOf(prototype));
        }
    
        var constructor = prototype.constructor;
        constructor.prototype = prototype;
        return constructor;
    }
    
    function descriptorOf(object) {
        return Object.keys(object).reduce(function (descriptor, key) {
            descriptor[key] = Object.getOwnPropertyDescriptor(object, key);
            return descriptor;
        }, {});
    }
    

    使用CLASS函数,我们可以在JavaScript中定义伪类,如下所示:

    var Animal = CLASS({
        constructor: function (name) {
            this.name = name;
        },
        getName: function () {
            return this.name;
        }
    });
    
    var Cat = CLASS({
        constructor: function (name, owner) {
            Animal.call(this, name);
            this.owner = owner;
        },
        jump: function () {
            alert(this.name + " jumping");
        }
    }, Animal);
    

    还有其他方法可以在JavaScript中进行继承。我建议您阅读Why Prototypal Inheritance Matters上的博文,了解有关JavaScript继承的更多信息。