需要的模式:创建返回可执行函数的新对象,并从原型继承

时间:2011-05-05 09:02:01

标签: javascript node.js

场景1 - 一切正常:

var AwesomeObject = function()
{
   var self = this;
   self.whatstuff = 'really awesome';
}

AwesomeObject.prototype.doStuff = function()
{
   var self = this;
   console.log('i did '+self.whatstuff+' stuff');
   return self;
}

var awesome = new AwesomeObject(); //returns a new AwesomeObject
awesome.doStuff(); // prints 'i did really awesome stuff' on the console

现在我甚至想要它甚至更棒:

var AwesomeObject = function()
{  
   var f = function() { console.log('i am awesome'); }
   var self = f;
   self.whatstuff = 'really awesome';
   return self;
}

AwesomeObject.prototype.doStuff = function()
{
   var self = this;
   console.log('i did '+self.whatstuff+' stuff');
   return self;
}

var awesome = new AwesomeObject(); //returns the interal f object
awesome(); // prints 'i am awesome'
awesome.doStuff(); // throws an error

新的AwesomeObject本身应该返回一个可执行函数,这样我就可以说'awesome();'

但我希望它也继承AwesomeObject.prototype

添加self.prototype = AwesomeObject.prototype;无济于事。

var AwesomeObject = function()
{  
   var f = function() { console.log('i am awesome'); }
   var self = f;
   self.whatstuff = 'really awesome';
   self.prototype =  AwesomeObject.prototype;
   return self;
}

好的我可以将AwesomeObject.prototype函数 - 一个接一个地复制到f

的范围内
var AwesomeObject = function()
{  
   var f = function() { console.log('i am awesome'); }
   var self = f;
   self.whatstuff = 'really awesome';
   self.doStuff =  function() { AwesomeObject.prototype.doStuff.apply(self,arguments); }
   return self;
}

但我认为必须有更好的方法,更好的模式,它是什么?

这个问题让我发疯,帮助真的很感激。

一般来说:如何创建一个

的函数对象
  • 可以使用新的
  • 创建
  • 返回可以执行的函数对象
  • 继承了给定原型的所有属性和方法

有办法吗?

THX 弗朗兹

3 个答案:

答案 0 :(得分:8)

一个非常简单的模式是工厂。

var AwesomeObject = (function() {
    var AwesomeObject = function() {
        this.whatstuff = 'really awesome';
    };

    AwesomeObject.prototype.doStuff = function() {
        console.log('i did ' + this.whatstuff + ' stuff');
        return this;
    };

    return function() {
        var o = new AwesomeObject();
        var f = function() { console.log("I am awesome"); };
        for (var k in o) {
            f[k] = o[k];    
        }

        return f;
    };

})();

var foo = AwesomeObject();
foo();
foo.doStuff();

Live Example

我们的想法是将您的功能和对象分成两部分。您的对象存在于函数的本地范围内,函数可以使用该对象。

对象本身完全通过原型继承。

关键是将对象的所有属性/方法转发到函数上。

这是最干净的解决方案。

答案 1 :(得分:2)

当一个属性被解析时,你可能知道原型链的遍历。 但是,如果您有一个对象awesome并尝试评估awesome.doStuff,则永远不会查询awesome.prototype该属性。您可以在示例"doStuff" in awesome => false"doStuff" in awesome.prototype => true中对此进行验证。

所以你所做的不是改变awesome的隐式属性,而是改变它的原型,这意味着通过执行new awesome创建的任何对象都将拥有该属性。验证:"doStuff" in new awesome() => true。这是有道理的,因为在使用f/awesome时无法区分构造函数或常规函数。

解析对象p上的属性o时的过程大致如下:

  • 检查p
  • 上是否定义了o
  • 检查p上是否定义o.__proto____proto__的使用是非标准的,但是已广泛实施,但上次检查时jscript除外,现在已在SpiderMonkey中弃用)
  • 检查p
  • 上是否定义了o.constructor.prototype
  • 检查p
  • 上是否定义了o.constructor.prototype.prototype

因此,一个解决方案是简单地设置o.__proto__ = AwesomeClass.prototype。将__proto__视为对象与其原型之间的隐藏中间对象。每个实例都会收到自己唯一的__proto__对象。但是像我说的那样,这已被弃用并且不合标准。

我们也可以在Function.prototype中设置值,但这会覆盖其他Function属性并影响所有Function实例。我们不希望这样。

那剩下什么了?结果不多。在保留对象的继承原型的同时,无法设置对象的完整原型。您需要遍历原型并复制所有属性。幸运的是,这将允许instanceof在使用构造函数链时按预期运行,并允许正确地继承/覆盖属性。

问题实际上是没有内置的方法将对象的属性复制到另一个对象中,并且没有标准方法来更改对象的原型链ad-hoc(__proto__)。

所以使用__proto__,或者遍历原型。

答案 2 :(得分:1)

我认为没有好方法可以做到这一点。我会重新设计你的程序以避免它。

但是,这是错误平台相关解决方案(适用于使用非标准__proto__属性的V8):

var PrototypeToBeInherited = {'inheritedProperty': 'inheritedPropertyValue'};

f = function() {
  return "result";
};
f.__proto__ = PrototypeToBeInherited;

f()
 => "result";
f.inheritedProperty
 => "inheritedPropertyValue"

对于您必须使用“new”创建的要求,只需将其包装在函数中:

F = function() {
    return f;
}
var instance = new F();