如何创建类似jquery的$()包装函数?

时间:2009-01-08 17:40:15

标签: javascript

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

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会有多棒,你会怎么做?

6 个答案:

答案 0 :(得分:2)

或者简单地说:

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

虽然要小心这一点,但如果最终的方法太多,那么使用原型可能会更好。

答案 1 :(得分: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();

答案 2 :(得分:0)

sktrdie answer看起来不错。

要考虑的另一件事是使用flyweight pattern而不是每次调用包装器时返回一个新的对象实例。 ExtJS函数Ext.fly执行此操作;它返回一个全局共享的实例。

答案 3 :(得分: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());

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

答案 4 :(得分:0)

如果您不想更改Array.prototype,唯一真正可行的解决方案是将方法添加到特定的数组对象:

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

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

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

更复杂的变体如下:

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将在那里设置而不在数组中 - 因此,不会更新其length属性。在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() {};

在这里,您可以通过doSomething()访问doOther()this.array中的数组。

答案 5 :(得分:0)

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