【问题标题】:JavaScript OOP: classical implementation oddJavaScript OOP:经典实现奇怪
【发布时间】:2013-08-14 00:52:30
【问题描述】:

好的,我已经修改了大多数在 JavaScript OOP 中实现继承的技术。 作为一名 Java 程序员,我对 classical 方法很感兴趣,但这就是问题所在;说我想创建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 构造函数。

【问题讨论】:

  • 如果某些外星文明曾经挖掘过 Stack Overflow 数据库,他们会认为 JavaScript 专门用于对动物进行分类。
  • 在 Cat 函数体中,您通常调用 Animal.call(this,name); 从 Animal 获取实例属性。更多关于 JS 中的基本构造函数(再次使用动物):stackoverflow.com/questions/16063394/…

标签: javascript oop inheritance


【解决方案1】:

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

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。因此,这样称呼它是没有意义的。

因此,现在首选的继承方式是:

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 中的继承。

【讨论】:

    猜你喜欢
    • 2015-10-23
    • 1970-01-01
    • 1970-01-01
    • 2010-12-24
    • 2016-05-24
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    • 2011-07-23
    相关资源
    最近更新 更多