Javascript Square Bracket Notation Multiple Dynamic Properties

孤街浪徒 提交于 2019-12-07 23:32:51

问题


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.


回答1:


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.




回答2:


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?



来源:https://stackoverflow.com/questions/7146899/javascript-square-bracket-notation-multiple-dynamic-properties

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!