A little test

137 views
Skip to first unread message

Dmitry A. Soshnikov

unread,
Nov 6, 2009, 3:59:58 AM11/6/09
to
Hi,

I specially didn't mention in the name of the topic to what kind of
theme in ECMA-262-3 is test related.

I've just explained on one forum again about [this-value] and what
object it should refer, there was some interesting examples (one of
which I'd like to make as a test).

The test is simple (please, try to answer (to youselft) first without
checking of code execution, then, execute the code (if needed), see
the result and give the answer here).

var foo = {
bar: function () {
return this;
}
};

alert(foo.bar()); // this - ?
alert((foo.bar)()); // this - ?
alert((foo.bar = foo.bar)()); // this - ?

P.S.> also, I'd like that guys for whom this test is very simple are
wait for other to answers, and then, if will be difficulty of other
people, give your answers.

/ds

abozhilov

unread,
Nov 6, 2009, 7:06:48 AM11/6/09
to
On Nov 6, 10:59 am, "Dmitry A. Soshnikov" <dmitry.soshni...@gmail.com>
wrote:

> alert(foo.bar()); // this - ?

| 11.2.3 Function Calls
| 6. If Type(Result(1)) is Reference, Result(6) is GetBase(Result(1)).
Otherwise, Result(6) is null.
| 7. If Result(6) is an activation object, Result(7) is null.
Otherwise, Result(7) is the same as Result(6).
| 8. Call the [[Call]] method on Result(3), providing Result(7) as the
this value and providing the list Result(2) as the
| argument values.

Here Result(6) is returned value from GetBase(Result(1)).
foo.bar(); //this refer `object' who referred from `foo';

> alert((foo.bar)()); // this - ?

() return internal Reference type. After that see point 6 from
Function calls.

Here `this' again refer `object' who referred from `foo'.

> alert((foo.bar = foo.bar)()); // this - ?

= Assignment expression return GetValue(Reference);

(foo.bar = foo.bar) => return value of `bar' property in `object'
referred from `foo'.
So Result(6) in Function Calls is null and pass to internal [[Call]]
method `null' for the `this' value.

| 10.2.3 Function Code
| * The caller provides the this value. If the this value provided by
the caller is not an object (including the case
| where it is null), then the this value is the global object.


alert((foo.bar = foo.bar)()); // this refer GlobalObject.

Regards and apologies for my english.
I will be happy, if somebody explain better from me.

Dmitry A. Soshnikov

unread,
Nov 6, 2009, 7:26:39 AM11/6/09
to
On Nov 6, 3:06 pm, abozhilov <fort...@gmail.com> wrote:

> [...]


> I will be happy, if somebody explain better from me.

> [...]

Your explanation was very good and accurate, thanks.

But you know it (I asked to wait for other answers ;)), it was very
easy for those who know what reference type is and how the [this-
value] is determinate by the caller. Also here the main moment is
related that identifier resolution just resolves to which base object
is property related, returning value of Reference Type; it doesn't
call GetValue which is vice-versa from assignment expression on
returning of which we get value any but not Reference type - for call
expression this means to get base as [null] => [Global].

The same situations with [this-value] are in similar examples. e.g.:

(foo.bar || foo.other)(); // global
(foo.bar, foo.bar)(); // global
(function () {})(); // global

In the last one is already not a Reference Type, and no identifier
resolution is taking place as it's not an identifier.

abozhilov

unread,
Nov 6, 2009, 9:45:10 AM11/6/09
to
On Nov 6, 2:26 pm, "Dmitry A. Soshnikov" <dmitry.soshni...@gmail.com>
wrote:

> (foo.bar || foo.other)(); // global


> (foo.bar, foo.bar)(); // global
> (function () {})(); // global

Yes, in previous post i forget very important part from specification.
11.2.1 Property Accessors and 11.1.2 Identifier Reference which
explain:

alert(foo.bar()); // this - ?

alert((foo.bar)()); // this - ?

Try it another test:

function bar()
{
return this;
}

var foo = {
bar: bar
};

window.alert(foo.bar()); //this ?
window.alert(Object(foo.bar)()); //this ?

window.alert((function(){return foo.bar;})()()); //this?

with(foo)
{
window.alert(this.bar()); //this ?
window.alert(bar()); //this ?
}

Dmitry A. Soshnikov

unread,
Nov 6, 2009, 12:48:09 PM11/6/09
to
On Nov 6, 5:45 pm, abozhilov <fort...@gmail.com> wrote:
> On Nov 6, 2:26 pm, "Dmitry A. Soshnikov" <dmitry.soshni...@gmail.com>
> wrote:
>
> > (foo.bar || foo.other)(); // global
> > (foo.bar, foo.bar)(); // global
> > (function () {})(); // global
>
> Yes, in previous post i forget very important part from specification.
>  11.2.1 Property Accessors and 11.1.2 Identifier Reference which
> explain:
>
> alert(foo.bar()); // this - ?

