The black magic of eval loses the sphere

disclaimer I do not support the use of eval, and I do not use it when writing code.

I am playing out the logic in a legacy project and was running into some very strange behavior with eval and would like to know under the hood an explanation of why this behavior exists.

var baz = function(cb) {
    cb('asdf');
}

function foo(qux, callback) {
    setTimeout(function() {
        // eval(callback('asdf')); // works
        // eval(baz(callback)); // works
        // eval(qux + "(" + callback + ")"); // resolve is undefined
    });
}

function bar() {
    return new Promise((resolve, reject) => {
        try {
            foo('baz', function(response){
                resolve(response);
            });
        } catch (e) {
            reject(e);
        }
    });
}

function init() {
    bar()
    .then(response => {
        console.log(response)
    })
    .catch(e => console.log(e));

}

init();

      

I wrote three examples of different ways to use eval, commented out the function foo

The third example doesn't work. This is the example I'm working on since our legacy code works. I know there are other ways to solve this problem. My solution was to just rewrite the function and not use eval at all.

My question is very precise, why does eval lose scope when passing a function name as a string, but it doesn't lose scope when passing an actual reference to the same function?

Here is a jsfiddle: https://jsfiddle.net/tkcjay4x/6/

+3


source to share


1 answer


I have to admit, the title scares me a little. If I understand this "black magic", does it make me an evil sorcerer?

When you execute eval(baz(callback))

, baz

calls callback

, and eval

executes the return value baz

, which is undefined

. eval(undefined)

equal eval('undefined')

, which is equal undefined

. So, in this case, using eval

essentially no-op - just doing it baz(callback)

will give the same result.



When you execute eval(qux + "(" + callback + ")")

, it qux + "(" + callback + ")"

is evaluated up to 'baz(function(response){ resolve(response); })'

. When you pass this value to eval, the code tries to access a named function resolve

that is not in the current scope. This is why it doesn't work. If you call a function directly, it can access variables that were present in the scope in which it was defined, but if you convert the function to a string and pass it in eval

, it can only access variables from the current scope.

+8


source







All Articles