Understanding ECMAScript Runtime Semantics, Algorithm Steps, and Abstract Operations
This article explains ECMAScript runtime semantics, the structure of algorithm steps, abstract operations, internal methods and slots, as well as completion records and the shorthand symbols ? and ! used in the specification, providing clear examples and code snippets for JavaScript developers.
Hello, I am "Early Evening Wind". This is the second article in the series "Understanding JavaScript from the ECMAScript Specification and Browser Engine Perspective". It is strongly recommended to read the articles in order; the full series can be accessed via the column link above.
Runtime Semantics
The official definition of runtime semantics is: Algorithms which specify semantics that must be called at runtime are called runtime semantics . In simple terms, it describes what happens when we call a JavaScript API or use a language construct, such as Number('23') or a for‑in loop.
Most runtime semantics are expressed as a series of algorithm steps .
Algorithm Steps
Algorithm steps consist of a multi‑level ordered list whose numbering follows the pattern number → lower‑case letter → lower‑case Roman numeral . For example:
1. Top‑level step a. Substep. b. Substep. i. Subsubstep. 1. Subsubsubstep a. Subsubsubsubstep i. SubsubsubsubsubstepThese steps are pseudo‑code and do not represent a concrete implementation.
An example from the specification shows the algorithm steps for the Boolean(value) API (image below).
The algorithm demonstrates how a value is converted to a Boolean, invoking the abstract operation ToBoolean in the first step.
Abstract Operations
To avoid repetition, the specification abstracts frequently used algorithm steps into abstract operations , which resemble reusable functions. They are invoked similarly to normal function calls, e.g., OperationName(arg1, arg2) . Abstract operations exist only in the spec and are not part of the JavaScript language.
The ToBoolean abstract operation is defined in the spec (image below) and belongs to the "Type Conversion" category of abstract operations.
Abstract operations are divided into four groups: Type Conversion, Testing and Comparison Operations, Operations on Objects, and Operations on Iterator Objects.
Internal Methods
Objects in ECMAScript have a set of internal methods that define their runtime behavior. For an ordinary object, the internal method [[GetPrototypeOf]] is defined as shown in the following diagram:
The same internal method also has definitions for module‑namespace exotic objects and Proxy exotic objects.
Internal Slots
Internal slots store an object's hidden state and are used by various specification algorithms. They are initialized to undefined and are not accessible as regular JavaScript properties. For example, the prototype of an object is exposed as the internal slot [[Prototype]] , which is returned by Object.getPrototypeOf() as O.[[Prototype]] .
Internal slots can hold values of either ECMAScript Language Types (Undefined, Null, Boolean, String, Symbol, Number, BigInt, Object) or ECMAScript Specification Types (Reference, List, Completion, Property Descriptor, Environment Record, Abstract Closure, Data Block).
Completion Records
A Completion Record explains the runtime propagation of values and control flow (e.g., break , continue , return , throw ). It has three fields, the most important being [[Type]] , which can be one of five kinds: normal, break, continue, return, or throw. An abrupt completion is any type other than normal.
Normal completions are the most common; every abstract operation implicitly returns a normal completion that wraps the actual value.
1. Return true. // equivalent to 1. Return NormalCompletion(true).
// NormalCompletion structure { Type: normal, Value: value, Target: empty }Symbols ? and !
In the specification, the question‑mark ? and exclamation‑mark ! are shorthand notations, not JavaScript operators. The ? represents the ReturnIfAbrupt abstract operation, which checks a completion record: if it is abrupt, the record is returned; otherwise the contained value is extracted.
For example, the algorithm step ? OperationName() is equivalent to ReturnIfAbrupt(OperationName()) . The exclamation‑mark version ! OperationName() asserts that the result is a normal completion and then extracts its value.
Let val be OperationName(). Assert: val is a normal completion. Set val to val.Value.
Example: Object.prototype.isPrototypeOf
The following excerpt shows how the shorthand symbols are used in the algorithm for Object.prototype.isPrototypeOf :
# 20.1.3.3 Object.prototype.isPrototypeOf ( V )
This method performs the following steps when called:
1. If V is not an Object, return false.
2. Let O be ToObject(this value).
3. Assert: O is a Completion Record.
4. If O is an abrupt completion, return Completion(O).
5. Else, set O to O.[[Value]].
6. Repeat,
a. Set V to V.[[GetPrototypeOf]]().
b. Assert: V is a Completion Record.
c. If V is an abrupt completion, return Completion(V).
d. Else, set V to V.[[Value]].
e. If V is null return false.
f. Let temp be SameValue(O, V).
g. Assert: temp is not an abrupt completion.
h. Set temp be temp.[[Value]].
i. If temp is true return trueUnderstanding these notations helps to read and interpret the ECMAScript specification more effectively.
References
ECMAScript Specification
How to Read the ECMAScript Specification
Understanding the ECMAScript spec, part 1
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.