在JavaScript中有继承的“正确”方法吗?如果是这样,它是什么?

时间:2008-10-22 03:03:01

标签: javascript oop refactoring interface

我一直在努力学习如何为现有代码添加测试 - 目前正在阅读Working Effectively With Legacy Code。我一直在尝试在JavaScript中应用一些原则,现在我正在尝试提取一个接口。

在JavaScript中搜索创建接口时,我找不到很多 - 我发现的继承似乎是几种不同的方式。 (有些人创建自己的基类来提供有用的方法,使其更容易进行继承,有些人使用函数,有些人使用原型)。

什么是正确的方法?有一个简单的例子用于在JavaScript中提取界面吗?

5 个答案:

答案 0 :(得分:13)

没有明确的正确的方式,因为有很多人在做这么多不同的事情。有很多有用的模式。

Crockford 建议您“顺其自然”,或者以与javascript原型性质相对应的方式编写javascript。

当然,他继续表明Netscape建议的原始模型实际上已经破裂了。他将其标记为“伪经典”,并指出了遵循该模型所涉及的许多误导和不必要的复杂性。

他将“对象”函数编写为补救措施(现在称为Object.create())。它允许一些非常强大的原型模式。

当你必须使用传统的javascript时,开发一个干净的界面并不总是那么容易,尤其是当你处理大型系统时,通常包括多个库,每个系统都实现了独特的风格和不同的继承模式。一般来说,我要说继承的“正确方法”是允许你编写一个干净的接口,它在遗留代码的上下文中表现良好,但也允许你重构并消除旧的依赖关系。

考虑到主要库模式之间的差异,我发现在我自己的工作中最成功的途径是保持我的接口完全独立于库接口。如果它有用,我将使用库或模块,但不会受其约束。这使我能够重构很多代码,淘汰一些库,并使用库作为脚手架,以后可以优化。

沿着这些方向,我编写了受Crockford寄生继承模式启发的界面。这简直就是一场胜利。

另一方面,我确信你可以争论选择一个库,在整个团队中执行它,并遵守它的继承模式和接口约定。

答案 1 :(得分:6)

javascript中没有类,只有对象。
但是如果你坚持模仿基于类的面向对象模型,你可以使用它:

function ChildClass() {
    ParentClass.call(this);
    // Write the rest of your constructor function after this point.
};
ChildClass.prototype = jQuery.extend({}, ParentClass.prototype, ChildClass.prototype);

jQuery.extend是jQuery库中的“浅拷贝”函数。您可以将其替换为任何其他对象复制/克隆功能。

答案 2 :(得分:5)

你正在看两件不同的事情。

首先你有接口。实现这一目标最常被接受的方式是Duck Typing(“如果它看起来像鸭子,嘎嘎叫像鸭子那么它就是鸭子”)。这意味着如果一个对象实现了一组接口方法,那么它就是那个接口。您可以通过定义一个接口的方法名数组来实现它。然后检查一个对象是否实现了那个interfece,你看它是否实现了那些方法。这是一个我掀起的代码示例:

function Implements(obj, inter)
{
    var len = inter.length, i = 0;
    for (; i < len; ++i)
    {
        if (!obj[inter[i]])
            return false;
    }
    return true;
}

var IUser = ["LoadUser", "SaveUser"];

var user = {
        LoadUser : function()
        {
            alert("Load");
        },

        SaveUser : function()
        {
            alert("Save");
        }
    };

var notUser = {
        LoadUser : function()
        {
            alert("Load");
        }
    };

alert(Implements(user, IUser));
alert(Implements(notUser, IUser));

现在你有了继承权。 JS没有内置的继承;所以你必须手动实现它。这只是将一个对象的属性“复制”到另一个对象的问题。这是另一个代码示例(不完美,但它证明了这一点):

function InheritObject(base, obj)
{
    for (name in base)
    {
        if (!obj[name])
            obj[name] = base[name];
    }
}

var Base = {
        BaseFunc : function() { alert("BaseFunc from base"); },
        InheritFunc : function() { alert("InheritFunc from base"); }
    }

var Inherit = {
        InheritFunc : function() { alert("InheritFunc from inherit"); },
        AnotherFunc : function() { alert("AnotherFunc from inherit"); }
    }

InheritObject(Base, Inherit);

Inherit.InheritFunc();
Inherit.BaseFunc();
Inherit.AnotherFunc();

Base.BaseFunc();
Base.InheritFunc();

您可能希望查看http://www.mootools.net。它有我最喜欢的Classes实现。你也一定想看看“Pro Javascript Design Patterns”

http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X

本书详细介绍了如何在javascript中模拟OOP。

答案 3 :(得分:3)

另请查看Dean Edwards的Base.js.您可以查看它here,博客文章不言自明。

答案 4 :(得分:0)

Prototype提供了自己的继承,来自http://www.prototypejs.org/api/class/create

var Animal = Class.create({
  initialize: function(name, sound) {
    this.name  = name;
    this.sound = sound;
  },

  speak: function() {
    alert(this.name + " says: " + this.sound + "!");
  }
});

// subclassing Animal
var Snake = Class.create(Animal, {
  initialize: function($super, name) {
    $super(name, 'hissssssssss');
  }
});