A "does global variable exist" function

R

RobG

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.
 
D

David Mark

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? :)
 
R

RobG

doesGlobalVarExist('v'); // true regardless

As is:

doesGlobalVarExist();

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


[...]
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.

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.
 
R

RobG

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.
 
D

David Mark

As is:

    doesGlobalVarExist();

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

Yes. Passing no argument at all would not lead to defined results.
[...]


Use the Function constructor.

Ok, using:

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

seems to be a solution.

To a non-problem of course. :)
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'

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":

You did see the disclaimer, right? Do not use that code. It is not
based on standards and is known to fail in some ES3 implementations.
  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.

Neither did the Dojo authors. ;) The fact is that it doesn't work
(not cross-browser anyway) and should never be expected to work
outside of ES5.
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]);

Different browsers do different things with that. I posted it as an
example of the bit of ES5 you quoted. I assume they put that clause
in there to prop up faltering libraries and other junk code prevalent
on the Web.
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?

Which spec are we talking about? ES5? ES3 says that global.eval may
well throw an exception and guarantees nothing about its behavior.
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.

In ES3 there is no telling. There have been charts published here
before detailing what the various browsers do with such a call. Even
if they were all observed to do the same thing, it is best to avoid it
as the specs make no promises as to its behavior.
 
D

David Mark

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.

See my previous follow-up. The use of global.eval is unpredictable.
That's why it was one of the first things I tried to yank out of
Dojo's loader (of course, it's still in there, but they do have some
very nice new background graphics to compensate).
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.

There's nothing related to this in that spec to conform to. That's
the problem.
 
A

Andrea Giammarchi

while in IE we have

function isGlobal(what) {
return execScript('"' + what + '" in this');
}

in ES3 we can generally use

function isGlobal(what) {
return what in (function(){return this}());
}

but since in ES5 and "use strict" this won't be the global object ...

// compatible ES5 and "use strict"
var isGlobal = function (what) {
function $isGlobal(what) {
return what in context;
}
var
script = document.createElement("script"),
context = document.documentElement
;
script.text = "this.$isGlobal=this;";
context.insertBefore(script, context.firstChild);
context.removeChild(script);
script = null;
context = $isGlobal;
delete context.$isGlobal;
context.isGlobal = (isGlobal = $isGlobal);
return isGlobal(what);
};

Regards,
Andrea Giammarchi
 
A

Andrea Giammarchi

On Jul 29, 3:56 am, Andrea Giammarchi

uhm, there is a typo in the global name, call it _isGlobal or the
context will be the function ...
 
R

Ry Nohryb

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;
      }
  }

And what's with falsy values ?
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?

You never know for sure. Browser makers seem to be changing this every
day. But to be sure you could do:

(new Function("p", "return eval(p)"))(evalInput);
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.

var indirectEval= window.eval;
indirectEval();
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.

Why not:

"k" in window
--> false
var k;
--> undefined
"k" in window
--> true

?
 
D

David Mark

while in IE we have

Scene missing?
function isGlobal(what) {
    return execScript('"' + what + '" in this');

}

Why wouldn't you just use a function constructor (as described
previously?)
in ES3 we can generally use

function isGlobal(what) {
    return what in (function(){return this}());

}

but since in ES5 and "use strict" this won't be the global object ...

According to the bit of ES5 that Rob quoted, this is trivial to do in
ES5 with global.eval. And again, why not just use the Function
constructor?
// compatible ES5 and "use strict"

Is this meant to run in the global context?
var isGlobal = function (what) {
    function $isGlobal(what) {

Please don't use "$" as a function name prefix.
        return what in context;
    }
    var
        script = document.createElement("script"),
        context = document.documentElement
    ;
    script.text = "this.$isGlobal=this;";

As I know we've discussed (remember Randy Webb?) this is not cross-
browser code.
    context.insertBefore(script, context.firstChild);

Never insert scripts outside of the head or body. Why would you
attempt to manipulate the DOM in such a non-standard way. Again, not
cross-browser compatible.
    context.removeChild(script);
    script = null;

That line is a waste of time.
    context = $isGlobal;

A function declared locally above.
    delete context.$isGlobal;

So, at this point your $isGlobal function has a property called
$isGlobal and you want to delete it? I don't see it, nor do I see
where this is supposed to be going.
    context.isGlobal = (isGlobal = $isGlobal);
    return isGlobal(what);

I'm literally speechless. :(

Do not use this code under any circumstances.
 
D

David Mark

And what's with falsy values ?








You never know for sure. Browser makers seem to be changing this every
day. But to be sure you could do:

(new Function("p", "return eval(p)"))(evalInput);

We covered that one, Jorge.
var indirectEval= window.eval;
indirectEval();

Why do you insist on using that host object in lieu of the Global
Object?
Why not:

"k" in window
--> false
var k;
--> undefined
"k" in window
--> true

You know full well why not. :(

Or do you? At the very least, you've been told a thousand times.
There's no standard that says the window object *is* the Global
Object. You are simply making bad inferences (from observations of a
necessarily limited set of user agents).

The window object may mirror global properties and setting its
properties may set properties on the Global Object. It may appear in
every way (that you've had time to test) to be the Global Object, but
there is no way to know for sure what is going on behind the scenes
with that host object and not a shred of specification anywhere that
says it must behave as you assume.
 
D

David Mark

On Jul 29, 3:56 am, Andrea Giammarchi

uhm, there is a typo in the global name, call it _isGlobal or the
context will be the function ...

Glad we got that cleared up. However...
 
R

Ry Nohryb

You know full well why not.  :(

Or do you?  At the very least, you've been told a thousand times.
There's no standard that says the window object *is* the Global
Object.  You are simply making bad inferences (from observations of a
necessarily limited set of user agents).

The window object may mirror global properties and setting its
properties may set properties on the Global Object.  It may appear in
every way (that you've had time to test) to be the Global Object, but
there is no way to know for sure what is going on behind the scenes
with that host object and not a shred of specification anywhere that
says it must behave as you assume.

"In addition, for some languages, such as ECMAScript [ECMAScript], the
Window interface is implemented by the object that provides the global
namespace for script execution"

http://www.w3.org/TR/Window//#introduction
 
D

David Mark

You know full well why not.  :(
Or do you?  At the very least, you've been told a thousand times.
There's no standard that says the window object *is* the Global
Object.  You are simply making bad inferences (from observations of a
necessarily limited set of user agents).
The window object may mirror global properties and setting its
properties may set properties on the Global Object.  It may appear in
every way (that you've had time to test) to be the Global Object, but
there is no way to know for sure what is going on behind the scenes
with that host object and not a shred of specification anywhere that
says it must behave as you assume.

"In addition, for some languages, such as ECMAScript [ECMAScript], the
Window interface is implemented by the object that provides the global
namespace for script execution"

http://www.w3.org/TR/Window//#introduction

How many times do we have to go over this? For one, that's obviously
not the language specification you have cited. That's an offhand
reference to a non-normative part of the language specs. In other
words, it's worthless, except to confuse people who don't know any
better. Are you among those people or simply trying to notch some
sort of hollow "victory" here?

I expected better from you, El Abuelo. Every time I give you the
slightest shred of credit, you make me regret it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top