Yep, here is: Identifier resolution for [foo] + property accessor for
[.bar]; by MemberExpression.Identifier algorithm it will be reference
type with base [foo] and property name [bar]. So, [this-value] is
[bar].

> alert((foo.bar)()); // this - ?

The same + inside the grouping operator in which already Reference
Type value is passed. [this-value] is [bar].

>
> Try it another test:
>
> function bar()
> {
>     return this;
>
> }
>
> var foo = {
>     bar: bar
>
> };
>
> window.alert(foo.bar()); //this ?

[this-value] is [foo], as it's value of Reference Type is standing
from the left of call-brackets.

> window.alert(Object(foo.bar)());  //this ?
>

Yep, ToObject will return the value of [foo.bar], that's no a
Reference Type, so [this-value] is [null] => [Global].

> window.alert((function(){return foo.bar;})()()); //this?
>

The same, value is returned, it's not a Reference Type, so [this-
value] is [null] => [Global].

> with(foo)
> {
>     window.alert(this.bar()); //this ?
>     window.alert(bar()); //this ?
>

> [...]
>

In the first call, [this] is the global object itself (in this
execution context - global context), so it's truly provided as base of
reference [this.bar], so [this-value] is [Global] without any
transformations.

In the second call identifier resolution is taking place for [bar], as
the result will be value of Reference Type with base [__withObject]
and property name [bar], where [__withObject] is an object inserted in
front of scope chain. So, [this-value] is [__withObject].

But, beside the activation object when it's used as the base object of
Reference Type and which transforms to [null] => [Global] for [this-
value], also [catch clause] of [try] when used as the based object
transforms to [null] => [Global]:

For activation object:

function foo() {
function bar() {}
bar(); // the same: AO.bar() => null.bar() => Global.bar();
}

For catch-clause:

try {
throw function () {
return this;
};
} catch (ex) {
alert(ex()); // ?
}

In the last example identifier resolution will return a value of
Reference Type with base [__catchClauseObject] and property name [ex],
where [__catchClauseObject] is an object inserted in front of scope
chain. But in difference from [with] which also inserts its object in
front of scope chain, [__catchClauseObject] base will be transformed
to [null] => [Global].

VK

unread,
Nov 7, 2009, 10:02:21 AM11/7/09
to
A little more practical exercise if no one minds:

<script type="text/javascript">
window.alert(window.navigator || 'undefined'); // alerts ?
var navigator = {'userAgent' : 'foobar'};
window.alert(window.navigator || 'undefined'); // alerts ?
</script>

1,000 self-assigned bonus points :) if one names a popular browser
where this code leads to a syntax error so never gets executed.

On a really practical level that comes to the old maskon and
demaskonizing problems, see for instance my old post from 2007:
http://groups.google.com/group/comp.lang.javascript/msg/65a858c19f383df0

Given a situation with a malicious script that shadows (maskonizes)
window.XMLHttpRequest with its own object that fully emulates the
native one plus sends copies of each data input to a 3rd party server.
Until the malicious library is fully removed from any wide use, out
emergency security patch has to ensure that each new XMLHttpRequest is
based on the default vendor's constructor and not on some 3rd party
runtime maskon. On detecting a maskonized environment the security
patch first tries to get the access to the real constructor; if it's
not possible on the given platform then warn the user and break the
code execution.


VK

unread,
Nov 7, 2009, 11:57:23 AM11/7/09
to
> A little more practical exercise if no one minds:
>
> <script type="text/javascript">
>  window.alert(window.navigator || 'undefined'); // alerts ?
>  var navigator = {'userAgent' : 'foobar'};
>  window.alert(window.navigator || 'undefined'); // alerts ?
> </script>
>
> 1,000 self-assigned bonus points :) if one names a popular browser
> where this code leads to a syntax error so never gets executed.

As not everyone may have each prominent browser installed, I am giving
the ROT13 encoded answers
( http://www.retards.org/projects/rot13/ if needed):

VR
haqrsvarq
[bowrpg Bowrpg]

Fnsnev
[bowrpg Anivtngbe]
[bowrpg Bowrpg]

Puebzr
[bowrpg Anivtngbe]
[bowrpg Bowrpg]

Bcren
haqrsvarq
[bowrpg Bowrpg]

Argfpncr 4.7
[bowrpg Anivtngbe]
[bowrpg Bowrpg]

Sversbk
flagnk reebe "erqrpynengvba bs pbafg anivtngbe"

Richard Cornford

unread,
Nov 7, 2009, 9:14:44 PM11/7/09
to
VK wrote:
>A little more practical exercise if no one minds:
>
> <script type="text/javascript">
> window.alert(window.navigator || 'undefined'); // alerts ?
> var navigator = {'userAgent' : 'foobar'};
> window.alert(window.navigator || 'undefined'); // alerts ?
> </script>
>
> 1,000 self-assigned bonus points :) if one names a popular
> browser where this code leads to a syntax error so never
> gets executed.
<snip>

