AshHeskes AshHeskes -3 years ago 115
Javascript Question

Javascript Square Bracket Notation Multiple Dynamic Properties

This may sound a bit unusual, I've never needed to use square bracket notation in this way before, and racking my brains I can't think of a way to produce the desired outcome.

I'm implementing a callback wrapper to maintain the reference of

this
when passing methods as callbacks

e.g.

foo.prototype.wrap = function(name){
var wrapper,
self = this;

wrapper = function(){
self[name](arguments);
};

return wrapper;
};

// usage

foo.wrap('bar');

// executes foo.bar maintaining 'this' as a reference to foo


The issue I'm having is that foo has some nested methods

e.g.

foo.bar.close();


I'm trying to figure out a way to make the wrap method support nested methods

e.g.

foo.wrap('bar.close')

// or

foo.wrap('bar','close');


So the
foo.wrap
function would need to dynamically add the square brackets corresponding to the length or the arguments passed in.

e.g.

self[x][y][z](arguments);


I can't think of a way to do this. Any ideas ?

I have a sneaking suspicion this isn't possible though.

Answer Source

I must be having one of those days where you forget everything :)

While @NilColor's answer is correct, and I did know it I just wasn't thinking with the correct hat on.

Anyway I decided that I still like the idea of having a wrapper that requires a bit less specificity when you attach it to your objects. And is a bit less verbose.

So I wrote it along with my original line of thinking, you might like it.

myObj.wrap = function(path, context){ 
    var wrapper,
        method = ( typeof path != 'string' && context )? path : this,
        context =  (typeof path === 'object' && context === undefined)? 
            path : (context || this);

    if (typeof path === 'string'){
        path = path.split('.');

        for ( var i = 0; i < path.length; i++ ){
            method = method[path[i]];
            if ( context === true  )
                context = ( i === path.length - 2 )? method : context; 
        };
    };

    wrapper = function(){
        method.apply(context, arguments);
    };

    return wrapper;
}

usage:

Bind any number of nested methods to myObj

    myObj.wrap('foo') //binds myObj.foo to myObj

// or

    myObj.wrap('foo.bar') //binds myObj.foo.bar to myObj

//or if myObj is a function

    myFunc.wrap() // binds myFunc to myFunc

Bind a method of myObj to another object

    myObj.wrap('foo.bar', someObj) //binds myObj.foo.bar to someObj

//or if myObj is a function

    myFunc.wrap(someObj) //Binds myFunc to someObj

Bind a nested method to it's parent

    myObj.wrap('foo.bar', true) // binds myObj.foo.bar to myObj.foo

Use as a helper

    myObj.wrap(someFunc, someObj) //binds someFunc to someObj

If you looking for an answer to the original question not in the context of method binding.

myObj.getProps = function(path, context){
var context = context || this;
    path = path.split('.');


for ( var i = 0; i < path.length; i++ ){
            context = context[path[i]];
    };

    return context;
};

Usage:

attach to an object or as a standalone function

Get the properties

myObj.getProps('foo.bar') // returns mayObj.foo.bar

Give it a context object

myObj.getProps('user.name', myAccounts) // returns myAccounts.user.name

to use it as a standalone function replace

myObj.getProps = function(path,context){....}

with

function getProps(path,context){....}

Note

If using it as a standalone function you will need to remember that it will start looking from the scope of this. So if it's defined in the global scope you need to provide full paths.

e.g.

getProps('myObj.foo.bar')

You can still use the context selector to change the reference object.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download