download original
(section numbering from "ECMAScript language specification"
(Ecma-262.pdf))
Strongly and dynamically typed.
Based on prototypes (no classes). I.e. there are only objects, which
may have prototypes, which are also objects. Objects have named
properties; property access is delegated to the prototype
(recursively), which is how "inheritance" is
implemented. Specifically, methods are also properties (of type
"function"), and are inherited just like any other properties.
Lexic and syntax are Java/C++ - like. Input to the lexer is a sequence
of Unicode codepoints; Java-like \uxxxx codes are supported.
Built-in Types: Undefined, Null, Boolean, Number, String, Object
For each non-object type except Undefined and Null, there is a
corresponding (native) object type, instances of which will be
automatically created when a value of the corresponding primitive type
is used like an object (autoboxing).
[8.6]
Objects are unordered sets of properties.
Properties have a name (which is a string), a value (which is an
object), and a set of attributes out of {ReadOnly, DontEnum,
ontDelete, Internal}.
Properties with attribute "Internal" ("Internal Properties"):
- have no name (umm...) and aren't directly accessible from
JavaScript.
- purely a specification concept (used in the specification (and here)
for describing the semantics of the language); whether/how they're
implemented is up to the implementation
- defined internal properties: Prototype, Class (that's the "kind" of
the object (...), not the class/prototype), Get(name),
Put(name,value), CanPut(name), Delete(name), DefaultValue,
Construct(...), Call(...) (only in function objects),
HasInstance(value) (only in function objects; determines whether
value has or inherits the function, AFAICS), Scope (only in function
objects; contains the scope chain (see below) of the function),
Match(string, index) (for regexes)
Property access in the source code generally works using either dot
notation (obj.property) or "indexed" access (obj["property"]). In the
latter case, the property name is given as a string, which may be
runtime-determined. obj may be either an identifier (which is resolved
using the current /scope chain/ (see below)), or an expression that
returns an object. More below.
The Delete(name) function, which deletes property name from the
object, is invoked in the source via "delete obj.name". It deletes the
property and returns true iff the property was present.
[8.7]
"Reference" type
- purely a specification concept (used in the specification (and here)
for explaining operators like delete, typeof and such); whether/how
they're implemented is up to the implementation
- represents a readable/writable reference to a property of an object
- encompasses: the object ("base object"), and the name of the
property
- operations: GetBase(Ref), GetPropertyName(Ref), GetValue(V) (returns
V if V is not a Reference, else, returns the value of the property),
PutValue(Ref, Value)
For example, a property access expression (obj.property or
obj["property"]) returns a Reference with obj as the base object and
"property" as the property. Since a Reference is returned, this
expression may be used on the right side as well as on the left side
of an assignment operator (=), i.e. it may be used for reading and
writing the property.
[10]
Code runs in an /execution context/.
Every function and constructor call enters a new execution context,
even if a function is calling itself recursively.
At any time there is a stack of execution contexts that runs up to the
current execution context (in callstack order).
An execution context is associated with a /variable object/, which
contains:
- local variable declarations (they're added to variable object as the
variables are declared)
For function code, the variable object additionally contains:
- the parameters given in the call to the function (with formal
parameter names as the names of the properties)
- an "arguments" property which holds
- a "length" property that contains the number of actual parameters
given
- for the nth (0-based) parameter, an "n" property that contains the
value of the parameter
- a "callee" property that contains the function being executed
(this is so anonymous functions can call themselves recursively)
for example, the print statements in the following function all
print the value of the formal parameter b:
function myf(a,b,c) {
print(b);
//print(arguments.1); //should work in priciple, but confuses the lexer
print(arguments[1]);
}
An execution context is also associated with a /scope chain/, which is
a stack of objects that is used to resolve identifiers. The scope
chain generally contains the variable objects of the current stack of
execution contexts in callstack order, but see below for
details. "with" and "catch" blocks also push an object onto the scope
chain. (there are also blocks ({....}), but they don't create a new
scope.
Additionally, an execution context has a /this/ value, which depends
on the caller (see below).
3 types of executing code/execution contexts:
- global (toplevel)
- variable object = "this" value = the "global object" (a special
object that is created when the JavaScript VM starts and is never
deleted)
- scope chain contains the global object only
- function code (part of a function definition body, or given as a
string to the "Function" constructor)
- scope chain = the variable object, followed by chain contained in
the "Scope" property of the function object
- "this" value provided by caller (see below)
- eval code (created by built-in "eval" function)
- scope chain and "this" value are the ones from the calling
execution context
[11]
Expressions with no real equivalent or different meaning [than] in
Java/C++:
("ref" refers to an expression that returns a Reference (see [8.7]
above))
- array literal: [exp,exp,exp...]
- creates new array as if by "new Array()" (for "new" expressions
see ...)
- no exp (i.e. just ,,) places the numeric value 1 at that position
(TODO: verify; Execute JS extension in Mozilla suggests otherwise)
- object literal:
TODO
- delete ref
- deletes the property of ref, i.e. calls Delete(propname) on the
base object of ref, and returns true iff the property was present
before
- most common usage: delete obj.property
- void expr
- evaluates expr, ignores result, returns undefined
- typeof expr
- returns a string describing the type of expr: for an object type
that's callable (implements Call), return "function" , for an
object type that's not callable, return "object", for primitive
types return "undefined", "object" (for type Null), "boolean",
"number", or "string", respectively. For host objects, the result
is implementation-defined (TODO: elaborate, verify)
E.g. typeof(42) => "number", typeof(new Number(42)) => "object"
- + expr
- calls ToNumber [9.3] on result of expr, i.e. converts result of
expr to a number
- lhs >>> count
- unsigned right shift, e.g. -2>>>1 => 2147483647, -2>>1 => -1
(there's no "unsigned left shift")
- addition (+) [11.6.1]
- if both operands are numbers, adds them; else, converts to String
and concatenates
- relational operators (<, >, <=, >=) [11.8.5]
- if any operand is a number, compares them numerically (returns
undefined if one couldn't be converted to number [TODO: Firefox
appears to return false in such a case; verify!]); else, converts
to String and compares using string compare
- comparison operator (==, !=) [11.9.3]
- for objects, test for identity (like Java); for other types,
*including String*, test for equality, including some type
coercions, e.g. 42=="42", true==1, false==0, true!=42
- strict equals operator (===, !==) [11.9.6]
- like ==, but without the type coercions. e.g. 42!=="42"
- obj instanceof func [11.8.6]
- true if obj delegates behaviour to func (func must be an object,
not a primitive)
- prop in obj [11.8.7]
- test for presence of prop in obj
[12]
(for the semantics of statements:
The Completion type is used to explain the behaviour of statements
(break, continue, return and throw) that perform nonlocal transfers of
control. Values of the Completion type are triples of the form (type,
value, target), where type is one of normal, break, continue, return,
or throw, value is any ECMAScript value or empty, and target is any
ECMAScript identifier or empty.
)
Statements with no real equivalent or different meaning [than] in
Java/C++:
- var v1[=v1v][,v2[=v2v]...]
- variable declaration. defines and optionally initializes
variables. They're added as properties to the variable object of
the current execution scope.
- for (lhs in obj) statement
run statement for each property (not having attribute DontEnum) in
obj and its prototype chain (obj may be any expression), assigning
the name of the property to lhs each time.
- for (var v in obj) statement
run statement for each property (not having attribute DontEnum) in
obj and its prototype chain (obj may be any expression), assigning
the name of the property to the variable v each time. v ist declared
just like in a variable definition outside a loop; no new variable
object is created, i.e. the variable is added to the variable object
of the enclosing execution context (this implies that the variable
continues to exist after the loop ends).
- switch (expr) { case caseexp : statement; [...] [default: statement;] }
any expressions are allowed for expr and the caseexps; they are
compared via === to decide which clause to start executing.
- throw expr
any value may be thrown, not just instances of (some subclass of)
some "exception type".
[13]
functions, objects, prototypes, constructors
- function identifier (args) { body }
set property "identifier" of the current variable object to a
function object F such that:
- F.length == number of args
- F.scope == scope chain of execution context that created the
function context
- PT=new Object(); F.prototype == PT; PT.constructor == F
- when calling F, execute its code in a new execution context, with
scope = (a variable object containing args and the "this" provided
by the caller) + F.scope
In a function call obj.func(args), obj will become the "this".
In a function call func(args), the top of the scope chain will
become the "this". For functions defined in the scope of an
object definition, this will be that object
- new fcn(args)
(fcn must be any function object)
- does the following:
newobj = new Object()
newobj.[[prototype]] = fcn.prototype [or Object.prototype if
fcn.prototype is undefined)
call fcn(args) with this == newobj
return newobj [or the return value of the call, if it was an object]
- so the prototype of obj = new fcn(args) is *not* fcn, but the
*prototype of fcn*. This means that properties of fcn cannot be
accessed via obj. In practice, this is used for "private"
variables/functions
---
TODO: don't forget:
- Date, Regexp, ...
- ...
back to javascript
(C) 1998-2017 Olaf Klischat <olaf.klischat@gmail.com>