【问题标题】:Simple inheritance implementation for JS: is this a good example?JS 的简单继承实现:这是一个很好的例子吗?
【发布时间】:2013-02-22 04:56:31
【问题描述】:

来自 Dojo,我真的想念一个 很多 Dojo 的 declare() 功能。 我正在开发一个复杂的应用程序,并且我从 Node 的 lang.inherits() 中破解了这个活生生的地狱,让它变得更……好吧,更强大。

这里有一个例子来展示它的实际作用:

var First = declare( null, {
  one: function(p){ 
    console.log("one in First");
    console.log(p); 
    return 1000; 
  },
  two: function(p){ 
    console.log("two in First");
    console.log(p);
    return 1001; 
  },
  constructor: function(a){ 
    this.a = a; 
    console.log("Constructor of First called");
  },
})

var Second = declare( First, {
  two: function( p ){
    console.log("two in Second"); 
    console.log( p );
    a = this.inherited(arguments);
    console.log("Inherited function returned: " + a );
  },
  constructor: function(a){ 
    console.log("Constructor of Second called, and this.a is...");
    console.log( this.a );
  },
})

console.log("Creating first...");
first = new First(10);
console.log("Creating second...");
second = new Second( 20 );

console.log( "first.a:")
console.log( first.a );
console.log( "second.a:")
console.log( second.a );

console.log( "first.one(1):")
first.one(1);
console.log( "first.two(2):")
first.two(2);

console.log( "second.one(3):")
second.one(3);
console.log( "second.two(4):")
second.two(4);

将显示:

Creating first...
Constructor of First called
Creating second...
Constructor of First called
Constructor of Second called, and this.a is...
20
first.a:
10
second.a:
20
first.one(1):
one in First
1
first.two(2):
two in First
2
second.one(3):
one in First
3
second.two(4):
two in Second
4
two in First
4
Inherited function returned: 1001

我知道lang.inherits() 函数之所以简约是有原因的:nodejs 不想强加特定的方式来处理 Javascript 中的“类”、原型和对象。

但是,很多代码都充满了:

function SomeClass( options ){
  this.options = options;
}

SomeClass.prototype.functionOne = function(something){
  //...
}
SomeClass.prototype.functionTwo = function(something){
  //...
}

哪一个可以(并且...嗯,应该?)写成:

SomeClass = declare( null, {
  constructor: function(options){
    this.options = options;
  },
  functionOne: function(something){
    // ...
  },
  functionTwo: function(something){
    // ...
  },
})

能够做到的好处是:

SomeOtherClass = declare( SomeClass, {
  constructor: function(){
    this.options['manipulate'] ++;
  },
  functionOne: function(something){
    this.inherited(arguments); // Call the superclass method
    // ...
  },
})

它会自动调用父类的构造函数等。 (为了实现this.inherited(),我实际上最终创建了函数的哈希映射,因为它们实际上是无名的);

这个版本和Dojo 的主要区别在于这个版本没有实现多重继承和混合。然而,虽然多重继承/混合在客户端环境中是有意义的,但我觉得它们在服务器端程序中将是一个主要的过度杀伤力。 好的......这是代码。 你能发现这段代码有什么问题吗?

我是否发明了一些已经存在的东西?

我们开始...

var 
  dummy
;

var declare = exports.declare = function(superCtor, protoMixin) {

  // Kidnap the `constructor` element from protoMixin, as this
  // it mustn't get copied over into the prototype
  var constructor = protoMixin.constructor;
  delete protoMixin.constructor;

  // The function that will work as the effective constructor. This
  // will be returned
  var ctor = function(){

    // Call the superclass constructor automatically
    if( typeof( superCtor.prototype.constructor === 'function' ) ){
       superCtor.prototype.constructor.apply( this, arguments );
    }

    // Call its own constuctor (kidnapped a second ago)
    if( typeof( constructor ) === 'function' ){
      constructor.apply( this, arguments );
    }
  };

  // The superclass can be either an empty one, or the one passed
  // as a parameter
  superCtor = superCtor === null ? function(){} : superCtor;

  // Create the new class' prototype. It's a new object, which happen to
  // have its own prototype (__proto__) set as the superclass' and the
  // `constructor` attribute set as ctor (the one we are about to return)
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });

  // Implement inherited() so that classes can run this.inherited(arguments)
  // This will only work for sub-classes created using declare() as they are
  // the ones with the _inheritMap in their prototype
  protoMixin.inherited = function(args){
    var name, fn;

    // Look for the name in the _inheritMap
    name = this._inheritMap[ args.callee ];
    if( name ){
      fn = superCtor.prototype[name];
      if( fn ){
        return fn.apply( this, args );
      } else {
        throw( new Error("Method " + name + "() not inherited!") );
      }
    }
  }

  // Copy every element in protoMixin into the prototype.
  ctor.prototype._inheritMap = {}
  for( var k in protoMixin ){
    ctor.prototype[ k ] = protoMixin[ k ];
    ctor.prototype._inheritMap[ protoMixin[ k ] ] = k;
  }

  return ctor;
};
exports = module.exports = declare;

【问题讨论】:

  • 我是咖啡脚本的忠实粉丝,我认为您应该尝试一下。它几乎可以满足您在继承方面的所有需求。
  • 是的,但我不是那种喜欢喝咖啡的人:D
  • 继承方法是否适用于多个继承级别?
  • 确实如此,它只是使用了 JS 的原型。唯一的“魔法”是构造函数的调用,以及 this.inherited(arguments)...

标签: javascript node.js class inheritance


【解决方案1】:

我会看一下npm install declarejs,它基本上是 Dojo 声明的删减版本。

您可以找到更多信息here

我个人更喜欢 Backbone 的 .extend() 这样的东西,很容易被撕掉。

【讨论】:

    【解决方案2】:

    嗯,我想答案是“如果它有效,那就太好了!”。 它有效……所以:太棒了!

    供将来参考,“声明”在 GitHub 上:

    https://github.com/mercmobily/JsonRestStores/blob/master/declare.js

    我更新了代码,使得 this.inherited(arguments) 可以在没有 hashmap 的情况下工作。

    目前,它是以下内容的一部分:

    https://github.com/mercmobily/JsonRestStores

    尽管我不妨创建一个单独的存储库,因为它一个拥有自己权利的方便功能!

    佣兵。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-27
      • 2015-10-30
      • 2015-01-04
      • 1970-01-01
      • 2016-04-25
      • 1970-01-01
      相关资源
      最近更新 更多