How do I create a jQuery-like $ () wrapper function?

I am creating a small code plugin that allows you to do some things with arrays. I don't want to add functions to the array object using prototype construct, I want people to be able to do something like:

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

      

Thus, leaving the regular array object unchanged.
So I came up with the following construct (which was inspired by the jQuery source code):

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.
    }
}

      

However, this doesn't work (obviously). What should happen in the init () function?

The error right now is when trying:

 arrayFunction(array).someSpecialArrayFunction();

      

does it say someSpecialArrayFunction () is not a function?

How to do it?

edit
Yes, this is a really simplified example. The actual thing has a few more methods.

Also, I just know how great it would be if it also supported chaning, how would you do that?

0


source to share


6 answers


Or simply:

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

      



Be careful with this though, if you have too many methods it is probably better to use a prototype.

+2


source


I'm not sure if this is the best syntax to get what you want, but I suppose this is an abbreviated example ... This is a quick way to get it to work anyway.



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();

      

+1


source


sktrdie's answer looks good.

Another thing to consider is using a flyweight pattern instead of returning an instance of a new object with each call to your wrapper. The ExtJS function Ext.fly does this; it returns a globally shared instance.

0


source


Try something like this:

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);
        },
    };
}

      

Calling with something like

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

      

should return the average of the array elements.

0


source


If you don't want t change Array.prototype

, the only real possible solution is to add methods to a specific array object:

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

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

      

Please note that I do not define doSomething()

and doOther()

inside wrap()

- otherwise we would create new functional objects for every call that is extremely inefficient.

A more complex option would be the following:

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;
    }
}

      

Here we are creating a new wrapper object (and not adding properties to the array itself). The wrapper object will still have access to all properties of the array. There's a small catch though:

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?!

      

Usage foo[4] =

will result in access to our wrapping object, and the properties 4

and 5

will be set there, not in the array, so its length property will not be updated. In IE, the call will push()

no longer be able to update the array correctly ...

If your wrapper object doesn't need to "redirect" calls to the array object, there are other solutions using closures. The first sktrdie example is one of them. I would object to them because they will create new function objects and with every call. What will i do:

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() {};

      

Here you can access the array in doSomething()

and doOther()

through this.array

.

0


source


Just extend the Array object and add your fancy methods to your object. Then you can make a bridge function that takes an array as an argument and returns your version of the array. This method is much simpler and more useful.

0


source







All Articles