The error is not a syntax error, it is a runtime error, which means that
the code does get executed, up the point where the error is thrown
(which is during variable instantiation for the global execution
context).

Richard.

VK

unread,
Nov 8, 2009, 2:20:47 AM11/8/09
to
Richard Cornford wrote:
> The error is not a syntax error, it is a runtime error, which means that
> the code does get executed, up the point where the error is thrown
> (which is during variable instantiation for the global execution
> context).

The code never gets executed in Fx (I guess we may reveal the "hero"
by now) as this slight code modification shows:

<script type="text/javascript">
window.alert('OK 1');
try {


window.alert(window.navigator || 'undefined'); // alerts ?
var navigator = {'userAgent' : 'foobar'};
window.alert(window.navigator || 'undefined'); // alerts ?
}

catch(e) {
window.alert(e.message);
}
finally {
window.alert('OK 2');
}
</script>

where neither of alerts ever appears. Unless of course we introduce
three stages for the code lifetime instead of the conventional two:
1) parsing stage (syntax errors)
2) var instantiation stage (this kind of errors)
3) execution stage (runtime errors interceptable by try-catch blocks)
It is possible but way too theoretical IMHO. Whatever error happens
before any statement executed so try-catch is useless - it is a syntax
one.

btw 1,000,000,000 bonus points if anyone points a Books of ECMA
prophetic passage suggesting that
var navigator;
clause prevents the code execution.
;)

Dmitry A. Soshnikov

unread,
Nov 8, 2009, 5:13:20 AM11/8/09
to
On Nov 8, 10:20 am, VK <schools_r...@yahoo.com> wrote:

> [...]


>  var navigator;
> clause prevents the code execution.
> ;)

> [...]

that because of extension implemented by SpiderMonkey (since v.1.5) -
[const] keyword which prevents redeclaration of the same identifier
name - no matter - will it be a new [const] or [var]. Also, current
Safari browser ES implementation (WebKit) has [const] support, but in
difference form SpiderMonkey it doesn't throws an exception sort of
"redeclaration of ...", but just ignore the next [const] or [var] for
the same identifier name.

const foo = 1;
var foo = 2; // error in FF, no error in Safari
alert(foo); // 1 - in Safari, no change was made in [var]

/ds

VK

unread,
Nov 8, 2009, 5:42:33 AM11/8/09
to
On Nov 8, 1:13 pm, "Dmitry A. Soshnikov" <dmitry.soshni...@gmail.com>
wrote:

The background mechanics of the bug is pretty obvious: someone
"wisely" made window.navigator a const on the underlaying interface
level: looks like a lazy patch against spoofing the navigator sniffing
or something (other window properties are not affected).

The trick is that in a purely ECMA 262 3rd.ed. compliant script it
might be a surprise because nothing in ECMA 262 3rd.ed. suggests that
var navigator;
or
var navigator = something;
may lead to a naming conflict with a host object property.

From the fun of the kind:

var arr = new Array;
var self = {'foo':'bar'};
for (var p in self) {
arr.push(p);
}
Name a known browser where arr will contain properties of the window
host object and not "foo"

John G Harris

unread,
Nov 8, 2009, 6:49:31 AM11/8/09
to
On Sun, 8 Nov 2009 at 02:42:33, in comp.lang.javascript, VK wrote:

<snip>


>The trick is that in a purely ECMA 262 3rd.ed. compliant script it
>might be a surprise because nothing in ECMA 262 3rd.ed. suggests that
> var navigator;
>or
> var navigator = something;
>may lead to a naming conflict with a host object property.

<snip>

It shouldn't be a surprise. Specifying host objects is outside the scope
of ECMA 262. It says so in section 4.

John
--
John Harris

Asen Bozhilov

unread,
Nov 8, 2009, 6:53:36 AM11/8/09
to
On 7 Ноем, 18:57, VK <schools_r...@yahoo.com> wrote:
> > <script type="text/javascript">
> >  window.alert(window.navigator || 'undefined'); // alerts ?
> >  var navigator = {'userAgent' : 'foobar'};
> >  window.alert(window.navigator || 'undefined'); // alerts ?
> > </script>

Your exercise depends from environment. ECMA 262 doesn't need to
explain host object and behaviour of environment object, properties,
function. etc. See what is been writing in ECMA 262 documentation:

