Learning objects and prototypes from ECMAScript specification

Time:2021-4-21

This article does not study ECMAScript and JavaScript in detail. Because they are interpreted according to ecma-262, the full text uses ECMAScript, or es for short. This article uses the latest standard document (2021-04-05). The link is as follows:https://tc39.es/ecma262/

There are many high-quality articles about the analysis of objects and prototypes, but most of them are mainly about explaining and analyzing phenomena, without analyzing the underlying principles or definitions. Therefore, after reading them, you may only learn the phenomena, but you don’t understand the reasons.

This paper attempts to start from the perspective of language standards, to see how the standard describes the object and prototype, hoping to provide you with a different perspective of understanding. Of course, the skill is limited. If you have any problems, please give me more advice.

Object oriented programming language

It is mentioned in Section 4 overview of the standard that:

ECMAScript is an object-oriented programming language for performing computations and manipulating computational objects within a host environment.

It is also mentioned in subsection 4.3

ECMAScript is object-based: basic language and host facilities are provided by objects, and an ECMAScript program is a cluster of communicating objects.

Through the description of these two paragraphs, we can say exactly:ECMAScript is an object-oriented programming language, which is based on objectThe core competence is also provided by the object.

So what is an object? In section 4.4.6, object is defined as:member of the type Object, that is, members of the object type. At first glance, they look a little confused. Don’t worry. Here’s another explanation:

An object is a collection of properties and has a single prototype object. The prototype may be the null value.

This makes it easier to understand:Object is a collection of properties and has a unique prototype object (possibly null)

Note:The prototype object here is different from the prototype object of the constructor, which is used uniformly in the following[[prototype]]To represent the prototype properties of an object.

Secondly, we need to remind you of the description in Section 4.3.1

Even though ECMAScript includes syntax for class definitions, ECMAScript objects are not fundamentally class-based such as those in C++, Smalltalk, or Java.

That is to say, ES is not an object-oriented language based on classes (creating objects through classes), but a prototype based language (which will be explained gradually later), which is different from C + +, Java and other languages. This is what we usually say, the class in ES is just grammar sugar.

How to create objects

Let’s continue with the description in Section 4.3.1

Instead objects may be created in various ways including via a literal notation or via constructors which create objects and then execute code that initializes all or part of them by assigning initial values to their properties.

Objects are created by using constructors in new expressions

It can be seen that the ways to create objects include:Literal quantity symbolandconstructor There are many different ways to create objects in Hongbao book, but the underlying logic is these two.

Object Literal

The method of literal quantity is very simple. For example, you can create an object literal with the following code:

{
    name: 'lml'
}

constructor

Use the constructor (hereinafter referred to as the constructor) to create objects through the new operator. There are two problems,What is a constructor? How does the new operator create objects?

First, let’s understand the definition of constructor (section 4.4.7)function object that creates and initializes objects

The value of a constructor’s “prototype” property is a prototype object that is used to implement inheritance and shared properties.

In addition, there is a description in Section 4.3.1

Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties.

From these descriptions, we can see that the constructor isFunction objectIts prototype attribute value is a prototype object, which is used to realize inheritance and attribute sharing. Here we can explain that “es is a prototype based object-oriented language”. (note that the prototype object here is different from [[prototype]] above.)

Secondly, let’s look at how the new operator creates objects. I believe you are familiar with this process (because the description process in the standard involves many pre abstract concepts, here we directly refer to the description in MDN)

1.Creates a blank, plain JavaScript object.<br/>2.Adds a property to the new object (\_\_proto\_\_) that links to the constructor function’s prototype object<br/>3.Binds the newly created object instance as the this context (i.e. all references to this in the constructor function now refer to the object created in the first step).<br/>4. Returns this if the function doesn’t return an object.

To summarize the results of this process:
The returned object will have all the properties assigned by this statement in the constructor, and the [[prototype]] property of the returned object points to the prototype object of the constructor.

Let’s take a simple example

function Animal(name) {
    this.name = name;
}

Animal.prototype.getName = function() {
    return this.name;
}

const animal = new Animal('miky');
console.log(name);

Take a look at the results:

Learning objects and prototypes from ECMAScript specification

Prototype and prototype chain

prototype

In fact, the concept of prototype has been mentioned in the previous content. First of all, let’s take a look at the definition in the standard (4.4.8)
object that provides shared properties for other objects

When a constructor creates an object, that object implicitly references the constructor’s “prototype” property for the purpose of resolving property references. <br/><br/>The constructor’s “prototype” property can be referenced by the program expression constructor.prototype, and properties added to an object’s prototype are shared, through inheritance, by all objects sharing the prototype.<br/><br/>Alternatively, a new object may be created with an explicitly specified prototype by using the Object.create built-in function.

