From: RobG on

I stumbled across a function that tests if a global variable exists or
not, my version of the code is below. Other than the obvious
irrelevance of such a function (a simple typeof test should be
sufficient in every case I can imagine), and that the use of
try..catch and eval should be limited as much as possible, are there
any significant issues with it?


function doesGlobalVarExist(v) {

try {
eval(v);
return true;

} catch(e) {
return false;
}
}


Given the description of the eval function in ECMA-262 ed 3 (ES 3) §
15.1.2.1 and eval code in § 10.1.2, it seems that when using a
"namespace" with functions initialised from an anonymous function it
is impossible to use eval to run code with global scope, e.g.:

var zz = 'Global zz';

var fn = (function() {
var zz = 'Local zz';
return function(v) {
return eval(v);
}
})();

alert(fn('zz')); // shows "Local zz"

The above always resolves to the local zz because the calling context
is placed on eval's scope chain when it is called, so the global zz is
"shadowed". Can eval code be run as global code using this scenario?
Are there cases where that is desirable (such as a
"doesGlobalVarExist" function)?

There is a statement in ES5 §10.4.2 that says:

"...if the eval code is not being evaluated by a direct call
(15.1.2.1.1) to the eval function then...Initialize the
execution context as if it was a global execution context"

I can't see how to call eval other than as a direct call.

Lastly, ES 3 says:

"if the eval property is assigned to, an EvalError
exception may be thrown"

Neither browser does, they allow assignments to eval.


--
Rob
From: David Mark on
On Jul 28, 10:51 pm, RobG <rg...(a)iinet.net.au> wrote:
> I stumbled across a function that tests if a global variable exists or
> not, my version of the code is below. Other than the obvious
> irrelevance of such a function (a simple typeof test should be
> sufficient in every case I can imagine), and that the use of
> try..catch and eval should be limited as much as possible, are there
> any significant issues with it?
>
>   function doesGlobalVarExist(v) {
>
>       try {
>           eval(v);
>           return true;
>
>       } catch(e) {
>           return false;
>       }
>   }


doesGlobalVarExist('v'); // true regardless

You could use:-

eval(arguments[0]);

....but as you noted, there's no practical use for this.

>
> Given the description of the eval function in ECMA-262 ed 3 (ES 3) §
> 15.1.2.1 and eval code in § 10.1.2, it seems that when using a
> "namespace" with functions initialised from an anonymous function it
> is impossible to use eval to run code with global scope, e.g.:
>
>   var zz = 'Global zz';
>
>   var fn = (function() {
>       var zz = 'Local zz';
>       return function(v) {
>           return eval(v);
>       }
>   })();
>
>   alert(fn('zz')); // shows "Local zz"

Use the Function constructor.

>
> The above always resolves to the local zz because the calling context
> is placed on eval's scope chain when it is called, so the global zz is
> "shadowed". Can eval code be run as global code using this scenario?
> Are there cases where that is desirable (such as a
> "doesGlobalVarExist" function)?
>
> There is a statement in ES5 §10.4.2 that says:
>
>  "...if the eval code is not being evaluated by a direct call
>   (15.1.2.1.1) to the eval function then...Initialize the
>   execution context as if it was a global execution context"

That came years too late for some libraries I can think of. :)

>
> I can't see how to call eval other than as a direct call.

// NOTE: Do NOT use this as it may require ES5

var global = this, testing = '123';

(function(v) {
var testing;

window.alert(global.eval(v)); // '123'
})('testing');

That will work in some modern browsers without ES5. It's not
something to depend on though. The Function constructor should be
used instead.

>
> Lastly, ES 3 says:
>
>  "if the eval property is assigned to, an EvalError
>   exception may be thrown"
>
> Neither browser does, they allow assignments to eval.

Neither browser? :)
From: RobG on
On Jul 29, 1:13 pm, David Mark <dmark.cins...(a)gmail.com> wrote:
> On Jul 28, 10:51 pm, RobG <rg...(a)iinet.net.au> wrote:
>
>
>
> > I stumbled across a function that tests if a global variable exists or
> > not, my version of the code is below. Other than the obvious
> > irrelevance of such a function (a simple typeof test should be
> > sufficient in every case I can imagine), and that the use of
> > try..catch and eval should be limited as much as possible, are there
> > any significant issues with it?
>
> > function doesGlobalVarExist(v) {
>
> > try {
> > eval(v);
> > return true;
>
> > } catch(e) {
> > return false;
> > }
> > }
>
> doesGlobalVarExist('v'); // true regardless

As is:

doesGlobalVarExist();

but that would be covered by the documentation. ;-)


[...]
> > Given the description of the eval function in ECMA-262 ed 3 (ES 3) §
> > 15.1.2.1 and eval code in § 10.1.2, it seems that when using a
> > "namespace" with functions initialised from an anonymous function it
> > is impossible to use eval to run code with global scope, e.g.:
>
> > var zz = 'Global zz';
>
> > var fn = (function() {
> > var zz = 'Local zz';
> > return function(v) {
> > return eval(v);
> > }
> > })();
>
> > alert(fn('zz')); // shows "Local zz"
>
> Use the Function constructor.

