This article looks at the data types in ES.

The data type

There are two types of data in ES.

One is the language type, which is the usual 12,’xccurate’,undefined and so on.

Canonical types are values that describe ECMAScript language structures and ECMAScript language types, such as references, lists, and so on.

Let’s start with the basic language types.

Language type

There are seven types of ES:

  • UndefinedType: has only one value:undefined.
  • NullType: has only one value:null.
  • BooleanType: has two values:trueandfalse.
  • StringType: is a collection of all ordered sequences of zero or more 16-bit unsigned integer values, up to 2^ 53-1 elements in length. I don’t want to go into the exact definition of it๐Ÿ”—.
  • SymbolType: Each value is unique, for exampleSymbol('s1mple'). Some built-in Symbol values are defined in the specification๐Ÿ”—.
  • NumberType: a total of 18437736874454810627 values, includingNaN,+Infinity,-Infinity. Define it in detail๐Ÿ”—.
  • ObjectType: For example:let a = {}. That’s a lot to talk about. See below.

The Object type

Object is a collection of properties.

Properties are identified using key-value pairs, and the key value of the property can be of type String (which can be empty ‘”) or Symbol.

Attributes fall into two categories:

  • Data attributesdata property: combines the key value with aES language valueAnd a set ofBoolean attributeAssociated with it.
  • Accessor propertiesaccessor property: Combines key values with one or twoAccessor functionAnd a set ofBoolean attributeAssociated with it. Accessor functions are used to store or retrieve ECMAScript language values associated with attributes.

All objects are logical collections of properties. But many kinds of objects have different semantics for accessing and manipulating their properties.

Ordinary objects are the most common form of objects and have default object semantics.

An Exotic object is any form of object whose attribute semantics are different from the default semantics.

Properties of attributes

Attribute is used to define and explain the state of object attributes.

