开发者

Javascript Square Bracket Notation Multiple Dynamic Properties

开发者 https://www.devze.com 2023-03-30 00:01 出处:网络
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.

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 = functi开发者_运维技巧on(){
        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.


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.


A general concept of "binding" this is something like this:

function bind(method, context) {
      var args = Array.prototype.slice.call(arguments, 2);
      return function() {
            var a = args.concat(
                               Array.prototype.slice.call(arguments, 0));
            return method.apply(context, a);
      }
}

This way you'll get a reference to method with linked this (context). This way you can bind nested methods like this:

> foo = {}
> foo.a = function(){console.log('a'); console.log(this)}
> bar = {bar: 'yeah'}
> f = bind(foo.a, bar)
> f()
-> a
-> {bar: 'yeah', __proto__: Object}

Is it something you are looking for?

0

精彩评论

暂无评论...
验证码 换一张
取 消