Ok, using:

try {
Function('return ' + arguments[0] + ';')();
return true;
}...


seems to be a solution.


> > The above always resolves to the local zz because the calling context
> > is placed on eval's scope chain when it is called, so the global zz is
> > "shadowed". Can eval code be run as global code using this scenario?
> > Are there cases where that is desirable (such as a
> > "doesGlobalVarExist" function)?
>
> > There is a statement in ES5 §10.4.2 that says:
>
> > "...if the eval code is not being evaluated by a direct call
> > (15.1.2.1.1) to the eval function then...Initialize the
> > execution context as if it was a global execution context"
>
> That came years too late for some libraries I can think of. :)

[...]
> > I can't see how to call eval other than as a direct call.
>
> // NOTE: Do NOT use this as it may require ES5
>
> var global = this, testing = '123';
>
> (function(v) {
> var testing;
>
> window.alert(global.eval(v)); // '123'
>
> })('testing');
>
> That will work in some modern browsers without ES5. It's not
> something to depend on though. The Function constructor should be
> used instead.

I actually tried something like that but the code wasn't doing what I
thought it was so it was discarded prematurely, here's a fixed version
that "works":

var fn = (function() {

var zz = 'Outer local zz';
var global = (function(){return this})();
return function(v) {

// var zz = 'Innner local zz';

try {
global.eval(arguments[0]);
return true;
} catch(e) {
return false;
}
}
})();

alert('fn zz: ' + fn('zz')); // false

But I don't understand why it works. The eval function is still called
from within another function, calling it as global.eval should just
change the value of the function's this keyword for property
resolution, shouldn't the enclosing activation object still be on the
scope chain and be involved in identifier resolution? As far as I can
see, it's the same as:

eval.call(global, arguments[0]);

which "works" also. The spec says "...if the eval code is not being
evaluated by a direct call [use global scope]", isn't global.eval a
direct call, and therefore should not be given global scope? The
variable object of the inner function (the one that calls global.eval)
seems to be on the scope chain - uncommenting the inner local zz
returns true.


> > Lastly, ES 3 says:
>
> > "if the eval property is assigned to, an EvalError
> > exception may be thrown"
>
> > Neither browser does, they allow assignments to eval.
>
> Neither browser? :)

Ooops, I had a sentence that said I was testing in Firefox and IE 6
only but I seem to have edited that out, so neither of those.


--
Rob
From: RobG on
On Jul 29, 3:19 pm, RobG <rg...(a)iinet.net.au> wrote:
> On Jul 29, 1:13 pm, David Mark <dmark.cins...(a)gmail.com> wrote:
> > On Jul 28, 10:51 pm, RobG <rg...(a)iinet.net.au> wrote:
[...]
> > > I can't see how to call eval other than as a direct call.
>
> > // NOTE: Do NOT use this as it may require ES5
>
> > var global = this, testing = '123';
>
> > (function(v) {
> >   var testing;
>
> >   window.alert(global.eval(v)); // '123'
>
> > })('testing');
>
> > That will work in some modern browsers without ES5.  It's not
> > something to depend on though.  The Function constructor should be
> > used instead.
>
> I actually tried something like that but the code wasn't doing what I
> thought it was so it was discarded prematurely, here's a fixed version
> that "works":

In Firefox but not IE 6.


>   var fn = (function() {
>
>       var zz = 'Outer local zz';
>       var global = (function(){return this})();
>       return function(v) {
>
>           // var zz = 'Innner local zz';
>
>           try {
>               global.eval(arguments[0]);
>               return true;
>           } catch(e) {
>               return false;
>           }
>       }
>   })();
>
>   alert('fn zz: ' + fn('zz'));  // false
>
> But I don't understand why it works. The eval function is still called
> from within another function, calling it as global.eval should just
> change the value of the function's this keyword for property
> resolution, shouldn't the enclosing activation object still be on the
> scope chain and be involved in identifier resolution? As far as I can
> see, it's the same as:
>
>     eval.call(global, arguments[0]);
>
> which "works" also. The spec says "...if the eval code is not being
> evaluated by a direct call [use global scope]", isn't global.eval a
> direct call, and therefore should not be given global scope?

In IE 6 it isn't given global scopie, it still returns true.

> The
> variable object of the inner function (the one that calls global.eval)
> seems to be on the scope chain - uncommenting the inner local zz
> returns true.

It seems the outer scope is omitted in Firefox but remains in IE. A
quirk that is unlikely to surface very often, but probably Firefox is
not conforming to ECMA-262 here.


--
Rob
From: Dmitry A. Soshnikov on
On 29.07.2010 6:51, RobG wrote:

<snip>

>
> There is a statement in ES5 �10.4.2 that says:
>
> "...if the eval code is not being evaluated by a direct call
> (15.1.2.1.1) to the eval function then...Initialize the
> execution context as if it was a global execution context"
>
> I can't see how to call eval other than as a direct call.
>

<http://dmitrysoshnikov.com/ecmascript/es5-chapter-2-strict-mode/#indirect-eval-call>

Dmitry.