9

i have eval function, which needs to execute javascript from php. but i need to pass element, so i can put mouse over tips on the link user clicked on.

var globalEval = function globalEval(src, element) {
        if (window.execScript) {
            window.execScript(src);
            return;
        }
        var fn = function(element) {
            window.eval.call(window,src);
        };
        fn(element);
    };

im using following way to pass $(this) element

globalEval(js_code, $(this));
// js_code is = alert(element);

i get error of undefined element, which is defined in globalEval(); how can i fix this?

Basit
  • 16,316
  • 31
  • 93
  • 154
  • If I'm correct in assuming `src` is always a string, what happens if you do `window.eval.call(window,'(function (element) {'+src+'})')(element);`? – Paul S. Dec 16 '12 at 22:42
  • @PaulS. ok i will try it and post back. – Basit Dec 16 '12 at 22:43

3 Answers3

12

This is a scoping issue as the global eval isn't invoking the code in the same scope as the variable element. If you must use eval even though eval is evil, you'll have to do it in a way that lets you invoke your code in the environment you want. One way to do this is to wrap it as an anonymous function which you give parameters for the environment variables of choice.

For example

window.eval.call(window,'(function (element) {'+src+'})')(element);

This means the src string is parsed but not invoked by the eval as it returns an anonymous function. You then invoke it, passing your data, in this case element.

Test it with var element = document.body, src = 'console.log(element.tagName)'; and you'll see it log "BODY". Please note that if you want to set global variables (or functions) this way they have to be stated as global explicitly (window.foobar = ...) or they will be GCd after the anonymous function finishes.

Community
  • 1
  • 1
Paul S.
  • 64,864
  • 9
  • 122
  • 138
  • 1
    Why not just local `eval(src)`, it would pick up `element` – Esailija Dec 16 '12 at 23:08
  • @Esailija Because I like to over-complicate things. No, the way in my answer means you specify the environment by **passing variables** and protect your current environment (because function is ByVal, a change such as `element = otherElm` doesn't effect where you invoked it) whereas a local `eval(src)` would use the current environment. There are other options it gives you about invoking it (e.g. var-ing it / using `.call`). I'm not saying `eval` is ever "safe", but at least this way means you can call in the environment you want (assuming `src` is valid JavaScript). – Paul S. Dec 16 '12 at 23:17
  • @PaulS. Thanks alot. this works fine now :). btw will this work also window.execScript('(function (element) {'+src+'})')(element); ? – Basit Dec 16 '12 at 23:19
  • 2
    You should use the [Function constructor](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function) instead: It reports (syntax) errors better. – geocar Dec 16 '12 at 23:20
  • @geocar +1 because I agree, but doing that doesn't involve `eval`, which isn't OP's question. – Paul S. Dec 16 '12 at 23:23
  • @PaulS. what you suggest on using? eval or function constructor and if function constructor, will there be any difference or anything might stop working in feature or dynamic javascript code from php? – Basit Dec 16 '12 at 23:23
  • @Basit I'd avoid `eval` wherever possible. As I mentioned in my answer, eval is evil. In a best case scenario you shouldn't be passing any script to be invoked this way (as mentioned by Esailija, I think?), and only pass data (e.g. as [JSON](https://developer.mozilla.org/en/docs/JSON)) – Paul S. Dec 16 '12 at 23:27
  • @PaulS. but is new function() is supported by older browsers? – Basit Dec 16 '12 at 23:37
  • `new Function` is supported in all major browsers and [should be supported in IE back to IE6](http://msdn.microsoft.com/en-us/library/ie/x844tc74(v=vs.94).aspx). – Paul S. Dec 16 '12 at 23:45
  • @PaulS. Thank you soo much for the help. the browser compatible question came, because i on Firefox documentation said ? ?, so i was worried. but thank you. – Basit Dec 16 '12 at 23:53
7

If all you want to do is have this set when you evaluate some code, try:

// Code you want to evaluate
var code = 'return this.whatever'

// What you want "this" bound to:
var that = { whatever: 69 }

// Now do this:
var result = new Function(code).call(that)

Using the Function constructor means you'll get what you expect; There is a lot of baggage that comes along with global eval, some of which might surprise you. Best to avoid it if you don't need it.

Now if you really wanted to call it element, the Function constructor can do that as well:

code = 'alert(element)'
var use_element = 69
result = new Function("element", code).call(this, use_element)
geocar
  • 9,085
  • 1
  • 29
  • 37
  • i like your suggestion. just wondering if its supported by older browsers and if any dynamic code of javascript from php will execute fine wihtout errors? – Basit Dec 16 '12 at 23:27
  • @Basit - See http://aptana.com/reference/api/Function.html for browser compatibility. PHP doesn't enter into it, you can simply do something like: `result = new Function("element", = json_encode($code) ?>).call(this, use_element)` if you like. – geocar Dec 20 '12 at 17:18
0

if the callback function is in the same dom, then set a global variable as repo before eval which will keep the variable. then use the global variable in the function you gonna call.

var response_repo;
function someFunc($callback){
 ....
 success: function(result) {
            response_repo = result;
            eval($callback+'();');
        },
 ....
 }


 callBackFunc(){
  $data=response_repo;
 }