| 2 Conformance
| A conforming implementation of ECMAScript is permitted to provide
additional types, values, objects, properties,
| and functions beyond those described in this specification.

| 4.1 Web Scripting
| A web browser provides an ECMAScript host environment for client-
side computation including, for instance,
| objects that represent windows, menus, pop-ups, dialog boxes, text
areas, anchors, frames, history, cookies, and
| input/output. Further, the host environment provides a means to
attach scripting code to events such as change of
| focus, page and image loading, unloading, error and abort,
selection, form submission, and mouse actions.
| Scripting code appears within the HTML and the displayed page is a
combination of user interface elements and
| fixed and computed text and images. The scripting code is reactive
to user interaction and there is no need for a
| main program.

Your code have two interesting things.
First is IE variable instantiation in global execution context:

var navigator;
alert(navigator); //IE undefined

Here IE overwrite internal attribute {ReadOnly}. ECMA 262 purely
explain behaviour like this one:

| 10.1.3 Variable Instantiation
| If there is already a property of the variable object with
| the name of a declared variable, the value of the property and its
attributes are not changed.

Second interesting is in my Firefox 3.5.5:

var navigator; //throw redeclaration of const navigator

For my, this error is bad.

var navigator;

Doesn't change internal attribute {ReadOnly}, because that i think
error must be throw when i try to assigned value to that property of
Variable Object, here property of Global Object.

Dmitry A. Soshnikov

unread,
Nov 8, 2009, 8:51:34 AM11/8/09
to
On Nov 8, 2:53 pm, Asen Bozhilov <asen.bozhi...@gmail.com> wrote:

> [...]


> Your code have two interesting things.
> First is IE variable instantiation in global execution context:
>
> var navigator;
> alert(navigator); //IE undefined
>
> Here IE overwrite internal attribute {ReadOnly}. ECMA 262 purely
> explain behaviour like this one:
>

Yep, that's IE's host objects buggy implementation. But moreover,
there's one interesting thing with it. If to use [eval] which won't
set {DontDelete} for [var]s (except known IE's [delete] operation for
properties of window host objects), we can see that some host object,
e.g. our [navigator] is just *hided* by the new value (sort of like
variable objects in scope chain - deeper identifier name shadows the
same name in variable object above):

alert(navigator); // [object], OK
alert(navigator.userAgent); // exactly that object we expect

// now use variable declaration
// using [eval] which should not
// set {DontDelete}

eval('var navigator;');
alert(navigator); // undefined, OK

// set new value
navigator = 10;
alert(navigator); // 10, OK

// remove it from the base object
// as navigator has no {DontDelete}
delete navigator;

alert(navigator); // [object], ;)

// and exactly restored main
// [navigator] host object
alert(navigator.userAgent);

> [...]


> Second interesting is in my Firefox 3.5.5:
>
> var navigator; //throw redeclaration of const navigator
>
> For my, this error is bad.
>
> var navigator;
>
> Doesn't change internal attribute {ReadOnly}, because that i think
> error must be throw when i try to assigned value to that property of
> Variable Object, here property of Global Object.

> [...]

Well, it can be treated from the other hand: *redeclaration* means
exactly repeat of *declaration*, but not the *assignment*, so FF from
their point of view is right. The other question is that they could do
not throw an exception just like Safari does, but from some point of
view that's even better - [const] is const - we've used to be sure
that it won't be ever changed, so ignored [var] and other [const]
without throwing exception - can make it more complicated to analyze
the code - if we've forgot that it was [const] we will think - why so
this value didn't change?

VK

unread,
Nov 8, 2009, 9:55:51 AM11/8/09
to

Thanks to everyone for comments.

All respondents seem overlooked the crucial part of the code: the
"var" part.

At no circumstances, being written anywhere or not, at a winter storm
or at a summer hot, day or night, end of the world or a Friday
evening: never ever
var something
is allowed to conflict or being mixed in any shall perform form with
anyHostObject.something property.

This rule is more crucial than the entire possible ECMA lore all
together. No "var" on introducing a variable - and you are on the
mercy of the environment and be ready for the most strange troubles,
like say "i doesn't support this property or method" for the code
like:

for (i=0; i<L; i++) {
// ...
}
(btw, of who ugly "convenience extension" is this and what
circumstances will lead to that?)

You said "var something" - you said everything. It is a JavaScript
variable, the topic is over and closed. That is the only possibility
to write a predictable code. Actually no, there is another
possibility: to make some global naming agreement between all browser
producers from one side and all JavaScript coders from the other about
how to prefix their variables and properties.
Having this prerequisite in mind, it is really hard to say what coding
is lesser unprofessional (the question of professionalism is removed
by default): the one of Fx where "var navigator" conflicts to death
with "window.navigator" - or the one of Opera where with "var self
= ..." it still enumerates window.self properties.

