JavaScript global object

R

Roman Ziak

Hello,

there were times when I used to be looking for a way to access
JavaScript Global object similar to those found in VBScript or PHP
($GLOBALS). At present this has only academic value for me. I was doing
research on JavaScript inheritance recently (simplifying it in
particular) and after reading 10.1.1, 10.1.3 and some other sections of
ECMA262 [1] I got a hint on accessing global object from different than
global scope.

Below is my example (please note that the host is WSH, feel free to
change WScript.Echo to your favourite output call):


myGlobal = this;

function AddVar (id, val)
{
myGlobal[id] = val;
}

function EvalCode (code)
{
myGlobal.eval(code);
}

AddVar("roman", 100.1);

WScript.Echo("roman=" + roman);

EvalCode("function TestEval1 (x,y) { return x+y; }")

// this fails
//WScript.Echo( "TestEval1(150,100) = ", TestEval1(150,100) );

EvalCode("TestEval2 = function (x,y) { return x-y; }")

// this passes
WScript.Echo( "TestEval2(150,100) = ", TestEval2(150,100) );

function EnumProp (o)
{
for(var k in o)
WScript.Echo(k + " : " + typeof(o[k]));
}

EnumProp(myGlobal); // same result with "this"


Function AddVar() works properly - the global variable is created. This
is, however, quite useless, because same behaviour can be invoked in
simpler way.

Function EvalCode() will not work for function declaration, but it will
work for assigning a function literal to new (global) variable (which is
variable rather than function definition).

EnumProp() is used to enumerate all defined variables and shows that
TestEval2() has been defined, however TestEval1() is missing, although
the code execute without error.

My question - anybody can explain where is function TestEval1() and why
it did not become property in intrisic Global object ?

Thank you
Roman
 
C

Csaba Gabor

Roman Ziak wrote:
....
EnumProp() is used to enumerate all defined variables and shows that
TestEval2() has been defined, however TestEval1() is missing, although
the code execute without error.

My question - anybody can explain where is function TestEval1() and why
it did not become property in intrisic Global object ?

Perhaps you will find some relevant reading at:
http://blogs.msdn.com/ericlippert/archive/2005/05/04/414684.aspx and
http://blogs.msdn.com/ericlippert/archive/2005/09/30/475826.aspx

Csaba Gabor from Vienna
 
R

RobG

Roman Ziak said on 27/03/2006 9:18 AM AEST:
Hello,

there were times when I used to be looking for a way to access
JavaScript Global object similar to those found in VBScript or PHP
($GLOBALS). At present this has only academic value for me. I was doing
research on JavaScript inheritance recently (simplifying it in
particular) and after reading 10.1.1, 10.1.3 and some other sections of
ECMA262 [1] I got a hint on accessing global object from different than
global scope.

Below is my example (please note that the host is WSH, feel free to
change WScript.Echo to your favourite output call):


myGlobal = this;

function AddVar (id, val)
{
myGlobal[id] = val;
}

function EvalCode (code)
{
myGlobal.eval(code);
}

AddVar("roman", 100.1);

WScript.Echo("roman=" + roman);

Where is WScript.Echo() defined? Alert is more generic:

alert("roman=" + roman);

EvalCode("function TestEval1 (x,y) { return x+y; }")

Add the line:

alert(typeof TestEval1);


and get 'function' in Firefox but 'undefined' in IE.

// this fails
//WScript.Echo( "TestEval1(150,100) = ", TestEval1(150,100) );

Replacing WScript.Echo with 'alert':

alert( "TestEval1(150,100) = " + TestEval1(150,100) );


'works' fine in Firefox but fails in IE with 'object expected'.

A function object is created that belongs to the execution context
created by eval(), it should be also added to the global object
referenced by myGlobal. In Firefox it is, in IE it isn't.

My reading of the spec is that IE is wrong here. In regard to eval
code, section 10.2.2 says:

