2009-01-08 63 views
0

我正在创建一个小代码插件,它允许你用数组做一些事情。我不希望将功能添加到使用原型建造的数组对象,我要的是,人们可以这样做:

arrayFunction([1, 2, 3]).someSpecialArrayFunction(); 

因此离开正常的数组对象不变。
于是我想出了下面的结构(这是启发了jQuery源代码):

var arrayFunction = window.arrayFunction = function(array) { 
    return new arrayFunction.fn.init(array); 
} 
arrayFunction.fn = arrayFunction.prototype = { 
    init: function(array){ 
     this.a = array; 
     //should I return something here? 
    }, 
    someSpecialArrayFunction: function(){ 
     //Super cool custom stuff here. 
    } 
} 

然而,这并不工作(明显)。 init函数()中应该发生什么?

错误现在的问题是,当我尝试:

arrayFunction(array).someSpecialArrayFunction(); 

它说,someSpecialArrayFunction()不是一个功能?

应该怎么做?

编辑
是的,这确实是一个简单的例子。实际的东西有更多的方法。

另外,我只是虽然它会是多么令人敬畏,如果它也支持chaning,你会怎么做?

+0

jquery的$实际上是一个对象。 – Malfist 2009-01-08 17:57:24

+0

在Javascript中,所有函数都是对象 - 您实际上是使用function关键字声明对象的,因此jQuery $既是对象又是函数,它返回该对象的实例。这可能需要一些习惯... – 2009-01-08 18:21:55

+0

你在这里寻找一种方法来创建你的示例*工作* - 或者通过将方法添加到包装器的原型中来将方法附加到包装器对象的一般模式。所以你可以管理大量的扩展方法集合? – 2009-01-08 18:47:18

回答

2

或者干脆:

var arrayFunction = function(array) { 
    var someSpecialArrayFunction = function() { 
     // do something with array 
    }; 
    return { 
     someSpecialArrayFunction: someSpecialArrayFunction 
    } 
}; 
arrayFunction([1, 2, 3]).someSpecialArrayFunction(); 

虽然要小心这个,如果你最终会有太多的方法可能会更好地使用原型。

1

我不知道这是为了得到你想要的最好的语法,但我想这是一个下调例子...反正这里是一个快速的方法,使工作

var arrayFunction = window.arrayFunction = function(array) { 
    return new arrayFunction.fn.init(array); 
} 
arrayFunction.fn = arrayFunction.prototype = { 
    init: function(array){ 
     var a = array; 
     return { 
      someSpecialArrayFunction: function(){ 
       alert (a.join(' - ')); //Super cool custom stuff here. 
      } 
     }; 
    }, 
} 
arrayFunction([1, 2, 3]).someSpecialArrayFunction(); 
0

sktrdieanswer看起来不错。

要考虑的另一件事是使用flyweight pattern而不是每次调用您的包装时都返回一个新的对象实例。 ExtJS功能Ext.fly这样做;它会返回一个全局共享的实例。

0

尝试这样:

var mathWrapper = function(array) { 
    return { 
     mean : function(){ 
      if (array.length == 0) return(0); 
      var total = 0; 
      for (var i = 0; i < array.length; i++) total += array[i]; 
      return(total/array.length); 
     }, 
    }; 
} 

通过调用的东西像

document.write(mathWrapper([1,2,3,4,5,6]).mean()); 

应该返回数组元素的平均值。

0

如果你不想T改变Array.prototype,唯一真正可行的解决方案是增加的方法,具体的数组对象:

function doSomething() {} 
function doOther() {} 

function wrap(array) { 
    array.doSomething = doSomething; 
    array.doOther = doOther; 
    return array; 
} 

请注意,我不定义doSomething()和内wrap()doOther() - 否则,我们会在每次调用时创建新的函数对象,效率非常低。

一个更复杂的变体将是以下几点:

function doSomething() {} 
function doOther() {} 

function wrap(array) { 
    if(this instanceof arguments.callee) { 
     this.doSomething = doSomething; 
     this.doOther = doOther; 
    } 
    else { 
     arguments.callee.prototype = array; 
     return new arguments.callee; 
    } 
} 

在这里,我们创建了一个新的包装对象(不属性阵列自身添加)。包装器对象仍然可以访问所有数组的属性。有一个细微差别,但:

var foo = wrap([1,2,3]); 
document.writeln(foo.length); // writes 3 
foo.push(4); 
document.writeln(foo.length); // writes 4 in FF, 3 in IE 
foo[4] = 5; 
foo[5] = 6; 
document.writeln(foo.length); // still writes 4?! 

使用foo[4] =将访问我们的包装对象和属性45将在阵列中设置有与没有 - 因此,它的长度属性将不会被更新。在IE中,调用push()将无法​​正确更新阵列...

如果您的包装器对象不需要将调用重新路由到数组对象,则还有其他解决方案使用闭包--sktrdie的第一个示例是一个这些。我会反对他们,因为他们会在每次调用时创建新的函数对象。我会做什么:

function wrap(array) { 
    if(this instanceof arguments.callee) 
     this.array = array; 
    else return new arguments.callee(array); 
} 

wrap.prototype.doSomething = function() {}; 
wrap.prototype.doOther = function() {}; 

在这里,你可以通过this.arraydoSomething()doOther()访问阵列。

0

只需扩展Array对象并将您喜欢的方法添加到您的对象。然后,您可以创建一个桥接函数,将数组作为参数并返回您的数组版本。这种方法要容易得多,也更有用。

相关问题