1

I'd like be able to call a function like item_edit.say hello passed as a string on the window object (like the last line of the following):

var arc={ view: { item_edit: {} } };

arc.view.item_edit={
  say_hello: function(){
    alert('hello there');
  }

}

var f_name='say_hello';
var g_name='item_edit.say_hello';

var str=window.arc.view.item_edit[f_name]();  // <- this works
var str2=window.arc.view[g_name]();  // <- this is what I'm interested in; curently doesn't work

any ideas on how to get this to work?

thx in advance

edit #1 I guess I should add that probably don't want to be doing eval although the more I look at it, that might be what makes sense (and is in fact what eval was made to do).

timpone
  • 19,235
  • 36
  • 121
  • 211

3 Answers3

1

Sure. The Google closure library does something like this in its goog.provide function when not optimized by the compiler.

function callDotted(obj, path, args) {
  var parts = path ? path.split('.') : [];
  var i, n = parts.length;
  for (i = 0; i < n - 1; ++i) {
    obj = obj[parts[i]];
  }
  var fn = i < n ? obj[parts[i]] : obj;
  return fn.apply(obj, args);
}

and then on browsers where Date.now returns the current timestamp,

callDotted(window, 'Date.now', [])

returns the current timestamp.

Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
0

Here's one way using .reduce().

var str2 = g_name.split('.').reduce(function(obj, key) {
    return obj[key];
}, window.arc.view);

You'll need to shim it for older browsers, and introduce safety checks if you want.


If you do this a lot, I'd add the function to your library so you can reuse it.

function keyToObj(obj, key) {
    return obj[key];
}

Then use it like this:

var str2 = g_name.split('.').reduce(keyToObj, window.arc.view);

As @MikeSamuel pointed out, there's an issue with the this value of the executed function when using this approach.

To resolve this, we could make another version that's suited specifically for method invocations.

function keyToMethod(obj, key, i, arr) {
    return i === arr.length - 1 && typeof obj[key] === "function"
                              ? function() {
                                    return obj[key].apply(obj, arguments);
                                }
                              : obj[key];
}

Now our function returns a function that invokes the method from the proper object.

var str2 = g_name.split('.').reduce(keyToMethod, window.arc.view)();

We could further enhance the returned function to check to see if the this value is the default value, and use the provided value if not.

Community
  • 1
  • 1
I Hate Lazy
  • 47,415
  • 13
  • 86
  • 77
-1

How about this:

var str2 = eval('window.arc.view.' + g_name + '()');
James Gaunt
  • 14,631
  • 2
  • 39
  • 57
  • This answer is correct, so I don't think it deserves the DV, but I do think it's a good idea to give some qualifications when suggesting `eval`. – I Hate Lazy Nov 08 '12 at 18:30
  • 3
    Eval is not 'evil'. It's perfectly valid javascript and used in almost all libraries (so probably on most pages of the web). Of course it has performance issues, but most javascript is not time critical. The mindset that writes off entire aspects of languages based on dogmatic adherence to anecdotes from the internet is far more damaging to the integrity of modern software. – James Gaunt Nov 08 '12 at 18:31
  • thats what JSON.parse is for. – GottZ Nov 08 '12 at 18:34
  • @Jan - I just did. The code is simple, easy to read and easy to maintain. Not all coding is about eeking out the last few cycles. Far more time is lost in debugging and correcting obscure 'fast' code than is lost on code that runs eval. – James Gaunt Nov 08 '12 at 18:34
  • its not about cycles or anything. its about the fact that eval executes your stuff in the global scope and besides that is the number one target for XSS – GottZ Nov 08 '12 at 18:35
  • Where is the XSS risk in this code? If you wrote off any language construct that can be used badly or introduce a security hole you'd have no language left. BTW many if not most JSON.Parse implementations use eval. Anyway - you're of course entitled to your opinion on the use of any part of the language, it was just the use of the word 'evil' that made me think you were just regurgitating nonsense. – James Gaunt Nov 08 '12 at 18:37
  • @user1689607, the answer is not correct. Try it when `g_name` is `"foo.bar,baz"`. The comma is treated by `eval` as an operator, not part of the name. This kind of subtle undefined behavior on slightly widgy inputs should be avoided, and it all comes about because the implementation is not simple but pulls in this hugely complex Javascript interpreter. – Mike Samuel Nov 08 '12 at 18:38
  • well. it does not matter because it would still be run in the global scope. what matters is that javascript is the most missunderstood language ever made. – GottZ Nov 08 '12 at 18:38
  • @Jan-StefanJanetzky Sure it does matter. We could also be worried about SQL injection attacks, but this code has nothing to do with databases. So why worry about XSS when the code is controlled? – Ian Nov 08 '12 at 18:39
  • ok. so simple question: why would you want to do that if you could do it right? – GottZ Nov 08 '12 at 18:39
  • you will loose the current scope when using eval. thats why almost every starter fails at using setTimeout and other evaluating methods correctly. – GottZ Nov 08 '12 at 18:40
  • 2
    telling people to use eval will guide them to problems they cannot fix themself. thats WHY eval IS evil. – GottZ Nov 08 '12 at 18:41
  • 1
    @JamesGaunt, The [E language](http://en.wikipedia.org/wiki/E_%28programming_language%29#Philosophy) allows flexible serialization and deserialization and dynamic code without giving up decomposable security. It shows that you can have your cake security-wise and eat it too. "The entire language is designed with secure computing in mind; this is accomplished chiefly by strict adherence to the object-oriented computing model, which in its pure form has properties that support secure computing ... to enable software components to co-operate even if they don't fully trust each other.""" – Mike Samuel Nov 08 '12 at 18:41
  • @MikeSamuel: I think you know that the solution works given the requirements. Of course it will break given different requirements. I don't know what point you're trying to make, but to be honest, an answer that suggests `eval` with no caveats is no more objectionable to me than the banal *"eval is evil"* comments. – I Hate Lazy Nov 08 '12 at 18:46
  • in my opinion even alert and prompt should be removed from the browser stack. aswell as syncronous ajax. this would hopefully make some people understand this beautiful language. – GottZ Nov 08 '12 at 18:46
  • thx for answers guys, tried upvoting; think it's a reasonable answer that would / could /should work – timpone Nov 08 '12 at 18:50
  • @user1689607, I agree that "eval is evil" is simplistic and silly, but I can only *know* that a solution is correct by matching it against a specification. With `eval` you've got this huge iceberg where the visible part is small, but there's a huge portion below the water. To verify that the solution that uses `eval` is correct you have to reason about all of that iceberg even when the specification is small. A single split and for loop can be matched against a small informal specification, but the entire JS parser cannot. Code so that your correctness argument is simple & small. – Mike Samuel Nov 08 '12 at 19:02
  • thx for answers; probably not a very well-written question on my end. Was just looking for a quick way to put code into different locations. Helped me a lot. thx – timpone Nov 08 '12 at 19:13
  • 1
    @MikeSamuel: Just to be clear, I'm not arguing for `eval` to be used here. I'm arguing only against knee-jerk reactions to `eval`. I hold them with the same esteem as I do the *"you should totally use jQuery for that"* comments. :-) – I Hate Lazy Nov 08 '12 at 19:26
  • @Mike 'With eval you've got this huge iceberg where the visible part is small, but there's a huge portion below the water.' - You're kind of describing all of modern programming. Do you know how complex a browser is, and underneath that the OS, and the bios, and machine code. You can't perform any sort of static analysis on any code of any non-trivial complexity. If you think excluding eval is somehow comforting then fine - but it's a false comfort. – James Gaunt Nov 08 '12 at 19:28
  • @Jan - 'telling people to use eval will guide them to problems they cannot fix themself.' - telling people to write software, particularly in javascript - will do the same - so all software must be evil too? Actually I can buy into that one. – James Gaunt Nov 08 '12 at 19:31
  • @JamesGaunt, Yes, on many computers there are complex processes running, but there are still ways to write code that is not entangled with those complex processes. – Mike Samuel Nov 08 '12 at 19:59
  • 1
    @user1689607, I think we agree then. My rule of thumb is, if you have a string of Javascript from a source you trust and you need it to bind to variables in the current scope then use `eval`. Conversely, if what you have is not a string of JavaScript, or is not from a trusted source, or shouldn't bind to variables in the current scope, then don't use `eval`. – Mike Samuel Nov 08 '12 at 20:02
  • @JamesGaunt, i wish you a happy life using eval. i will continue writing debugable, fast and reliable code. its your choice but it sadens me that there actually exist people supporting eval. you are the first person i ever talked to, that claims that eval is usefull. people who use javascript strings mostly dont know about json and what it does and is. – GottZ Nov 08 '12 at 20:22