I am wondering if the maskon problem is solved by anyone yet. The
initial approach is by checking the prototype chain of course. The
repair way is already mentioned in the last post by Dmitry A.
Soshnikov, I would just suggest to use "shadowed" instead of "hidden"
as a more used programming term. Then "delete" should help but not
everywhere. This is why I was shocked that some regulars might not
know all per-UA "delete" peculiarities.
Anyone wants to propose a code? I'll wait till Monday before posting
the RedPill function used in our solutions.

Asen Bozhilov

unread,
Nov 8, 2009, 10:17:10 AM11/8/09
to
On 8 Ноем, 15:51, "Dmitry A. Soshnikov" <dmitry.soshni...@gmail.com>
wrote:

> alert(navigator); // [object], OK


> alert(navigator.userAgent); // exactly that object we expect
>
> // now use variable declaration
> // using [eval] which should not
> // set {DontDelete}
>
> eval('var navigator;');
> alert(navigator); // undefined, OK
>
> // set new value
> navigator = 10;
> alert(navigator); // 10, OK
>
> // remove it from the base object
> // as navigator has no {DontDelete}
> delete navigator;
>
> alert(navigator); // [object], ;)
>
> // and exactly restored main
> // [navigator] host object
> alert(navigator.userAgent);

You give, very very interesting example. What are you think about this
one:

window.a = 10;
eval('var a = 1;');
window.alert(a); //1
window.alert(delete a); //true
window.alert(a); //10

The interesting here is, how IE form Scope Chain when entering in
global execution context. I think IE when entering in global execution
context, Scope Chain contains:

Window Host <-- Global Object

Global execution context associated with Global Object for Variable
Object, and another interesting part is, how IE get properties of
`object' who referred from `window'.

window.a = 10;
eval('var a = 1;'); //ignore {DontDelete}
window.alert(a); //1
window.alert(window.a); //1