The features of the data attribute are [[Value]], [[Writable]], [[Enumerable]], and [[64x].

The accessor properties are [[Get]], [[Set]], [[Enumerable]], [[64x]].

Their meaning is not much to say, just look it up, not the point.

Object internal methods and internal slots

Object Internal method: Its algorithm specifies the actual semantics of the Object. Not part of the ES language, defined by the specification, for illustrative purposes only. Internal methods are polymorphic, and different objects may perform different algorithms.

Internal Slots: An Internal state for the algorithm to use. Not an object property, not inherited. The value may be a canonical type or a language type. (For ease of understanding, you can actually think of it as an internal property, not visible to the developer. And the internal slot name is too awkward ๐Ÿ˜‚, hereafter called internal properties.)

These two are defined by the specification to describe the behavior of ES objects, which can be simply understood as functions and properties of objects.

** Internal methods and attributes are identified by double parentheses: [[XXXXX]]**

The table ๐Ÿ”— summarizes the necessary internal methods for an object. Each object must have its algorithm, but it is not necessarily the same.

Just to recap what’s there:

[[GetPrototypeOf]], [[SetPrototypeOf]] : Gets and sets the prototype of the object.

[[IsExtensible]] : Determines whether additional properties can be added to this object.

[[PreventExtensions]] : Determines whether new properties can be added to this object. // What’s the difference between this and the one above

[[GetOwnProperty]], [[DefineOwnProperty]] : Gets and sets the property descriptor for the property of the object (named as a parameter).

[[HasProperty]] : Determines whether an object has its own or inherited properties (named parameters).

[[Get]], [[Set]] : Gets and sets the value of the property named parameter.

[[Delete]] : Deletes the properties of the object (whose name is parameter).

[[OwnPropertyKeys]] : Returns a list of properties of the object itself.

As mentioned in the previous article, functions are callable objects. So it has an extra internal method: [[Call]]. Constructors have an extra inner method: [[Construct]].

In other words, the [[Call]] method of the function object is called when the function is executed. The [[Construct]] method of the constructor is executed when the object is constructed.

Their actual semantics will be examined in due course.

The following section, ๐Ÿ”—, describes the immutable behavior of these basic internal methods. For example, the return type specification, and so on. These rules are mandatory for all objects, although their algorithms may differ. These edges and corners don’t need developers to worry about, so I won’t go into details.

Internal object

Intrinsic Objects are built-in Objects that the algorithm in the specification refers to. Things like Array, String, Object and their prototypes.

See table ๐Ÿ”— in detail, do not list, until the use of time to say again.

By the way, this set of built-in objects is one for each Realm. What is a realm? For example, the Array object in an IFrame on a page is not the same as the Array object on that page. They are both domains.

Specification types

Canonical types are used within the specification to describe ES semantics and cannot be used outside the specification.

List and Record types

The List type is used to explain the execution of a List of function arguments. A value of type List is a simple ordered sequence of List elements containing a single value.

This is simply an array of ES, but at the time the specification was written there was no array type of ES, so we used List to describe types like arrays. For example, ยซ1,2ยป defines a List value that has two elements, each initialized to a specific value. A new empty list can be represented as ยซยป.

(The List implementation in ES Engine262 is an array.)

The Record type is used to describe data aggregation in the canonical algorithm. A Record value consists of one or more named fields. The value of each field is an ECMAScript value or an abstract value represented by a name associated with the Record type. Field names are always enclosed in double parentheses, such as [[value]].

R.[[Field2]] is short for the R field named [[Field2]].

(In Engine262, Record is implemented with objects.)

Set and Relation

The Set type is used to explain an unordered Set of elements used in an in-memory model where no element appears more than once. Elements can be added to or removed from a collection. Sets can be merged, crossed, or subtracted from each other.

The Relation type is used to explain constraints on sets.

// I don’t know about ๐Ÿ˜‚.

Completion Record type

The Completion Record type is used to explain the runtime propagation of values and control flow.

Each runtime semantics in the ECMAScript specification explicitly or implicitly returns a completed Completion Record reporting its results.

(This definition is a mouthful, but it’s not so important that it’s easy to understand.)

Completion Record is a Record, so you can describe it as an object, and it has three fields:

Completion Record = {
  [[type]] // There are five types of Completion: Normal, break, continue, return, and throw
  [[value]] If [[type]] is normal,return, throw
  [[target]] // The target label of the direction control transfer. The value is string or empty only when [[type]] is break or continue
}
Copy the code

The Completion Record returned when [[type]] is normal is called Normal Completion. The rest are called the abrupt completion.

In the various abstract operations of the specification (also known as algorithms), there is a Return Infinity, which implicitly returns a Completion Record, equivalent to a Return NormalCompletion(“Infinity”).

Specifications are very common in algorithms, right? Call(exoticToPrim, input, ยซ hint ยป) The opening statement, which means:

Let res be the result of performing the Call(exoticToPrim, input, ยซ hint ยป) abstraction operation.

As mentioned above, each runtime semantics shows or implicitly returns a Completion Record, so

If res is an abrupt completion, return res.

If res is a Completion Record, res = res.[[value]].

You’ll see it again! ToString(key) is prefixed with! “, which means:

Let res to ToString (key)

Assert that the RES is not an abrupt completion

If res is a Completion Record, res.[[value]] = res.

These two are different. Look at the assignment statement at the end.

While reading the specification, ignore its practical significance for the time being.

Reference types

The Reference type is used to explain the behavior of operators such as delete, Typeof, assignment operators, super keywords, and other language characteristics.

(LHS, in my opinion, to solve the problem of who is where)

A Reference is the resolved name or property binding. Reference consists of three components:

{
  BaseValue / / value is: undefined, Object, Boolean, String, Symbol, Number, Environment Record.
  ReferencedName // String or Symbol value.
  StrictReference // A Boolean value indicating whether strict mode is used
}
Copy the code

A base value of undefined means that the reference cannot be resolved.

There is also a Super Reference, which represents the name binding expressed using the Super keyword. There is an additional thisValue component whose base value will never be an Environment Record.

Here’s an example:

let a = {
  b: 'test'
}
Copy the code

Where, when looking for b, we will get a Reference type, whose value is:

{
  BaseValue: a,
  ReferencedName: b,
  StrictReference: false
}
Copy the code

The specification also specifies some abstraction operations for it, such as GetBase, GetReferencedName, IsStrictReference, and so on.

Just to be brief:

  • GetBase (V) : V is a Reference. Get the base component of V.

  • GetReferencedName (V) : V is a Reference. Gets the name component of V.

  • IsStrictReference (V) : V is a Reference. Get strict component of V.

  • HasPrimitiveBase (V) : V is a Reference. Base for judging V component values are these original value Boolean, String, Symbol and Number.

  • IsPropertyReference (V) : V is a Reference. Used to determine whether V is an attribute Reference, that is, its base value is Object or HasPrimitiveBase (V) is true.

  • IsUnresolvableReference (V) : V is a Reference. Reference is used to determine whether the Reference cannot be parsed, i.e. the base value is undefined.

  • IsSuperReference (V) : V is a Reference. If V is Super Reference, thisValue component or not.

  • GetValue (V) :

    If V is not Reference, return V directly

    Is the Reference,

    ReferenceError is raised when Reference cannot be parsed. Uncaught ReferenceError: A is not defined

    Is the attribute Reference,

    If it is the base of the original value of a Boolean, String, Symbol, Number,

    Just let base = ToObject(Base). โญ•1 (in the future, where there is red circle is the place with notes, circle, focus ๐Ÿ˜‚)

    Return base.[[Get]](GetReferencedName(V), GetThisValue(V)).

    Then Reference must be Environment Record,

    Return base.getBindingValue (GetReferencedName(V), IsStrictReference(V)).

    โญ•1: This is why we can use methods on string and number objects when they are not objects.

    For example, when using ‘SOMEBODY’.tolocalelowerCase (), you need to run an LHS query to find out what ‘SOMEBODY’. ToLocaleLowerCase ‘is before you can execute the function. Reference:

    {
      BaseValue: 'SOMEBODY'.ReferencedName: toLocaleLowerCase,
      StrictReference: false
    }
    Copy the code

    Determine that ‘SOMEBODY’ is a primitive value, ToObject it, which turns it into a String and gets the toLocaleLowerCase method.

    When Reference is Environment Record, the binding value of Environment Record is probably obtained because Environment Record has not been said.

  • PutValue (V, W) :

    If V is not Reference, a ReferenceError is raised.

    If Reference cannot be parsed,

    ReferenceError is raised for strict mode.

    Otherwise, โญ• 2

    Get the GlobalObject,

    Perform the Set(globalObj, GetReferencedName(V), W, false) operation to return the result.

    If it is an attribute Reference,

    If it is the base of the original value of a Boolean, String, Symbol, Number, ToObjet.

    Base.[[Set]](GetReferencedName(V), W, GetThisValue(V))

    If the return value is false and in strict mode, ReferenceError is raised.

    So it must be Environment Record,

    Execute base.setMutableBinding (GetReferencedName(V), W, IsStrictReference(V)). Returns the result.

    โญ•2: This place is the usual algorithm when we do the assignment operation a = 1 without declaring variables, it will create a new attribute on the global object and assign its value.

    When Reference is an Environment Record, the most likely operation is to create a mutable binding on the base of type Environment Record and assign the value.

  • GetThisValue (V) : Returns the value of thisValue component when it is a SuperReference.

  • InitializeReferencedBinding (V, W) : as the base for the Environment Record, perform InitializeBinding (GetReferencedName (V), W) operation, the initialization is binding.

The Reference type is one of the more important canonical types, and understanding the ES runtime semantics doesn’t get around it, so it covers a lot, unlike the Completion Record type, which doesn’t matter much for understanding the semantics on the one hand, and I don’t know much about ๐Ÿ˜‚ on the other.

The Property type Descriptor

The property descriptor type, the operation used to explain the properties of an object property, has a value of type Record, divided into data property descriptors and accessor property descriptors.

Its abstract operation I will not say more, their understanding of the line ๐Ÿ”—.

Lexical Environment Type The type of Environment Record

The following section describes scope, identifier binding, and so on in ES.

As an added bonus, WHEN I saw a lot of tutorials using Activation objects to explain scopes and closures, I wondered why they weren’t in the specification until I looked them up and discovered that AO and VO were part of the ES3 specification, but not since ES5.

Data Blocks

Used to describe different and variable sequences of byte size (8 bits) values. I also do not understand temporarily, did not say ๐Ÿ˜‚ first.


This is the end of this first, I was going to finish the next chapter of abstract operations, but I found it a little long when I wrote it down, so I’ll talk about it in the next chapter. The second part focuses on type testing, type conversions, and basic operations on objects.

Finally, if it is useful to you, please pay attention to, star, github warehouse ๐Ÿ”—. ๐Ÿ™ ๐Ÿ™