"The scope chain is initialised to contain the same objects, in
the same order, as the calling context's scope chain. This
includes objects added to the calling context's scope chain by
with statements and catch clauses.

"Variable instantiation is performed using the calling context's
variable object and using empty property attributes.

"The this value is the same as the this value of the calling context."

Which means (to me) that any variable added to eval()'s global object
should also be added to the global object of the calling context (i.e.
the global object referenced by myGlobal).

EvalCode("TestEval2 = function (x,y) { return x-y; }")

Here an anonymous function is assigned to the global property TestEval2,
it is equivalent to the same statement without eval():

TestEval2 = function (x,y) { return x-y; };

and almost identical to:

function TestEval2(x,y){ return x-y; }

// this passes
WScript.Echo( "TestEval2(150,100) = ", TestEval2(150,100) );

The fact that is works in IE shows that sometimes it does follow the
spec. ;-)

function EnumProp (o)
{
for(var k in o)
WScript.Echo(k + " : " + typeof(o[k]));
}

EnumProp(myGlobal); // same result with "this"


Function AddVar() works properly - the global variable is created. This
is, however, quite useless, because same behaviour can be invoked in
simpler way.
Yes.


Function EvalCode() will not work for function declaration, but it will
work for assigning a function literal to new (global) variable (which is
variable rather than function definition).

It does 'work' for a function declaration in some browsers.

EnumProp() is used to enumerate all defined variables and shows that
TestEval2() has been defined, however TestEval1() is missing, although
the code execute without error.

Which says that TestEval1() was created in IE, but was added to the
temporary execution context created by calling eval(). It is added to
myGlobal in Firefox, but not IE.

My question - anybody can explain where is function TestEval1() and why

In IE, TestEval1 was not added to the global object so who know where it
is? It may still exist, but maybe not.

it did not become property in intrisic Global object ?

Because IE is buggy in this regard?
 
R

RobG

Csaba Gabor said on 27/03/2006 10:31 AM AEST:

Bizarre - try this;

// Get a reference to the global object
var Global = this;

// Declare fred with function declaration
function fred(){alert('Hi from fred');}

// Test it
findFred('Declaration');

// Declare fred with function expression
var fred = function(){alert('Hi from fred');}

// Test it
findFred('Expression');

// 'Declare' fred with eval
var fred = eval("function(){alert('Hi from fred');}");

// Test it
findFred('Eval()');

function findFred(txt){
var msg = txt + ": fred not found :-(";
for (var p in Global) {
if ('fred' == p) msg = txt + ': found ' + p + '!';
}
alert('fred is ' + (typeof fred) + '\n' + msg);
}
 
R

Roman Ziak

Hi Rob,

I did some more exploration and tests and reading on the articles Csaba
posted. It is more clear now - the way I was expecting it to work is
correct.
Roman Ziak said on 27/03/2006 9:18 AM AEST:

Where is WScript.Echo() defined? Alert is more generic:

alert is annoying. For those who will follow-up on this issue, here is
better alternative, which will work in both hosts - WSH and browser
(tested with IE/FF/Opera).

if(this.WScript != null)
{
// Why cannot just assign echo = WScript.Echo ... ?
echo = function(s)
{
WScript.Echo(s);
}
}
else
{
echo = function(s)
{
s = s ? s.replace(/\n/, "<br/>") : "";
s += "<br/>";
document.body.innerHTML += s;
}
}
Add the line:

alert(typeof TestEval1);


and get 'function' in Firefox but 'undefined' in IE.

alert( "TestEval1(150,100) = " + TestEval1(150,100) );


'works' fine in Firefox but fails in IE with 'object expected'.

Yes, this works as expected in FF/Opera and function is added. Seems
that JScript lacks conformance to ECMA-262 here. Also the links, Csaba
posted, confirm it.

When I changed EvalCode() to run eval() in the context of EvalCode()
instead of myGlobal, the function TestEval1() disapeared from global
context as expected (FF/Opera at least).

The funny thing about JScript is that eval execution context is quite
weird, say I do this:

