Javascript OO语法

时间:2010-09-16 00:30:03

标签: javascript oop

在JavaScript中使用OO似乎有很多不同的方法。

我喜欢:

function ClassA(){};
ClassA.prototype={
    someFunc:function(a,b,c){},
    otherFunc:function(){}
}
var c=new ClassA();

并且从未使用过超出此功能的功能(尽管是一个熟练的OOer)。我怀疑这是老式的,因为我经常看到新的闪烁变体,这让我想知道我是否选择了最好的方法。例如,你可以在构造函数方法中创建魔法来创建私有变量和访问器方法,我认为(直到最近)是不可能的。子类化怎么样?我不知道如何实现这一点,但它现在必须有某种共同模式。

你是怎么做到的?为什么?

7 个答案:

答案 0 :(得分:6)

function foo() {
  var bar = function() { console.log("i'm a private method"); return 1; };
  var iAmAPrivateVariable = 1;

  return {
    publicMethod: function() { alert(iAmAPrivateVariable); },
    publicVariable: bar()
  }
}

//usage
var thing = foo()

这被称为功能性应用程序,因为您实际上正在利用闭包进行封装(这是在javascript中执行此操作的唯一方法)。

一般来说,你不应该在javascript中做OO,因为很多原因,它不是那么好的语言。认为方案有波浪括号和分号,你将开始像专业人士那样编写语言。话虽如此,有时OO更合适。在这些情况下,以上通常是最好的选择

编辑:将继承带入混合

function parent() {
  return { parentVariable: 2 };
}

function foo() {
  var bar = function() { console.log("i'm a private method"); return 1; };
  var iAmAPrivateVariable = 1;

  me = parent();
  me.publicMethod = function() { alert(iAmAPrivateVariable); };
  me.publicVariable = bar();

  return me;
}

这使得事情变得更加复杂,但是在仍然采用OO概念的功能方法(在这种情况下,使用装饰器函数而不是真正的继承)的同时实现了期望的最终结果。我对整个方法的喜欢之处在于,我们仍然按照这种语言的方式处理对象 - 可以随意附加内容的属性包。

EDIT2:

只是想在信用到期时给予信任,这种方法对于doug crockford在Javascript:The Good Parts中的建议略有简化。如果你想把你的js技能提升到一个新的水平,我强烈建议从那里开始。我不认为我从这么小的书中学到了很多东西。

另一个注意事项是,这与你在大多数工作中大部分时间都会看到的情况截然不同,往往很难解释a)发生了什么,以及b)为什么会这样对同事来说是一个好主意。

答案 1 :(得分:5)

Simple JavaScript Inheritance

因为John Resig这么说。

答案 2 :(得分:2)

JavaScript中的“子类化”通常是指基于原型的继承,它基本上遵循这种模式:

function Superclass() { }
Superclass.prototype.someFunc = function() { };

function Subclass() { }
Subclass.prototype = new Superclass();
Subclass.prototype.anotherFunc = function() { };

var obj = new Subclass();

这构建了obj -> Subclass.prototype -> Superclass.prototype -> Object.prototype的“原型链”。

几乎每个用于JavaScript的OOP库都建立在这种技术之上,提供了抽象大部分原型“魔法”的函数。

答案 3 :(得分:1)

我认为joose是一种非常酷的方式在javascript中执行OOP http://code.google.com/p/joose-js/

答案 4 :(得分:1)

JavaScript中的对象与几乎所有其他高端语言都不同。它们不是基于类(如Java,C ++,PHP等),而是基于原型的。因此,必须对面向对象编程的基本范例进行相当大的修改。那些不能或不想重新思考并坚持使用基于类的思维的人必须在JavaScript中构建基于类的逻辑,或者使用已经构建它的其他人的代码。

答案 5 :(得分:0)

我喜欢做类似