I think IE just ignore *window.* in `window.a' and here IE make
identifier resolution in Scope Chain.

And what are you think about:

var a = 10;
eval('var a = 1;');
window.alert(a); //1
window.alert(delete a); //false

VK

unread,
Nov 8, 2009, 12:51:56 PM11/8/09
to
Asen Bozhilov wrote:
> The interesting here is, how IE form Scope Chain when entering in
> global execution context. I think IE when entering in global execution
> context, Scope Chain contains:
>
> Window Host <-- Global Object

Bingo!

By quoting myself from 2006:
http://groups.google.com/group/comp.lang.javascript/msg/02528de788828b39
"IE and Opera have two separate scopes: Global and enclosing Window.
Firefox has (or pretending to have) only one: Global which is Window
(or Window which is Global - I'm really lost here). If both allowed by
specs so the better. If one of them is not allowed by specs - it
doesn't make it disappear."

Back in March 2006 "the public" was not ready yet to such things so
the hysteria was like with an ugly rat thrown into lady's room :)

In fact any browser has Global scope first and window scope above it:
so first Global lookup, if not found then window lookup. That is the
only way to make JavaScript usable without some fantastic "global
naming agreement" between browser producers and JavaScript programmers
mentioned in my previous post. The rest of the story is caused by a
set of events:
1) 1999 ECMA 262 sh** crap about host == Global or whatever (I'm still
doubting very much that they knew themselves was what written that day
in that particular section).
2) "religious war" of 2005-2008 when anyone in anti-IE camp tried to
be as holly as it gets so implemented or at least tried to implement
even the most sick parts of specs either by ECMA or by W3C
3) the last but maybe the most influential one: the anti-popup
campaign 2005-2006. Who remembers that time, at some moment a lot of
resources became nearly unusable as on each visit 3-5-10 window pop-
ups and pop-unders have been thrown. So "kill these pupups!" was a
global demand so all browser manufactures jumped on it as an
opportunity to be cooler than the competitor. That was the time of
actively shadowing window native methods like "open" with bogus one
and actively looking and fixing possibilities to get to the shadowed
methods. That was the time of "bugs" like "prevent user from getting
fresh method references from the runtime created iframe object" and
similar.

Any way, the real scope schema, being patched, fixed, locked, emulated
etc. everywhere 10 years in the row is the reason of the rather sorry
- but definitely not catastrophic - state we are having right now.

In the relevance to eval() escaping DontDelete on IE: it's just an
oops of the original "delete" functionality fix made back then for the
reason (3). The "hanging out ends" can be seen in this test code back
from the spring of 2006:

<script type="text/javascript">

window['foo'] = 1;

eval('var foo = 2');

window.alert(this.window.foo); // 2

delete foo; // OK

try {
window.alert(this.window.foo);
// Error # 438 Not supported
}
catch(e) {
window.alert(
'window.alert(this.window.foo)\n' +
(e.number & 0xFFFF) + ' ' +
e.message);
}

try {
window.alert(this.foo);
// Error # 438 Not supported
}
catch(e) {
window.alert(
'window.alert(this.foo)\n' +
(e.number & 0xFFFF) + ' ' +
e.message);
}

try {
window.alert(window.foo);
// Error # 438 Not supported
}
catch(e) {
window.alert(
'window.alert(window.foo)\n' +
(e.number & 0xFFFF) + ' ' +
e.message);
}

try {
window.alert(foo);
// Error # 7 Out of memory
}
catch(e) {
window.alert(
'window.alert(foo)\n' +
(e.number & 0xFFFF) + ' ' +
e.message);
}

</script>

Richard Cornford

unread,
Nov 9, 2009, 2:01:24 AM11/9/09
to
Asen Bozhilov" wrote:

The code above is insufficient to support this conclusion. For example,
the outcome would be the same if - window - were the [[Prototype]] of
the global object. In order to support a scope chain based explanation
it would be necessary to show that one of the global object or the
window object had properties that the other did not. Else the possibly
that they were both on the scope chain would be meaningless as if they
both have exactly the same properties all Identifier resolution would
resolve against whichever was encountered first.

A test strategy to see if any arbitrary Identifier, when resolved
against the scope chain, is resolved as a property of any single object
(which includes that object's prototype chain) is to use that identifier
to declare a function local variable, use the - with - statement to
place the object on the scope chain, and then resolve the Identifier
within the - with - block. The two possible results are that the
Identifier is not identified as a property of the object added to the
scope chain and so is resolved as the local variable in the containing
scope, or it is resolved as a property of the object added to the scope
chain by the - with - statement. If the value of the local variable is
sufficiently easily discriminated from other values then com[paring its
value with the value retrieved in the - with - block will determine
whether the object has the property in question, in terms of scope chain
Identifier resolution. This may seem convoluted in comparison with using
the - in - operator, but it does directly speak to the question of
Identifier resolution within the environment being tested.

Any differences detected between the properties or the global object and
the window object could then be the basis for further examination of
their respective roles/locations on the scope chain. The absence of any
detectable differences would instead be an indicator that there would be
no point in their both being on the scope chain as whichever came later
would never be implicated in Identifier resolution.

A simple, one Identifier, test function using the above method (though
not very efficiently) might be:-

function doesIdentifierResolutionFindOnObject(identifeir, object){
var fn, ret;
var fnBody = [
"var res, ","identifeir"," = '#Declared in Outer Scope#';",
"with(obj){",
"res = ","identifeir",";",
"}",
"return (res !== '#Declared in Outer Scope#');"
];
fnBody[1] = fnBody[5] = identifeir;
fn = new Function('obj', fnBody.join(''));
try{
ret = fn(object);
}catch(e){
ret = 'EXCEPTION: '+e.message;
}
return ret;
}

- returning true or false boolean values, or s string if an exception is
thrown (true if the Identifier is resolved as a property of the object
and false if it is resolved as a property of the containing scope).

> Global execution context associated with Global Object for
> Variable Object, and another interesting part is, how IE
> get properties of `object' who referred from `window'.
>
> window.a = 10;
> eval('var a = 1;'); //ignore {DontDelete}
> window.alert(a); //1
> window.alert(window.a); //1
>
> I think IE just ignore *window.* in `window.a' and here IE make
> identifier resolution in Scope Chain.

That is not as easy as it sounds because the scrip engine would find it
very hard to know that no - window - variable as declared in a
containing scope or that no object with a - window - property had been
added to the scope chain with a - with - statement (well, the former is
possible and the - with - condition could be handled independently).
Particularly problematic for IE would be the functions created from
intrinsic event attributes on HTML elements as they get an dynamically
augmented scope chain and there would be no way of knowing whether any
DOM node on the scope chain would have a - window - property added at
any time, or the function reference copied to the DOM branch where a
node already had a - window - property.

If the global object and the window object are different objects (and
how much real evidence for that has been presented so far?) all apparent
transferring of information between them could be accounted for by each
having a very specialised [[Put]] methods (and/or [[Get]] methods). Such
a method could easily observe the assignment of a value to one object
and repeat that assignment for the other (or transfer the assignment to
a shred prototype, or an object on the prototype chain of each).

> And what are you think about:
>
> var a = 10;
> eval('var a = 1;');
> window.alert(a); //1
> window.alert(delete a); //false

That is the expected behaviour. Remember that ECMA 262 3rd Ed. Section
10.1.3 Variable Instantiation (for VariableDeclaration) says "If there

is already a property of the variable object with the name of a declared
variable, the value of the property and its attributes are not changed".

So when the - eval - attempts to re-declare - a - it finds the Variable
object already has an - a - property and leaves it as it is, with its
DontDelete attribute in place.

Richard.

Asen Bozhilov

unread,
Nov 9, 2009, 6:21:31 AM11/9/09
to
On Nov 9, 9:01 am, "Richard Cornford" <Rich...@litotes.demon.co.uk>
wrote:

> The code above is insufficient to support this conclusion. For example,
> the outcome would be the same if - window - were the [[Prototype]] of
> the global object.

Actually yesterday when i post, i think about your words.

window.a = 10;
var a = 20;
window.alert(a); //20
window.alert(window.a); //20

If window is [[Prototype]] of Global Object in second case, lookup in
prototype chain will be start from one level up. So i expected in
second case 10. If you right, IE again have different mechanism for
setting and getting properties from Global Object.


> function doesIdentifierResolutionFindOnObject(identifeir, object){
> var fn, ret;
> var fnBody = [
> "var res, ","identifeir"," = '#Declared in Outer Scope#';",
> "with(obj){",
> "res = ","identifeir",";",
> "}",
> "return (res !== '#Declared in Outer Scope#');"
> ];
> fnBody[1] = fnBody[5] = identifeir;
> fn = new Function('obj', fnBody.join(''));
> try{
> ret = fn(object);
> }catch(e){
> ret = 'EXCEPTION: '+e.message;
> }
> return ret;
>
> }
>
> - returning true or false boolean values, or s string if an exception is
> thrown (true if the Identifier is resolved as a property of the object
> and false if it is resolved as a property of the containing scope).

Thanks. That is usefully, that code refutation my "conclusion", but
again stay many unknowns about that case. Before people from Microsoft
explain that, i doesn't have trusted to that's hypothesеs.

> > var a = 10;
> > eval('var a = 1;');
> > window.alert(a); //1
> > window.alert(delete a); //false
>
> That is the expected behaviour. Remember that ECMA 262 3rd Ed. Section
> 10.1.3 Variable Instantiation

Of course, but IE have different behaviour when been used `delete'
operator for variable defined with `var' in global execution context
and properties of Global Object.

this.a = 10;
var b = 10;
try {
window.alert(delete this.a); //throw error
}catch(e)
{
window.alert(e);
window.alert(delete b); //false
}

After a few months kangax post similar topic.
<URL: http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/22e6b2d147f57ee5/dda4dee3390fa71a?#dda4dee3390fa71a>

Richard Cornford

unread,
Nov 9, 2009, 8:22:09 AM11/9/09
to
On Nov 9, 11:21 am, Asen Bozhilov wrote:

> On Nov 9, 9:01 am, Richard Cornford wrote:
>
>> The code above is insufficient to support this conclusion.
>> For example, the outcome would be the same if - window -
>> were the [[Prototype]] of the global object.
>
> Actually yesterday when i post, i think about your words.
>
> window.a = 10;
> var a = 20;
> window.alert(a); //20
> window.alert(window.a); //20
>
> If window is [[Prototype]] of Global Object in second case, lookup in
> prototype chain will be start from one level up. So i expected in
> second case 10. If you right,

I was not asserting that any prototype relationship existed between
the two (and don't believe that it does). My intention was to point
out that the "code above" did not represent evidence for a scope chain
relationship because its specific behaviour could be accounted for in
other ways (such as a prototype relationship). My point being that if
a scope chain relationship is going to be proposed the evidence
presented should be evidence of something that could only be explained
by a scope chain relationship.

> IE again have different mechanism for
> setting and getting properties from Global Object.
>
>> function doesIdentifierResolutionFindOnObject(identifeir, object){
>> var fn, ret;
>> var fnBody = [
>> "var res, ","identifeir"," = '#Declared in Outer Scope#';",
>> "with(obj){",
>> "res = ","identifeir",";",
>> "}",
>> "return (res !== '#Declared in Outer Scope#');"
>> ];
>> fnBody[1] = fnBody[5] = identifeir;
>> fn = new Function('obj', fnBody.join(''));
>> try{
>> ret = fn(object);
>> }catch(e){
>> ret = 'EXCEPTION: '+e.message;
>> }
>> return ret;
>
>> }
>
>> - returning true or false boolean values, or s string if an
>> exception is thrown (true if the Identifier is resolved as a
>> property of the object and false if it is resolved as a
>> property of the containing scope).
>
> Thanks. That is usefully, that code refutation my "conclusion",
> but again stay many unknowns about that case. Before people
> from Microsoft explain that, i doesn't have trusted to that's

> hypothes?s.

The first thing that is needed is a clear statement of the evidence
for the window object and the global object being different objects.
The way in which they can be differentiated (if they can be at all)
could then guide the hypothetical explanations of the relationship
between them.

>>> var a = 10;
>>> eval('var a = 1;');
>>> window.alert(a); //1
>>> window.alert(delete a); //false
>
>> That is the expected behaviour. Remember that ECMA 262 3rd Ed.
>> Section 10.1.3 Variable Instantiation
>
> Of course, but IE have different behaviour when been used
> `delete' operator for variable defined with `var' in global
> execution context and properties of Global Object.