EvalCode("function TestEval1 (x,y) { return x+y; } EnumProp(this);")

still do not get TestEval1 enumerated in EnumProp().
Here an anonymous function is assigned to the global property TestEval2, it is equivalent to the same statement without eval():

TestEval2 = function (x,y) { return x-y; };

and almost identical to:

function TestEval2(x,y){ return x-y; }

This part actually works in FF/Opera as expected. Why do you think this
should not work ?
In IE, TestEval1 was not added to the global object so who know where it
is? It may still exist, but maybe not.



Because IE is buggy in this regard?

That seems to be the conclusion.

It's a shame for JScript 5.6. Cannot get my example to compile with
JScript.NET to test it, keeps babling something about variables not
being defined and such.

Thanks for your responses
 
R

RobG

Roman Ziak said on 27/03/2006 1:03 PM AEST:
Hi Rob,

I did some more exploration and tests and reading on the articles Csaba
posted. It is more clear now - the way I was expecting it to work is
correct.



alert is annoying. For those who will follow-up on this issue, here is
better alternative, which will work in both hosts - WSH and browser

Yes, I usually write messages to the document too, but alert is just so
convenient... sometimes.

[...]
The funny thing about JScript is that eval execution context is quite
weird, say I do this:

EvalCode("function TestEval1 (x,y) { return x+y; } EnumProp(this);")

still do not get TestEval1 enumerated in EnumProp().

It seems that in IE functions are either added to some special object
other than the global object or as "DontEnum".

Try declaring a function:


function fred(){alert('hi from fred');}


You will not find 'fred' using for..in (e.g. your EnumProp()) - try my
response to Csaba Gabor.


[...]
This part actually works in FF/Opera as expected. Why do you think this
should not work ?

I didn't say it wouldn't, I just said that it works in IE - that it
works in other browsers is a given.

This fails in Netscape and IE:

// fred with eval expression
var fred = eval("function(){alert('Hi from fred');}");
fred();


But does it matter? Is there any circumstance where that might be
required, considering the equivalent and more reliable:

var fred = new Function("alert('Hi from fred');");


works everywhere? Well, in IE, Firefox and Netscape at least and I
would be very surprised if not elsewhere too.


[...]
 
V

VK

Roman said:
Hello,

there were times when I used to be looking for a way to access
JavaScript Global object similar to those found in VBScript or PHP
($GLOBALS). At present this has only academic value for me. I was doing
research on JavaScript inheritance recently (simplifying it in
particular) and after reading 10.1.1, 10.1.3 and some other sections of
ECMA262 [1] I got a hint on accessing global object from different than
global scope.

<snip>

You may find interesting reading my posts in the thread
<http://groups.google.com/group/comp..._frm/thread/11e9e7898e4b6dd0/07008e34b9555194>

Also see some references to MSDN linked in my posts.

Briefly IE's scope structure differs rather significally from the one
proposed in ECMA 262 or implemented by say in Firefox.

In your own samples you never work with the Global scope: you are
addressing Window scope allocated atop of Global (again - it's in IE,
not in ECMA specs).

Keeping it in mind the rest of results is easy to explain.
 
M

Michael Winter

On 27/03/2006 00:18, Roman Ziak wrote:

[snip]
myGlobal = this;

Variables should always be declared using a var statement. Though this
particular assignment is not likely to ever cause problems, it's good
practice to explicitly declare myGlobal.

[snip]
function EvalCode (code)
{
myGlobal.eval(code);
}

This is a problem, and seems to also produce different results in
different browsers. The first issue is that you are calling the eval
function as a method, however:

If value of the eval property is used in any way other than a
direct call (that is, other than by the explicit use of its
name as an Identifier which is the MemberExpression in a
CallExpression), or if the eval property is assigned to, an
EvalError exception may be thrown.

-- 15.1.2.1 eval(x), ECMA-262 3rd Ed.

