如何在JavaScript中模拟“类”? (有或没有第三方库)

时间:2008-12-10 12:06:39

标签: javascript oop

如何在JavaScript中模拟类(和名称空间)?

我需要创建一个JavaScript库,并且对该语言的使用经验有限。我一直认为它对类有本机支持,但它与Java的相关性低于我的假设。似乎JavaScript中的所有内容实际上都是一个函数。

到目前为止,我发现它是一种动态的弱类型语言很有意义,但这对于那些习惯使用强类型语言并使用编译器发现的人来说有点偏离我们的错误:)

我主要使用C#和Java,并且希望语法类似,所以对于我们需要维护它的其他C#开发人员来说,这个库看起来很熟悉。

我有以下类型的代码可行,但我想知道其他开发人员会采取什么措施。有哪些替代方案?有没有更好的方法?有没有更可读的方式?

我明白我要的是类似于C#或Java的东西时,我应该接受事实,这是JavaScript的,但我的目标是尽量减轻对其他开发人员的学习曲线使它更加熟悉和直观。

//Perform the namespace setup (this will actually be done with checking 
//in real life so we don't overwrite definitions, but this is kept short 
//for the code sample).
var DoctaJonez = new function();
DoctaJonez.Namespace1 = new function();

/**
 * Class description.
 */
DoctaJonez.Namespace1.SomeClass = function()
{
    /**
     * Public functions listed at the top to act like a "header".
     */
    this.publicFunction = privateFunction;

    /**
     * Private variables next.
     */
    var privateVariable;

    /**
     * Finally private functions.
     */
    function privateFunction()
    {

    }
}

//Create an instance of the class
var myClass = new DoctaJonez.SomeClass();

//Do some stuff with the instance
myClass.publicFunction();

7 个答案:

答案 0 :(得分:15)

答案 1 :(得分:9)

为了在JavaScript中对OOP的一般理解,你不能比阅读Douglas Crockford更好:

对于Dojo粉丝(以及一般技巧)Neil Roberts有好文章:

普通香草dojo.declare()可能是主流图书馆中最先进的OOP基础。我有偏见,但不接受我的话。以下是如何使用它的示例。

普通的香草物品:

// Let's define a super simple class (doesn't inherit anything).
dojo.declare("Person", null, {
  // Class-level property
  answer: 42,

  // Class-level object property
  name: {first: "Ford", last: "Prefect"},

  // The constructor, duh!
  constructor: function(age){
    this.age = age; // instance-level property
  },

  // A method
  saySomething: function(verb){
    console.log("I " + verb + " " +
      this.name.first + " " + this.name.last + "!" +
      " -- " + this.answer);
  },

  // Another method
  passportControl: function(){
    console.log("I am " + this.age);
  }
});

使用示例:

// A fan of Ford Perfect
var fan = new Person(18);
fan.saySomething("love"); // I love Ford Perfect! -- 42
fan.passportControl();    // I am 18

单继承很简单:

// Let's create a derived class inheriting Person
dojo.declare("SuperAgent", Person, {
  // Redefine class-level property
  answer: "shaken, not stirred",

  // Redefine class-level object property
  name: {first: "James", last: "Bond"},

  // The constructor
  constructor: function(age, drink){
    // We don't need to call the super class because
    // it would be done automatically for us passing
    // all arguments to it.

    // At this point "age" is already assigned.

    this.drink = drink; // Instance-level property
  },

  // Let's redefine the method
  saySomething: function(verb){
    // Let's call the super class first
    this.inherited(arguments);
    // Pay attention: no need for extra parameters, or any extra code,
    // we don't even name the class we call --- it is all automatic.
    // We can call it any time in the body of redefined method

    console.log("Yeah, baby!");
  },

  shoot: function(){ console.log("BAM!!!"); }
});

使用示例:

// Let's create a James Bond-wannabe
var jb007 = new SuperAgent(45, "Martini");
jb007.saySomething("dig");  // I dig James Bond! -- shaken, not stirred
                            // Yeah, baby!
jb007.passportControl();    // I am 45
jb007.shoot();              // BAM!!!

// Constructors were called in this order: Person, SuperAgent
// saySomething() came from SuperAgent, which called Person
// passportControl() came from Person
// shoot() came from SuperAgent.

的混入:

// Let's define one more super simple class
dojo.define("SharpShooter", null, {
  // For simplicity no constructor

  // One method to clash with SuperAgent
  shoot: function(){
    console.log("It's jammed! Shoot!");
  }
});

基于Mixin的多重继承:

// Multiple inheritance
dojo.declare("FakeAgent", ["SuperAgent", "SharpShooter"], {
  // Let's do it with no constructor

  // Redefine the method
  saySomething: function(verb){
    // We don't call super here --- a complete redefinition

    console.log("What is " + verb "? I want my " + this.drink + "!");
  },
});

使用示例:

// A fake agent coming up
var ap = new FakeAgent(40, "Kool-Aid");
ap.saySomething("hate"); // What is hate? I want my Kool-Aid!
ap.passportControl();    // I am 40
ap.shoot();              // It's jammed! Shoot!

// Constructors were called in this order: Person, SuperAgent
// saySomething() came from FakeAgent
// passportControl() came from Person
// shoot() came from SharpShooter.

正如您所看到的,dojo.declare()为所有必需品提供了一个简单易用的API:直接单继承,基于mixin的多重继承,构造函数的自动链接,以及无麻烦的超级方法。

答案 2 :(得分:1)

例如,在http://mckoss.com/jscript/object.htm

在谷歌搜索“JavaScript面向对象”时,你会发现一堆例子。通过查看像Ext JS这样的流行JavaScript框架,您将了解这些概念以及它们在实践中的应用方式。

答案 3 :(得分:1)

mepcotterell提​​供了良好的链接,但我想补充一点,我个人更喜欢将名称空间视为对象,即DoctaJonez.Namespace1 = {};

答案 4 :(得分:1)

使用MooTools。请参阅文章 How to write a Mootools Class

答案 5 :(得分:1)

如果您(和您的团队)习惯使用Java但需要为网站制作一些JavaScript,那么您应该考虑Google Web Toolkit(GWT)。它允许您使用Java编写JavaScript,并将其转换为JavaScript。不过我还没试过。

JavaScript实际上是一种非常酷的语言。它有一些缺陷(包括允许你做非常愚蠢的事情),但有一点自我约束你可以做出很棒的东西。 JavaScript实际上是对象 - 面向的,而不是 - 面向,但你可以做很多相同的事情。你没有(AFAIK)继承,但它的输入并不严格(它的一个强大但又危险的特性),所以你会发现它没有限制。

答案 6 :(得分:0)