Maybe, but that makes the error generating case the interesting one,
not the case where everything goes as specified.

> this.a = 10;
> var b = 10;
> try {
> window.alert(delete this.a); //throw error
> }catch(e)
>
> {
> window.alert(e);
> window.alert(delete b); //false
>
> }
>
> After a few months kangax post similar topic.

I noticed, but I also noticed that the errors were also thrown when
replacing - window - with - this -, so this does not represent
evidence of there being two distinct objects involved.

Richard.

Dmitry A. Soshnikov

unread,
Nov 9, 2009, 3:09:38 PM11/9/09
to
On Nov 8, 8:51 pm, VK <schools_r...@yahoo.com> wrote:

> [...]


>  // Error # 7 Out of memory}

> [...]

Yeah, such result can be seen also in the following example (I've
already showed this example here before):

b = 10;
alert(b);
delete b;
alert(b); // "b" is not defined

Next:

b = 10;
alert('b' in window); // true

Next:

b = 10;
delete b;
alert('b' in window); // false

And bellow this bug with "out of memory" is:

b = 10;
alert('b' in window); // true, OK, as above
delete b;
alert('b' in window); // true, again true? above was false

// the most buggy-thing
alert(b); // **out of memory**, not "b" is not defined

Does anyone have accurate info about what MS says about it?