The following points should be noted in this description:

  • When the constructor creates an object, the object created will have an implicit reference to the prototype object of the constructor to solve the attribute reference of the object. What is a property reference? It can be simply understood as the search process of object attributes, which will be described in the prototype chain section below.
  • The prototype property of the constructor can be used in the code constructor.prototype Any attribute added to the prototype can be shared by the object created by the constructor.
  • We can also use Object.create Method explicitly specifies [[prototype]] to create an object, which is a method introduced in Es5

We make a simple rewrite based on the above code:

function Animal(name) {
    this.name = name;
}

Animal.prototype.getName = function () {
    return this.name;
}

const animal = new Animal('miky');
console.log(animal.name, animal.category);

Animal.prototype.category = 'animal';

console.log(animal.name, animal.category);

const animalByObjectCreate = Object.create(Animal.prototype);

console.log(animalByObjectCreate.name,  animalByObjectCreate.category);

The output results are as follows: < br / >
miky undefined<br/>
miky animal<br/>
undefined animal

Here we add two points:

  1. As mentioned above, the prototype of the constructor can be accessed directly through the constructor.prototype Get, for example Animal.prototype . How to get the [[prototype]] of an object? There are generally two methods:

    -Through Object.getPrototypeOf (object), which is a method introduced in Es5
    -Through object\_\_ proto\_\_ Property, but this feature is non-standard and is not recommended
    
    For example, in the above example:` Object.getPrototypeOf (animal) ===  Object.getPrototypeOf (animalByObjectCreate) ===  Animal.prototype `
  2. The prototype of a constructor has a “constructor” attribute pointing to the constructor function itself. For example, in the above example:Animal.prototype.constructor === Animal

Prototype chain

Based on the above animal constructor and animal object, we write this Code:console.log(animal.toString()), it will output[object Object]. But no matter the animal object itself or its [[prototype]] object has toString attribute method, why can it still be called normally? This is the role of prototype chain. First of all, let’s take a look at how prototype chain is described in the standard (4.3.1)

Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” property. <br/><br/>Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain.

The general meaning is: an object created by a constructor will have an implicit reference to its prototype object. At the same time, its prototype object will also have an implicit non null reference to its own [[prototype]] object. By analogy, a traversable chain is formed, which isPrototype chain

The role of prototype chain is to analyze the attributes of objects. Let’s take a look at the description in the standard (4.3.1)

When a reference is made to a property in an object, that reference is to the property of that name in the first object in the prototype chain that contains a property of that name.

In other words, first the object mentioned directly is examined for such a property; if that object contains the named property, that is the property to which the reference refers; if that object does not contain the named property, the prototype for that object is examined next; and so on.

When a property reference on an object is required, first check whether the object itself contains the property with the same name; if the object does not contain the property, check the [[prototype]] object of the object, and so on, until the property is found or [[prototype]] is null.

Based on this, we can simply draw the search process of the toString attribute method above. Of course, the real traversal process ends when toString () is found.

Learning objects and prototypes from ECMAScript specification

As for why toString appears in Object.prototype Object, which we’ll talk about in the next section.

Object and function

In many previous topics related to prototypes or prototype chains, function and object are two constructor objects that are easy to get people involved. In this section, we will sort out their prototypes and [[prototype]] through the definition of these two objects in the standard.

In Chapter 20, the standard introduces some basic objects, namely basic objects. The importance of basic objects is self-evident. It can even be said that these basic objects are the origin (ancestor) of all other objects. Section 1 and section 2 of this chapter introduce object and function respectively. We can see the importance of these two.

Before the formal introduction, we need to make it clear that object and function are both objects and constructors. When we understand the topic of related prototype chain, we must first distinguish whether they are used as objects or constructors. This is very important!

Object

The related introduction of object is in section 20.1

Properties of object constructor

20.1.2 Properties of the Object Constructor:<br/>has a [[Prototype]] internal slot whose value is %Function.prototype%.<br/>has a “length” property.<br/>has the following additional properties:…

  1. The implicit prototype of object refers to Function.prototype That is: Object.getPrototypeOf (Object) === Function.prototype
  2. Object has a length property with a value of 1( Object.length ===1), which is not writable by default
  3. Object also has many properties. Among these properties, exceptObject.prototypeIn addition, we are familiar with the static methods of object. You can directly see MDN for details(link)

Object.prototype This is the prototype object of object constructor. The properties on this object will be shared by all instances of object. Let’s focus on this object

Object.prototype Properties of

First, it is defined in the standard, Object.prototype The properties of attribute are as follows: {[[writable]]: false, [[enumerable]]: false, [[configurable]]: false}, so we can’t rewrite or configure the prototype attribute of object. such asObject.prototype = {}It is invalid and will report an error in strict mode. We select the most relevant part of this paper to introduce

  1. has a [[Prototype]] internal slot whose value is null.in other words: Object.getPrototypeOf ( Object.prototype ) === null
  2. The initial value of Object.prototype.constructor is %Object%.
    in other words: Object.prototype.constructor === Object
  3. Other properties are basically method properties that we are very familiar with, including hasownproperty, isprototypeof, toString and so on. Please refer to MDN for details(link)