Calling the function as a method seems to cause Firefox and Opera to
violate 10.2.2, whereas IE continues to follow it regardless.

[snip]
Function EvalCode() will not work for function declaration,

It works perfectly, but it doesn't create a global variable (in IE, and
Fx and Op when eval is called as a function). It's not supposed to.

Section 10.2.2 of ECMA-262 states:

When control enters an execution context for eval code, the
previous active execution context, referred to as the calling
context, is used to determine the scope chain, the variable
object, and the this value.

In this case, the calling context is the EvalCode function. Evaluating a
function declaration within that context is /almost/ the same as writing:

function EvalCode(code) {
function TestEval1(x, y) {
return x + y;
}
}

That is, evaluation of the code creates a nested function.

I said 'almost the same' because, as you should know, the variable
instantiation process would have function declarations evaluated before
execution of the code begins. That is, TestEval1 would be available as a
nested function at any point within the body of EvalCode. However,
because the function declaration is evaluated using eval, it doesn't
exist until execution of that function call. It's closer to:

function EvalCode(code) {
var TestEval1 = function(x, y) {
return x + y;
};
}

but still not exactly the same as this would create a local variable
during the variable instantiation process.
but it will work for assigning a function literal to new (global)
variable (which is variable rather than function definition).

For comparison, this evaluation would produce the equivalent of:

function EvalCode(code) {
TestEval2 = function(x, y) {
return x - y;
};
}

Notice that this version does not include a var statement.

The variable, TestEval2, does not exist anywhere within the scope chain
of the EvalCode function, therefore assignment will proceed (as normal)
by creating a new global variable, and assigning to it a reference to
the new function object.

I hope that helps,
Mike
 
M

Michael Winter

On 27/03/2006 08:10, VK wrote:

[snip]
You may find interesting reading my posts in the thread [url snipped]

Indeed the OP might. He would then realise, by reading the other posts
in that thread, that you are not the one to listen to when it comes to
technical matters.

Incidentially, I can think of nothing in that thread that is relevant, here.

[snip]

Mike
 
M

Michael Winter

On 27/03/2006 01:37, RobG wrote:

[snip]
A function object is created that belongs to the execution context
created by eval(),
^^^^^^^
No, not created by eval: used by eval.

If there is an active execution context when the eval function is
called, which there always will be if it is called within the body of a
function, the eval function will use that execution context for its
scope chain, variable instantiation, and this operator value.

If there is no active execution context, then the eval function will act
as if it were global code. The scope chain will consist only of the
global object, variable instantiation will occur using the global
object, and the this operator will refer to the global object.
it should be also added to the global object referenced by myGlobal.
[...]

No, it shouldn't. See my other post.
My reading of the spec is that IE is wrong here.

On the contrary. IE is acting precisely to specification, and Opera and
Firefox will, too, if the eval function is called as a function (as it
should be):

var global = this;

function evalAsMethod(code) {
global.eval(code);
}
function evalAsFunction(code) {
eval(code);
}

evalAsFunction('function test() {}');
alert(typeof test); /* undefined */

evalAsMethod('function test() {}');
alert(typeof test); /* function (in Op and Fx) */

[snip]
Which means (to me) that any variable added to eval()'s global object
should also be added to the global object of the calling context (i.e.
the global object referenced by myGlobal).

You seem to have muddled the definition of execution context. It is,
more-or-less, the environment for a function; it's scope chain, variable
object, and this operator value. An execution context is formed just by
calling a function, not how it is called (though that can affect facets
of the execution context). Therefore, the calling context (if any) is
the execution context of the function in which the eval function is called.

The eval function only acts as global code when executed in the global
portion of a program.

[snip]

The rest of your post seems to be based on this (unfortunately mistaken)
premise.

Mike
 
R

Roman Ziak

Michael said:
On 27/03/2006 00:18, Roman Ziak wrote:

[snip]
myGlobal = this;

Variables should always be declared using a var statement. Though this
particular assignment is not likely to ever cause problems, it's good
practice to explicitly declare myGlobal.