的事情
// namespace "My"
var My = new function {

  // private methods
  /**
   * Create a unique empty function.
   * @return {Function} function(){}
   */
  function createFn () {return function(){}}

  /** A reusable empty function. */
  function emptyFn () {}

  /**
   * Clone an object
   * @param {Object}  obj     Object to clone
   * @return {Object}         Cloned object
   */
  function clone (obj) { emptyFn.prototype=obj; return new emptyFn() }

  // public methods
  /**
   * Merge two objects
   * @param {Object} dst        Destination object
   * @param {Object} src        Source object
   * @param {Object} [options]  Optional settings
   * @return {Object}           Destination object
   */
  this.merge = function (dst, src, options) {
    if (!options) options={};
    for (var p in src) if (src.hasOwnProperty(p)) {
      var isDef=dst.hasOwnProperty(p);
      if ((options.noPrivate && p.charAt(0)=='_') || 
          (options.soft && isDef) || 
          (options.update && !isDef)) continue;
      dst[p]=src[p]; 
    }
    return dst;
  }

  /**
   * Extend a constructor with a subtype
   * @param {Function} superCtor      Constructor of supertype
   * @param {Function} subCtor        Constructor of subtype
   * @param {Object} [options]        Optional settings
   * @return {Function}               Constructor of subtype
   */
  this.extend = function (superCtor, subCtor, options) {
    if (!subCtor) subCtor=createFn();
    if (!options) options={};
    if (!options.noStatic) this.merge(subCtor, superCtor, options); 
    var oldProto=subCtor.prototype;
    subCtor.prototype=clone(superCtor.prototype);
    this.merge(subCtor.prototype, oldProto);
    if (!options.noCtor) subCtor.prototype.constructor=subCtor; 
    return subCtor;
  }

}

然后就像......

// namespace "My.CoolApp"
My.CoolApp = new function(){

  // My.CoolApp.ClassA
  this.ClassA = new function(){

    // ClassA private static
    var count=0; 

    // ClassA constructor 
    function ClassA (arg1) {
      count++;
      this.someParam=arg1;
    }

    // ClassA public static
    My.merge(ClassA, { 
      create: function (arg1) {
        return new ClassA(arg1);
      }
    }

    // ClassA public
    My.merge(ClassA.prototype, {
      doStuff : function (arg1) {
        alert('Doing stuff with ' + arg1);
      },
      doOtherStuff : function (arg1) {
        alert('Doing other stuff with ' + arg1);
      }
    }

    return ClassA;
  }

  // My.CoolApp.ClassB
  this.ClassB = new function(){

    My.extend(My.CoolApp.ClassA, ClassB);
    // ClassB constructor
    function ClassB () {
      ClassA.apply(this, arguments);
    }

    return ClassB;
  }

}

... clone函数是继承的关键。简而言之:

  • 通过将对象设为一次性函数的原型并使用'new'调用该函数来克隆对象。
  • 克隆父构造函数的原型,并将结果设置为子类的原型。

答案 6 :(得分:0)

用于画布的Javascript中的OOP

查看js中有用的OOP在不同情况下的效果......这样可以绘制正方形和圆形as objects,以便您可以根据需要返回并循环或操纵它们。

function Shape(x,y,color){
  this.x = x
  this.y = y
  this.color = color
}

function Square(height,width,color){
  Shape.call(this, event.x, event.y, color)
  this.height = height
  this.width = width
  this.x -= canvas.offsetLeft + (this.height/2)
  this.y -= canvas.offsetTop + (this.width/2)
}

Square.prototype = new Shape();
Square.prototype.draw = function(color){
  ctx.fillStyle = color
  ctx.fillRect(this.x,this.y,this.height,this.width)
}

function Circle(color, width){
  Shape.call(this)
  this.x = event.x -60
  this.y = event.y -60
  this.width = width
 }

Circle.prototype = new Shape();
Circle.prototype.draw = function(color){
  ctx.beginPath()
  ctx.arc(this.x,this.y,this.width,0,2*Math.PI, false);
  ctx.fillStyle = color
  ctx.fill()
}