ES5 changed variable object(VO) to lexical environment. What's the motivation of such change since VO is already very obvious as perception?
I think variable objects are more analogous to environment records.
An Environment Record records the identifier bindings that are created
within the scope of its associated Lexical Environment.
In ES5 there are two different kinds of environment records:
Declarative environment records are used to define the effect of
ECMAScript language syntactic elements such as FunctionDeclarations,
VariableDeclarations, and Catch clauses that directly associate identifier bindings with ECMAScript language values. Object
environment records are used to define the effect of ECMAScript
elements such as Program and WithStatement that associate
identifier bindings with the properties of some object.
So the question would be why declarative environment records were introduced instead of only using object environment records just like ES3 variable objects. The difference is that declarative environment records can have immutable bindings:
In addition to the mutable bindings supported by all Environment
Records, declarative environment records also provide for immutable
bindings. An immutable binding is one where the association between an
identifier and a value may not be modified once it has been
established.
Immutable bindings don't have a direct equivalent in objects. A property can be defined as both non-configurable and non-writable, becoming immutable. However,
Creation and initialisation of immutable binding are distinct steps so
it is possible for such bindings to exist in either an initialised or
uninitialised state.
But you can't have an uninitialized property. If you define a non-configurable non-writable property with value undefined, then you won't be able to initialize it to the desired value.
I don't think it's possible to have uninitialized immutable bindings in ES5. CreateImmutableBinding is only used in Declaration Binding Instantiation and Function Definition, and in both cases it's immediately initialized with InitializeImmutableBinding.
But possibly this was done to allow uninitialized immutable bindings as extensions of the language, like the JavaScript 1.5 const. Or maybe they already had in mind ES6 const.
The same author whose ES3 article you linked wrote also about ES5 (and even linked that section there). I'll quote Mr. Soshnikov from his "Declarative environment record" section in ECMA-262-5 in detail. Chapter 3.2. Lexical environments: ECMAScript implementation:
In general case the bindings of declarative records are assumed to be stored directly at low level of the implementation (for example, in registers of a virtual machine, thus providing fast access). This is the main difference from the old activation object concept used in ES3.
That is, the specification doesn’t require (and even indirectly doesn’t recommend) to implement declarative records as simple objects which are inefficient in this case. The consequence from this fact is that declarative environment records are not assumed to be exposed directly to the user-level, which means we cannot access these bindings as e.g. properties of the record. Actually, we couldn’t also before, even in ES3 — there activation object also was inaccessible directly to a user (except though Rhino implementation which nevertheless exposed it via __parent__ property).
Potentially, declarative records allow to use complete lexical addressing technique, that is to get the direct access to needed variables without any scope chain lookup — regardless the depth of the nested scope (if the storage is fixed and unchangeable, all variable addresses can be known even at compile time). However, ES5 spec doesn’t mention this fact directly.
So once again, the main thing which we should understand why it was needed to replace old activation object concept with the declarative environment record is first of all the efficiency of the implementation.
Thus, as Brendan Eich also mentioned (the last paragraph) — the activation object implementation in ES3 was just “a bug”: “I will note that there are some real improvements in ES5, in particular to Chapter 10 which now uses declarative binding environments. ES1-3’s abuse of objects for scopes (again I’m to blame for doing so in JS in 1995, economizing on objects needed to implement the language in a big hurry) was a bug, not a feature”.
I don't think I could express this any better.
Related
I'm reading ECMAScript 2023.
It say all execution contexts has "Realm" state component.
And it describes,
a realm consists of a set of intrinsic objects, an ECMAScript global environment, all of the ECMAScript code that is loaded within the scope of that global environment, and other associated state and resources.
I understand realm is for global environment like window(browser), global(node).
And I understand "Global Environment Records" already define global environment once on first code evaluation.
I wonder why a Realm for a execution context is needed.
I'm reading https://tc39.es/ecma262/#sec-execution-contexts.
You can find the current Realm record as "the value of the Realm component of the running execution context".
That term is referenced multiple times across the specification, mostly for bookkeeping to carry-over the value, but in the end to lookup intrinsic prototypes or cached template strings from the current realm.
I'm reading DOM SPEC, and I meet the realm and I don't know what is this. According the SPEC said, it's a something of ECMA. I have learned JS, but I haven't learned about realm!
In addition, a part of content in constructing events section , To create an event using eventInterface, If I'm not mistaken eventInterface means this, but I don't found that need to give realm! Who gives the eventinterface a realm? It is chrome's blink??
From https://tc39.es/ecma262/#sec-code-realms:
Before it is evaluated, all ECMAScript code must be associated with a
realm. Conceptually, a realm consists of a set of intrinsic objects, an ECMAScript global environment, all of the ECMAScript code
that is loaded within the scope of that global environment, and other
associated state and resources.
It is perfectly ok that you did not hear about realm. As a developer we can not create it, a JS engine controls realm creation when starts to execute a code.
When you create an event with new Event(), you create an object in JS and a realm is just a place where an event object is placed.
What's a clean best practice for keeping track of and referring to general JavaScript objects - most likely Dojo-declared - that may have been declared in one area (read module) of an application but that need to be used in another area? We're assuming AMD here.
As mentioned by the "Non-Widgets" section of Dojo's "Using Declarative Syntax" reference guide:
... regular objects don't have a registry like Dijit based widgets do, therefore in order to be able to reference them after you instantiate them, you have to create a reference to them in the global scope.
Global scope? Rrraaughh?! One of the biggest things about "Modern Dojo" is the frowning upon willy-nilly usage of the global namespace:
One of the core concepts of "modern" Dojo is that things in the global namespace are bad. There are numerous reasons for this, but in a complex web application, the global namespace can easily become polluted with all manner of code [...]. This means in "modern" Dojo, if you are about to access something in the global namespace STOP because you are doing something wrong.
Also, from that guide:
Again, repeat after me "the global namespace is bad, the global namespace is bad, I will not use the global namespace, I will not use the global namespace".
In light of that, have there been any other popular ideas expressed about maybe having a general-purpose object registry that exists in the application's context? Is it feasible or perhaps obvious to just Dojo-define a module whose sole purpose is to be a mixed bag of references to objects that get used throughout the application?
What do the recent standards say about extending host objects and their prototypes? E.g. is extending NodeList with a method _forEach or Document with a method _my_query properly defined?
Will I see anything I add to Object.prototype on host objects by the standard?
How do real implementations behave with respect to the relevant standards?
Note: I am not asking whether it is a good idea to extend host objects or their prototypes (although Object.defineProperty makes things a bit easier when it comes to enumerating issues).
ECMAScript 5 does not say anything about host objects' prototype chain.
This is defined in WebIDL.
Specifically, take a look at ECMAScript bindings section, which says:
Unless otherwise specified, the [[Prototype]] internal property of
objects defined in this section is the Object prototype object.
and this, from the following section:
Each ECMAScript global environment ([ECMA-262], section 10.2.3) must
have its own unique set of each of the initial objects, created before
control enters any ECMAScript execution context associated with the
environment, but after the global object for that environment is
created. The [[Prototype]]s of all initial objects in a given global
environment must come from that same global environment.
There's even an example:
iframe.appendChild instanceof Function; // Evaluates to true
Finally, Interface Prototype Object section says (emphasis mine):
The named properties object for a given interface A must have an
internal [[Prototype]] property whose value is as follows:
If A is not declared to inherit from another interface, then the value
of the internal [[Prototype]] property of A is the Array prototype
object ([ECMA-262], section 15.4.4) if the interface was declared with
[ArrayClass], or the Object prototype object otherwise
([ECMA-262], section 15.2.4).
Otherwise, A does inherit from another interface. The value of the
internal [[Prototype]] property of A is the interface prototype object
for the inherited interface.
So now if we look at DOM Level 3, and Document interface we can see that it inherits from Node interface. Node interface does not explicitly inherit from anything else, which means it inherits from Object.prototype.
This is theory :)
In practice, not all browsers follow this behavior, although most of the recent ones certainly do.
The ECMASCRIPT5 spec states :
A web server provides a different host environment for server-side
computation including objects representing requests, clients, and
files; and mechanisms to lock and share data. By using browser-side
and server-side scripting together, it is possible to distribute
computation between the client and server while providing a customised
user interface for a Web-based application.
Each Web browser and server that supports ECMAScript supplies its own host environment,
completing the ECMAScript execution environment.
I do not think it says anything else. This can be read to mean that an implementation can conform to the spec and implement the browser objects however it wants. This has been the case in the past. It does seem logical though to apply the power of the language to the external environment and I believe that all "modern" browsers now do that.
the dom/html elements have an prototype chain as follows:
HTMLElement > Element > Node > Object
hooking in anywhere in the chain where it makes the senes is probly the best bet.
The ECMAScript specification defines an "unique global object that is created before control enters any execution context". This global object is a standard built-in object of ECMAScript, and therefore a native object.
The spec also states:
In addition to the properties defined in this specification the global
object may have additional host defined properties. This may include a
property whose value is the global object itself; for example, in the
HTML document object model the window property of the global object is
the global object itself.
So, in web-browsers, the window object is just a convenient name for the ECMAScript global object, and therefore, the window object is a native ECMAScript object.
Did I get this correctly?
This mostly comes down to a question of what it really means to be a "native object" or a "host object". The ECMAScript specification provides fairly abstract definitions of those terms and there is plenty of room for differing interpretations of the definitions. For example, in the definition of native object, what is the word "semantics" actually talking about. Is it just the primitive object semantics (in ES specified by the [[propName]] internal properties) or does it include application level semantics of the object. The DOM window object certainly has observable application level semantics that are not defined in the ES specification, so if those semantics are considered it can't be a "native object".
The answer is probably much simpler if you look at it as a question of implementation pragmatics. A ES engine implementer probably thinks of any object that is allocated in the ES heap and managed by the ES garbage collector to be a "native ES object". A "host object" would generally be thought of something that exists external to the ES heap and that is accessed using some sort of interoperability layer such as COM, XPCOM, or the V8 embedding API. Depending upon the implementation, the DOM window object might fall into either category. This distinction is probably more relevant to both engine implementers and host providers than any of specification level distinctions.
There will likely be further definitional clarifications in the next edition of the ES specification. There is even a proposal to eliminate the "native" and "host" object terminology: http://wiki.ecmascript.org/doku.php?id=strawman:terminology . However, it isn't clear whether such definitions really have very much practical impact.
I could (and probably will) argue that the specification does not require the global object to be a native object. The spec defines a native object as:
object in an ECMAScript implementation whose semantics are fully defined by this specification rather than by the host environment.
And the definition of a host object:
object supplied by the host environment to complete the execution environment of ECMAScript.
The host object definition could certainly be applied to window, it is an object supplied by the host environment to complete the execution environment of ECMAScript. In addition, Its semantics are not fully defined by the ECMAScript specification.
There's also the case that the ECMAScript engines that run in browsers, such as V8, TraceMonkey, etc, do not create the window object. Rather, it is provided by the DOM (constructed and inheriting from DOMWindow or Window, for example).
Yes, your reasoning sounds about right. As a semi-proof, when a function is executed without explicit this ("in the global context"), its this will evaluate to window inside the function body. But this is really JSVM-specific. For example, have a look at this v8-users message (and the related discussion.) Things are a bit more complicated behind the scenes, but look approximately as you describe to the user.