I agree. My oversight.
[snip]
function EvalCode (code)
{
myGlobal.eval(code);
}

This is a problem, and seems to also produce different results in
different browsers. The first issue is that you are calling the eval
function as a method, however:

If value of the eval property is used in any way other than a
direct call (that is, other than by the explicit use of its
name as an Identifier which is the MemberExpression in a
CallExpression), or if the eval property is assigned to, an
EvalError exception may be thrown.

-- 15.1.2.1 eval(x), ECMA-262 3rd Ed.

Calling the function as a method seems to cause Firefox and Opera to
violate 10.2.2, whereas IE continues to follow it regardless.

If this is the case, then JScript/IE does not get it right. The prove:

<previous program>

myGlobal.eval("function TestEval3(x) { return x+1; }");

EnumProp(myGlobal);

echo( "TestEval3(1) = " + TestEval3(1) );

JScript accepts dot notation and evaluates, enumerates TestEval3()
function in global object.
[snip]


I hope that helps,
Mike

Thanks for your reply.

It's unbelievable that all of JavaScripts violate 15.1.2.1 and accept
the dot notation.

What is the practical use of all this ? ... Some time ago I wanted to
have a routine allowing include() (for WSH/JScript). Browsers allow for
creating script element on the fly, but WSH does not have similar call.
Because of 10.2.2 running eval() in subroutine include() would not
create global code. I got around by creating short routine Include() in
the header of every file and evaluation in global context

eval(Include("the_script.js"));

I think there may still be a possible solution to this by enumerating
newly added objects right after eval() in Include() and re-assign them
to global object.

Thanks for your insight.

Roman
 
M

Michael Winter

On 27/03/2006 15:16, Roman Ziak wrote:

[snip]
[...] JScript/IE does not get it right.

I would like to point out that the behaviour of WSH and IE does differ.
myGlobal.eval("function TestEval3(x) { return x+1; }");

EnumProp(myGlobal);

echo( "TestEval3(1) = " + TestEval3(1) );

JScript accepts dot notation

For the eval function? What I quoted did say an exception 'may be
thrown', not must be. My point was that the eval function should be used
directly.
and evaluates, enumerates TestEval3() function in global object.

As it should.