Properties of object instances

Object instances have no special properties beyond those inherited from the Object prototype object.

Object instance Division Object.prototype There are no special properties other than inherited properties. In addition, the object created through new object (argument) is object instance,The literal quantity of an object can also be regarded as an instance of an objectIts [[prototype]] points to Object.prototype Yes.

Function

Function is introduced in section 20.2

Properties of the function constructor

  1. has a [[Prototype]] internal slot whose value is %Function.prototype%.This is very important, which means: Object.getPrototypeOf (Function) === Function.prototype
  2. Function.length : the initial value is 1
  3. Function.prototype : prototype object of function, and Object.prototype Properties are identical in nature, so they cannot be overridden or configured in any way

Function.prototype Properties of

  1. has a [[Prototype]] internal slot whose value is %Object.prototype%.: means: Object.getPrototypeOf ( Function.prototype ) === Object.prototype
  2. has a "length" property whose value is +0𝔽.andhas a "name" property whose value is the empty String.Which means: Function.prototype.length === 0; Function.prototype.name === ”;
  3. The initial value of Function.prototype.constructor is %Function%.: Function.prototype.constructor === Function
  4. Other properties include the apply, call and bind methods, which are very familiar to us. That’s why our custom function can directly call this method, because the default of our custom function [[prototype]] is to point to Function.prototype These methods can be found along the prototype chain.

There is one extra detail to pay attention to here, that is Function.prototypedoes not have a "prototype" property.At the same time:

The Function prototype object is specified to be a function object to ensure compatibility with ECMAScript code that was created prior to the ECMAScript 2015 specification.

And that means, type of Function.prototype ===’function’ (in short, a function that can be called) is not ‘object’. However, although it is a function object, it has no prototype object and cannot be used as a constructor (using the new operator will report an error). This is a standard downward compatibility issue. Just pay attention to this detail.

Properties of the function instance

First, you need to define the scope of function instances. You can briefly review several ways to create functions

  • Function declaration
  • Function expression
  • Function constructor
  • Function.prototype.bind method
    With the continuous evolution of the standard, different types of functions have been added, including arrow function, generator function, async function and so on. We can regard the functions created in these ways as instances of function objects.
  1. Length attribute:The value of the "length" property is an integral Number that indicates the typical number of arguments expected by the function., which can be understood as the number of parameters expected by the function, but the actual number of parameters passed in may be different when the function is called
  2. Name attribute:The value of the "name" property is a String that is descriptive of the function. In fact, it is the name of the function, and the value of the name attribute of the anonymous function is an empty string
  3. Prototype attribute:
    The prototype attribute is very important. First of all, let’s take a look at the characteristics of this attribute
    { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }。 It can be seen that the prototype property is writable, but it cannot be enumerated and configured, that is, we can point to the prototype of the function instance again.

Function instances that can be used as a constructor have a “prototype” property.

This passage is also very important. First of all, we need to be clear: only function instances that can be used as constructors can have the prototype attribute. The standard also points out that async functions, generator functions, arrow functions and functions created by the bind method do not have the prototype attribute, so these functions cannot be used as constructors.

Function objects created using Function.prototype.bind, or by evaluating a MethodDefinition (that is not a GeneratorMethod or AsyncGeneratorMethod) or an ArrowFunction do not have a “prototype” property.

Continue to see the description of the prototype attribute of the function instance in the standard

Whenever such a Function instance is created another ordinary object is also created and is the initial value of the function’s “prototype” property. Unless otherwise specified, the value of the “prototype” property is used to initialize the [[Prototype]] internal slot of the object created when that function is invoked as a constructor.

It is also a very important description. We can draw the following conclusions:

  • The prototype initial value of a function instance is aordinary object“, which is defined as:object that has the default behaviour for the essential internal methods that must be supported by all objects. This definition may not be very easy to understand, but in the actual implementation, it isAn object instance object with an initial constructor attribute pointing to the constructor function
  • If not specified, when called as a constructor, this initial value is the value of the [[prototype]] attribute of the instance object it creates, which has been mentioned many times in the previous article. Of course, we can also rewrite the prototype point of a functional instance, which is the underlying principle of inheritance.

Through the introduction above, we can draw the prototype chain diagram related to function and object. In fact, as long as we understand the content specified in the standard, it is relatively easy to draw it

Learning objects and prototypes from ECMAScript specification

In addition to object and function, the standard also introduces Boolean, string, array and other built-in objects in detail, and defines the prototype and [[prototype]] attributes of these built-in objects. I believe that after reading, the topics related to prototype and prototype chain can be better understood and remembered.

Recommended Today

Envoy announced alpha version of native support for windows

Author: sunjay Bhatia Since 2016, porting envoy to the windows platform has been an important part of the projectOne of the goalsToday, we are excited to announce the alpha version of envoy’s windows native support. The contributor community has been working hard to bring the rich features of envoy to windows, which is another step […]