Prev: FAQ Topic - Why does simple decimal arithmetic give strange results? (2010-07-29)
Next: validate 3 fields
From: David Mark on 29 Jul 2010 01:53 On Jul 29, 1:19 am, 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 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. ;-) Yes. Passing no argument at all would not lead to defined results. > > [...] > > > > > > 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. To a non-problem of course. :) > > > > 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": 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.
From: David Mark on 29 Jul 2010 01:56 On Jul 29, 1:27 am, RobG <rg...(a)iinet.net.au> wrote: > 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. 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). > > > 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. There's nothing related to this in that spec to conform to. That's the problem.
From: Andrea Giammarchi on 29 Jul 2010 03:56 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
From: Andrea Giammarchi on 29 Jul 2010 04:16 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 ... <andrea.giammar...(a)gmail.com> wrote: > 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
From: Ry Nohryb on 29 Jul 2010 04:24
On Jul 29, 4:51 am, 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; > } > } 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 ? -- Jorge. |