0

This is not related to this as such func.apply and func.call do not apply (no pun intended).

I need to pass the current context of a function to another function, by which I mean I need access to the named local variables within a function.

here is a somewhat contrived example:

function doSomething(f){
    eval(f)
}
function test(callback){
    doSomething("callback.apply(1, 2)")
}
test(function(a, b){
    console.log(a + b);
})

How can I pass the local variable callback to doSomething so it is available to eval - I recognise this is a contrived example. Is this even possible?

I know that nested contexts carry over, so if I were to declare doSomething within test this would just work. However that does not help me.

Zack Newsham
  • 2,810
  • 1
  • 23
  • 43
  • At first, I thought that it was possible to access the parent context, but [it's not](http://stackoverflow.com/questions/6332017/how-to-get-this-value-of-caller-function). Why is a problem passing `this` to the function? Should a global stack of contexts work for your problem? – Wikiti Jun 27 '16 at 17:06
  • What is your actual problem? No, it is never possible to access arbitrary function contexts. – Bergi Jun 27 '16 at 17:08
  • Have a look at [this snippet](http://stackoverflow.com/a/24032179/1048572) which uses a form of eval that also allows to inject particular things in the evaluation scope – Bergi Jun 27 '16 at 17:09
  • @Wikiti - a global stack would likely fix this, however this is something I need to apply retroactively to libraries. My only thought currently is to parse the function and collect all locally defined variables and do a `this[varName] = varName` type statement immediately after they are applied. The issue is that I'd have to then replace the callback with `this[callback]` - it gets messy – Zack Newsham Jun 27 '16 at 17:09
  • Do you really need `eval` in this case if you are not generating code on the fly? why not to create closure `function() { callback(1,2); }` and pass that to `doSomething`, and inside `doSomething` you just call that function instead on invoking eval. – csharpfolk Jun 27 '16 at 17:13
  • @csharpfolk my example isn't great - it doesnt highlight the greater case - which is that I need access to named local variables from an old context in a new context – Zack Newsham Jun 27 '16 at 17:20
  • @Bergi - I'm looking at that post now, it may just do the trick. The actual problem is that I need to access local variables in a new scope - One example would be if I were to split a function into two parts - whre the second runs in a `Worker` - it would still run sequentially. I'd need to have access to the variables defined in the first worker, in the second - when it was called – Zack Newsham Jun 27 '16 at 17:24
  • @ZackNewsham can you improve your question to provide more info about your problem? Do you want to access local variables via string e.g. `doSth('var1.foo.bar')` in some other function - then this will not be possible since there is nothing in JS that out of the box is holding all local variables, you would be force to pass them as additional parameters... – csharpfolk Jun 27 '16 at 17:34
  • @ZackNewsham: To pass anything into a worker, you have to serialise it. To serialise functions, they must not be closures. You have to be explicit about what you pass. There is no "get reference to scope" thing that does this for you. – Bergi Jun 27 '16 at 17:45
  • @Bergi - I thought this might be the case. The issue I was having didnt even involve workers - but that was the ultimate goal. I know you can pass functions, including annonymous to a worker, but they have to be explicit. I was hoping there was a better way of doing this than assigning all the local variables to an object and passing that to the worker. But I suspect that is what I'll have to do - I really liked that code snippet though. Hopefully there is a way I can incorporate that. – Zack Newsham Jun 27 '16 at 17:50

2 Answers2

1

If you're really wanting to use eval... you can create an IIFE in string format, and pass in the arguments that you want almost the way you were doing it before:

function doSomething(f) {
  eval(f)
}

function test(callback) {
  doSomething('(' + callback.toString() + ')(1, 2)');
}

test(function(a, b) {
  console.log(a + b);
})
KevBot
  • 17,900
  • 5
  • 50
  • 68
  • Clever work-around. This is basically what browser drivers like phantom.js and selenium do. – slebetman Jun 27 '16 at 17:24
  • this would work for the specific case asked - but not the general case. I should have been more generic in my question - see comment above. – Zack Newsham Jun 27 '16 at 17:31
-1

bind will work for u

function doSomething(f){
    eval(f());
}
function test(callback){
    doSomething(callback.bind(null,1,2))
}
test(function(a, b){
    console.log(a + b);
})
vinay pandey
  • 133
  • 4