Dmitry A. Soshnikov

unread,
Nov 9, 2009, 3:39:58 PM11/9/09
to
On Nov 8, 6:17 pm, Asen Bozhilov <asen.bozhi...@gmail.com> wrote:

> What are you think about this
> one:
>
> window.a = 10;
> eval('var a = 1;');
> window.alert(a); //1
> window.alert(delete a); //true
> window.alert(a); //10
>
> The interesting here is, how IE form Scope Chain when entering in
> global execution context. I think IE when entering in global execution
> context, Scope Chain contains:
>
> Window Host <-- Global Object
>
> Global execution context associated with Global Object for Variable
> Object, and another interesting part is, how IE get properties of
> `object' who referred from `window'.
>

There's one more interesting thing with IE's window, "window-wrapper"
and this (in role of Global). If we use IE8 debugger (in developer
tools) and test the following code (adding the breakpoint in the first
line):

a = 10;
this.b = 20;
window.c = 30;
var d = 40;

we'll see that [a] and [d] are *near* (on the same level) the [window]
object and the [b] and [c] are *in* the window - should be somewhere
in the window or [this] - but we won't see it - try to find out them -
you won't.

So, we have the structure something like this (just as we have some
that variable object which is *not* the [window] and *not* [this]):

VO = {
window: {
b: - ?,
c: - ? - where are they?
},
d: on entering - undefined, then - 40,
a: 10 - created on execution
};

This debugger's tab shows "locals" (local variables, of the "local"
execution context), and as we see - [window], [d] and [a] - are in
that "locals". The main issue - where are the [b] and [c]? Why don't
we see them in the properties of [window]? Nor in [window.window], nor
in [self], nor in [window.self.window]. And also - we don't see [d]
and [a] there.

Moreover, we can use the near tab for "watches" and add watch for the
[this] (which should be Global object) - and again - we won't find [b]
and [c] there.

The presence of some invisible VO (variable object) which is not the
Global as should be, can bee also seen in this example:

alert(e); // undefined
try {} catch (e) {}
alert(e);

Here we see, that in IE, just like with NFE (name function expression)
bugs - identifier [e] are present in the VO (but not in window, nor in
this). Actually, that's a bug as catch clause object should be added
to the front of scope chain only on execution time (and removed after
catch is finished) but not the entering the execution context time.

But the main interest here is that [e], if again to see in debugger,
is on the same level as [window] - but not *in* [window]:

VO = {
window: {},
e: ...
};

Backing to the [navigator] host object mentioned in this thread:

eval('var navigator;');


navigator = 10;
alert(navigator); // 10

delete navigator;
alert(navigator); // [object]

if we see in debugger, we see that structure:

VO = {
window: {
...
navigator: <host object>
...
},
navigator: 10
};

That's why after deleting our [eval]uated [navigator] we still see
[navigator] that is taken from the [window.navigator].

So, the idea mention by Richard seems to have sense - that there's
sort of special [[Get]] method implementation for that stuff. But I'm
not sure about that properties are copied to different object any
time.

/ds

Reply all
Reply to author
Forward
0 new messages