ECMAScript 4 Netscape Proposal
Core Language
Concepts
|
Wednesday, September 4, 2002
A value is an entity that can be stored in a variable, passed to a function, or returned from a function. Sample values include:
undefined
null
5
(a number)true
(a boolean)"Kilopi"
(a string)[1, 5, false]
(a three-element array){a:3, b:7}
(an object with two properties)function (x) {return x*x}
(a function)String
(a class, a function, and a type)A type t represents three things:
The set S indicates which values are considered to be members of type t. We write v t to indicate that value v is a member of type t. The mapping I indicates how values may be implicitly coerced to type t. For each value v already in S, the mapping I must map v to itself. The mapping E indicates how values may be explicitly coerced to type t. For each value v in the domain of I, E must map v to the same value as I maps v. In other words, any implicit coercion is also an explicit coercion but not vice versa.
A value can be a member of multiple sets, and, in general, a value belongs to more than one type. Thus, it is generally not useful to ask about the type of a value; one may ask instead whether a value belongs to some given type. There can also exist two different types with the same set of values but different coercion mappings.
On the other hand, a variable does have a particular type. If we declare a variable x of type t, then whatever value is held in x is guaranteed to be a member of type t, and we can assign any value of type t to x. We may also be able to assign a value v t to x if type t’s mapping specifies an implicit coercion for value v; in this case the coerced value is stored in x.
Every type represents some set of values but not every set of values is represented by some type (this is required for logical consistency — there are uncountably infinitely many sets of values but only countably infinitely many types).
Every type is also itself a value and can be stored in a variable, passed to a function, or returned from a function.
If type a’s set of values is a subset of type b’s set of values, then we say that that type a is a subtype of type b. We denote this as a b.
Subtyping is transitive, so if a b and b c, then a c. Subtyping is also reflexive: a a. Also, if v t and t s, then v s.
The set of all values is represented by the type Object
, which
is the supertype of all types. A variable with type Object
can hold any value.
The set of no values is represented by the type Never
, which is
the subtype of all types. A function with the return type Never
cannot return.
A class is a template for creating similar values, often called objects or instances. These instances generally share characteristics such as common methods and properties.
Every class is also a type and a value. When used as a type, a class represents the set of all possible instances of that class.
A class C can be derived from a superclass S. Class C can then inherit characteristics of class S. Every instance of C is also an instance of S, but not vice versa, which, by the definition of subtyping above, implies that C S when we consider C and S as types.
The subclass relation imposes a hierarchy relation on the set of all classes. ECMAScript 4 currently does not support multiple inheritance, although this is a possible future direction. If multiple inheritance were allowed, the subclass relation would impose a partial order on the set of all classes.
A class typically contains a set of members, which can be variables, functions, etc. Members are classified as either instance or global members. Instance members become properties of instances of the class. Global members become properties (sometimes called class properties) of the class object itself; a class has only one global member with a given name.
Members can have attributes which modify their behavior.
An instance (sometimes called an object) contains a set of properties. An instance belongs to a particular class and must have properties for the instance members defined in that class and its ancestors; these bindings are made when the instance is created. An instance may also have additional dynamic properties, which can be added and deleted any time after the instance has been created.
Unless specified otherwise, each separately created instance has a distinct identity. The ===
operator returns
false
when applied to two different instances or true
when applied to the same instance (with the
exception of NaN
, which always compares unequal to itself).
Instances provide the appearance of lasting forever, although an implementation is expected to garbage-collect them when they are no longer reachable.
A property is a runtime binding of a property name to a value. The values of some properties can change. Properties can be fixed or dynamic. Fixed properties are declared as members of a class definition and are created at the time the object is constructed. Dynamic properties can be added to an object at any time after the object was created. All ECMAScript 3 properties are dynamic.
Properties can have attributes. Fixed properties inherit their attributes from the corresponding members.
A property name identifies a property of an instance and consists
of a namespace N, an identifier id, and a class C.
There is no language syntax for fully specifying a property name; in this specification property names are denoted using the
notation N::
idC. If the property is fixed, then
C is the class in which the corresponding member is defined. If the property is dynamic,
then C is the instance’s most derived class.
An instance can contain at most one property for each property name. An instance can contain multiple
properties with the same namespace N and name id but different classes C; in this case the
property with the most derived class C is said to override the others. The overridden properties are still
present in the instance and can be accessed using the super
operator.
A scope represents one of the following delimited portions of ECMAScript source code. Some scopes are further distinguished as being regional scopes, as indicated in the table below.
Nonterminal | Regional | Description |
---|---|---|
Program | yes | The top level of a program |
PackageDefinition | yes | A package definition |
ClassDefinition | yes | A class definition |
FunctionDefinition | yes | A function definition |
FunctionExpression | yes | A function expression |
Block | no* | A block (but not a group of directives prefixed with attributes) |
ForStatement | no* | A for statement |
CatchClause | no* | A catch clause of a try statement |
*These three scopes become regional scopes if the next outer scope is a class scope.
A scope is a static entity that does not change while an ECMAScript program is running (except that if the program calls
eval
then new ECMAScript source code will be created which may share existing scopes or create its own scopes).
A scope other than the top level of a program (the global scope) is always contained inside another scope. If two scopes overlap,
one must be contained entirely within the other, so scopes form a hierarchy.
Scope information is used at run time to help with variable and property lookups and visibility checks.
A scope should not be confused with an activation frame. A scope should also not be confused with a namespace.
An activation frame contains a set of runtime bindings of all qualified names defined in a scope to values. A new activation frame comes into existence each time the scope is entered. A function closure captures a reference to the activation frame in which it was created. Activation frames provide the appearance of lasting forever, although an implementation is expected to discard them after the scope is exited and any closures that captured the activation frame have been garbage-collected.
The values of some bindings in an activation frame can change. The bindings’ values begin in an uninitialized state. It is an error to read a binding in an uninitialized state.
Activation frame bindings can have attributes which modify their behavior.
A qualified name consists of a namespace N and an identifier id.
In this specification qualified names are denoted using the notation N::
id. An activation
frame can contain at most one binding for each qualified name.
A namespace parametrizes names. A namespace attribute N may be attached to the declaration of any name
or property p. That namespace then acts like a lock on accesses to p: another piece of code may access
p only by qualifying it with that namespace using N::
p or by executing a use namespace(
N)
directive in a scope surrounding the access of p. Unlike in C++, a namespace is not a scope and does not contain
any names or properties itself; a namespace only modifies the accessibility and visibility of names or properties attached
to activation frames, classes, or objects.
A namespace is a value that can be passed as the first operand of the ::
operator.
public
is the default namespace for declarations; a use namespace(public)
directive is implicit
around the global scope. Each package has a predefined, anonymous internal
namespace and each class has a predefined,
anonymous private
namespace; these provide access control. User-defined namespaces may also be used for more
flexible access control.
Waldemar Horwat Last modified Wednesday, September 4, 2002 |