Note (and here's a difference I mentioned) that IE does not create the
function as an enumerable property of the global object, though it is
still created. This isn't a problem caused by the eval function as even
normal function declarations don't become enumerable properties.

[snip]
It's unbelievable that all of JavaScripts violate 15.1.2.1 and accept
the dot notation.

Again, an exception /may/ be the result. View it as a warning to
programmers that using the eval function in that way is not a good idea.

[snip]

Mike
 
R

RobG

Michael Winter said on 27/03/2006 8:26 PM AEST:
On 27/03/2006 01:37, RobG wrote:

[snip]
A function object is created that belongs to the execution context
created by eval(),

^^^^^^^
No, not created by eval: used by eval.

If there is an active execution context when the eval function is
called, which there always will be if it is called within the body of a
function, the eval function will use that execution context for its
scope chain, variable instantiation, and this operator value.

If there is no active execution context, then the eval function will act
as if it were global code. The scope chain will consist only of the
global object, variable instantiation will occur using the global
object, and the this operator will refer to the global object.

I understood this part of 10.2.2 on eval code:

"When control enters an execution context for eval code, the
previous active execution context, referred to as the
calling context,..."

to mean that calling eval() created a new execution context that used
the calling context's scope chain, etc. so that variables created within
the call to eval() were added to the caller - but also that eval() had
its own context (though it might be virtually indistinguishable from the
caller's).

it should be also added to the global object referenced by myGlobal.
[...]


No, it shouldn't. See my other post.

Ah yes, of course :-x

function A(){
eval('function B(){}');
}

is nearly the same as:

function A(){
function B(){};
}

noting the difference in availability mentioned in your other post.

On the contrary. IE is acting precisely to specification, and Opera and
Firefox will, too, if the eval function is called as a function (as it
should be):

var global = this;

function evalAsMethod(code) {
global.eval(code);
}
function evalAsFunction(code) {
eval(code);
}

evalAsFunction('function test() {}');
alert(typeof test); /* undefined */

evalAsMethod('function test() {}');
alert(typeof test); /* function (in Op and Fx) */

Is that unique to eval()? Does it happen (or is there an equivalent
behaviour) with any other function/method call?

There seems to be many cases (such as the previously discussed 'new
Object()', 'Object()' and 'new Object') that indicate that the creators
of JavaScript have gone to some lengths to ensure consistent behaviour
even when it appears maybe there shouldn't be.

For eval() to behave differently to window.eval() seems contrary to that.

I noticed elsewhere in the thread your quote from 15.1.2.1 about 'an
EvalError exception may be thrown' but what is the logic in that (other
than your idea of a "don't do this" suggestion)?

[snip]
Which means (to me) that any variable added to eval()'s global object
should also be added to the global object of the calling context (i.e.
the global object referenced by myGlobal).


You seem to have muddled the definition of execution context.

No, I muddled the calling context - I looked at the calling context of
EvalCode() rather than eval itself and thought "eval's being called from
a global context", but it wasn't.


[...]
The eval function only acts as global code when executed in the global
portion of a program.

Indeed. :)
 
M

Michael Winter

On 28/03/2006 06:10, RobG wrote:

[snip]
I understood this part of 10.2.2 on eval code:

"When control enters an execution context for eval code, the
previous active execution context, referred to as the
calling context,..."

to mean that calling eval() created a new execution context that used
the calling context's scope chain, etc. [...]

You are quite right. Calling the eval function would, in principle,
create a new execution context as that's what happens when functions are
called. However, it would seem to me that this note is aimed more
towards implementers than programmers.

As the eval function would have its own execution context, the
evaluation of any variable or function declarations in the global
portion of the Program string would have those declarations create
properties of the variable object in the execution object of the eval
function. Section 10.2.2 says that instead, the eval function should use
execution context that was active when it was called.

[snip]
Is that unique to eval()? Does it happen (or is there an equivalent
behaviour) with any other function/method call?

Do you mean for a function or method to behave differently depending on
whether it's called directly or as a method? Other than the obvious -
user-defined methods that rely on the this operator, and DOM methods -
none spring to mind at the moment.

[snip]
I noticed elsewhere in the thread your quote from 15.1.2.1 about 'an
EvalError exception may be thrown' but what is the logic in that (other
than your idea of a "don't do this" suggestion)?

Perhaps it relates to the this operator value. Calling a function as a
method sets a specific value for the operator, yet for the eval
function, it has been specified already to be the this operator value of
the calling context. As this runs contrary to the definition of the eval
function, and there should not be any reason to call the function as a
method (just avoid masking the property with other variables in the
scope chain), it may have been deemed better to flag this as a run-time
error.

Maybe someone else has a better theory...

[snip]

Mike
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Mon, 27
Mar 2006 00:37:24 remote, seen in RobG
Roman Ziak said on 27/03/2006 9:18 AM AEST:

Where is WScript.Echo() defined? Alert is more generic:

alert("roman=" + roman);

In WSH.

<FAQENTRY> As 'WSH' does not occur in the FAQ, suggest changing line
before '.wsh' to read
'Microsoft's Windows Scripting Host (WSH) Newsgroup:-'


The following indicates how a localised addition can make code for one
system testable in another :

roman = 'GJC'
document.write = alert // try removing this line
WScript = {Echo:document.write}
WScript.Echo("roman=" + roman)
 
C

Csaba Gabor

Dr said:
The following indicates how a localised addition can make code for one
system testable in another :

roman = 'GJC'
document.write = alert // try removing this line
WScript = {Echo:document.write}
WScript.Echo("roman=" + roman)

Nice. Thanks.
Csaba
 

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

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top