How JavaScript objects are created

In JavaScript, there are two ways to create objects: object literals and using new expressions. Object literals are a flexible and convenient way to write. For example:

Var o1 = {p: "I'm in Object literal", alertP:function(){alert(this.p); }}Copy the code

Thus, an object o1 with a member variable P and a member method alertP is created from the object literal. This way of writing does not require a constructor to be defined and is therefore beyond the scope of this article. The disadvantage of this approach is that each creation of a new object requires a complete definition statement, which makes it difficult to create a large number of objects of the same type and makes it difficult to use advanced features such as inheritance.

New expressions are used in conjunction with constructors, such as new String(” a String “), which calls the built-in String function to construct a String object. Create an object that does the same thing by defining the constructor and then calling the new expression:

Function CO(){this.p = "I'm in a constructed object"; this.alertP = function(){ alert(this.p); } } var o2 = newCO();Copy the code

So what happens when you use the new operator to call a constructor? It was very simple. Four things happened:

var obj  ={};
obj.__proto__ = CO.prototype;
CO.call(obj);
return obj;
Copy the code

In the first line, create an empty object obj.

The second line points the empty object’s __proto__ member to the constructor object’s Prototype member, which is the most critical step, described in more detail below.

In line 3, we assign the constructor’s scope to the new object, so this in the CA function points to the new object obj, and then call CO. So we assign a member variable P to obj, and the value of the member variable is “I ‘min constructed object”.

Line 4, return the new object obj. This is especially the case when a constructor contains a return statement, as described below.

Define JavaScript constructors correctly

Unlike other mainstream programming languages, JavaScript’s constructor does not exist as a specific method of a class; When any ordinary function is used to create a class of objects, it is called a constructor, or constructor. To be a true constructor, a function must satisfy the following conditions:

Set the properties of the new object (this) inside the function, usually by adding properties and methods.

2. Constructors can contain return statements (not recommended), but the return value must be this or some other non-object type. The constructor CO defined above is a standard, simple constructor. The following example defines a function C1 that returns an object. We can call it using a new expression that correctly returns an object:

Function C1(){var o = {p: "I'm in C1"} return o; } var o1 = new C1(); alert(o1.p); / / I 'm p in C1Copy the code

However, this approach is not recommended because the prototype of Object O1 is the prototype of the Object O defined inside function C1 (object.prototype). This is equivalent to executing the first three steps of a normal new expression and returning the value of C1 in the fourth step. This approach is also inconvenient to create a large number of objects of the same type, is not conducive to the use of advanced features such as inheritance, and is prone to confusion and should be abandoned.

It is a measure of JavaScript’s flexibility that a constructor can be used as a normal function in some cases. The following example defines C2 as a “multi-purpose” function:

function C2(a, b){ this.p = a + b; this.alertP = function(){ alert(this.p); } return this.p; Var C2 = new C2(2,3); var C2 = new C2(2,3); c2.alertP(); // result is 5 alert(C2(2, 3)); // The result is 5Copy the code

This function can be used either as a constructor to construct an object or as a normal function. When used as a normal function, it takes two arguments and returns the sum of the two. For code readability and maintainability, it is recommended that functions that are constructors be unadulterated with code other than constructors; Similarly, generic function functions should not be used as constructors.

Why use constructors

From the above definition, on the surface, constructors seem to simply initialize a newly created object, adding member variables and methods; However, constructors do much more than that. To illustrate the significance of using constructors, let’s review the previous example. Var o2 = new CO(); When you create an object, four things happen:

var obj  ={};
obj.__proto__ = CO.prototype;
CO.call(obj);
return obj;
Copy the code

Let’s say the most important thing is the second step, which assigns the __prop__ property of the newly generated object to the constructor’s Prototype property so that all objects created through the constructor can share the same prototype. This means that all objects created by the same constructor inherit from the same object, so they are all objects of the same class. The details of prototype and inheritance will be covered in another article.

The __prop__ attribute does not exist in the JavaScript standard, but it is now a standard attribute by default in some mainstream JavaScript execution environments to point to constructor stereotypes. This property is not visible by default, and the details of implementation vary from execution environment to execution environment. For example, Internet Explorer does not have this property. All we need to know is that there is a pointer to the constructor prototype inside the JavaScript object, that the pointer is automatically assigned when a new expression is called, and that we should not modify it.

In the four steps of constructing an object, we can see that, except for the second step, we do not need to use new expressions to achieve other steps, so new expressions are not only a simplification of these four steps, but also the only way to achieve inheritance.

Where it’s easy to get confused

One area of confusion about JavaScript constructors is the stereotype’s constructor property. In JavaScript, every function has the default prototype object property, which by default contains two member properties: constructor and __proto__. The details of the stereotype are beyond this article; we are now concerned with the constructor property.

In object-oriented thinking, we say that a constructor is equivalent to the definition of a “class,” so it would be a mistake to think that the constructor property is the actual constructor of the class, and that when a new expression creates an object, the constructor is called directly to initialize the object. The actual process of new expression execution was described above (four steps), of which the third step is used to initialize the object, and the initialization function called is the “class function” itself, not constructor. This may not be easy to understand without considering the question, but let’s give an example to illustrate:

function C3(a, b){ this.p = a + b; this.alertP = function(){ alert(this.p); Function fake(){this.p = 100;}}// We define a function to override the constructor of the C3 prototype, attempting to change the value of the attribute p. } C3.prototype.constructor = fake; Constructor var C3 = new C3(2,3); c3.alertP(); // The result is still 5Copy the code

The above code manually changes the constructor function in the C3 prototype, but it has no real effect on the creation of the C3 object, as you can see in the new expression, only the constructor itself initializes the object. So what does the constructor property do? In general, we can use the constructor attribute to test the type of an object:

Var myArray on = [1, 2, 3]; (myArray.constructor == Array); // trueCopy the code

This works for simple objects, but not for complex situations such as inheritance or cross-windows:

function f() { this.foo = 1; } function s() { this.bar = 2; } s.prototype = new f(); Var son = new s(); Constructor == s; // Create a subclass object using the constructor (son.constructor == s); // false (son.constructor == f); // trueCopy the code

Such results may not be what you expect, so be careful when using the constructor attribute, or avoid it altogether.

How JavaScript objects are created

In JavaScript, there are two ways to create objects: object literals and using new expressions. Object literals are a flexible and convenient way to write. For example:

Var o1 = {p: "I'm in Object literal", alertP:function(){alert(this.p); }}Copy the code

Thus, an object o1 with a member variable P and a member method alertP is created from the object literal. This way of writing does not require a constructor to be defined and is therefore beyond the scope of this article. The disadvantage of this approach is that each creation of a new object requires a complete definition statement, which makes it difficult to create a large number of objects of the same type and makes it difficult to use advanced features such as inheritance.

New expressions are used in conjunction with constructors, such as new String(” a String “), which calls the built-in String function to construct a String object. Create an object that does the same thing by defining the constructor and then calling the new expression:

Function CO(){this.p = "I'm in a constructed object"; this.alertP = function(){ alert(this.p); } } var o2 = newCO();Copy the code

So what happens when you use the new operator to call a constructor? It was very simple. Four things happened:

var obj  ={};
obj.__proto__ = CO.prototype;
CO.call(obj);
return obj;
Copy the code

In the first line, create an empty object obj.

The second line points the empty object’s __proto__ member to the constructor object’s Prototype member, which is the most critical step, described in more detail below.

In line 3, we assign the constructor’s scope to the new object, so this in the CA function points to the new object obj, and then call CO. So we assign a member variable P to obj, and the value of the member variable is “I ‘min constructed object”.

Line 4, return the new object obj. This is especially the case when a constructor contains a return statement, as described below.

Define JavaScript constructors correctly

Unlike other mainstream programming languages, JavaScript’s constructor does not exist as a specific method of a class; When any ordinary function is used to create a class of objects, it is called a constructor, or constructor. To be a true constructor, a function must satisfy the following conditions:

Set the properties of the new object (this) inside the function, usually by adding properties and methods.

2. Constructors can contain return statements (not recommended), but the return value must be this or some other non-object type.

The constructor CO defined above is a standard, simple constructor. The following example defines a function C1 that returns an object. We can call it using a new expression that correctly returns an object:

Function C1(){var o = {p: "I'm in C1"} return o; } var o1 = new C1(); alert(o1.p); / / I 'm p in C1Copy the code

However, this approach is not recommended because the prototype of Object O1 is the prototype of the Object O defined inside function C1 (object.prototype). This is equivalent to executing the first three steps of a normal new expression and returning the value of C1 in the fourth step. This approach is also inconvenient to create a large number of objects of the same type, is not conducive to the use of advanced features such as inheritance, and is prone to confusion and should be abandoned.

It is a measure of JavaScript’s flexibility that a constructor can be used as a normal function in some cases. The following example defines C2 as a “multi-purpose” function:

function C2(a, b){ this.p = a + b; this.alertP = function(){ alert(this.p); } return this.p; Var C2 = new C2(2,3); var C2 = new C2(2,3); c2.alertP(); // result is 5 alert(C2(2, 3)); // The result is 5Copy the code

This function can be used either as a constructor to construct an object or as a normal function. When used as a normal function, it takes two arguments and returns the sum of the two. For code readability and maintainability, it is recommended that functions that are constructors be unadulterated with code other than constructors; Similarly, generic function functions should not be used as constructors.

From the above definition, it seems that a constructor simply initializes a newly created object, adding some member variables and methods; However, constructors do much more than that. To illustrate the significance of using constructors, let’s review the previous example. Var o2 = new CO(); When you create an object, four things happen:

var obj  ={};
obj.__proto__ = CO.prototype;
CO.call(obj);
return obj;
Copy the code

Let’s say the most important thing is the second step, which assigns the __prop__ property of the newly generated object to the constructor’s Prototype property so that all objects created through the constructor can share the same prototype. This means that all objects created by the same constructor inherit from the same object, so they are all objects of the same class. The details of prototype and inheritance will be covered in another article.

The __prop__ attribute does not exist in the JavaScript standard, but it is now a standard attribute by default in some mainstream JavaScript execution environments to point to constructor stereotypes. This property is not visible by default, and the details of implementation vary from execution environment to execution environment. For example, Internet Explorer does not have this property. All we need to know is that there is a pointer to the constructor prototype inside the JavaScript object, that the pointer is automatically assigned when a new expression is called, and that we should not modify it.

In the four steps of constructing an object, we can see that, except for the second step, we do not need to use new expressions to achieve other steps, so new expressions are not only a simplification of these four steps, but also the only way to achieve inheritance.

Where it’s easy to get confused

One area of confusion about JavaScript constructors is the stereotype’s constructor property. In JavaScript, every function has the default prototype object property, which by default contains two member properties: constructor and __proto__. The details of the stereotype are beyond this article; we are now concerned with the constructor property.

In object-oriented thinking, we say that a constructor is equivalent to the definition of a “class,” so it would be a mistake to think that the constructor property is the actual constructor of the class, and that when a new expression creates an object, the constructor is called directly to initialize the object. The actual process of new expression execution was described above (four steps), of which the third step is used to initialize the object, and the initialization function called is the “class function” itself, not constructor. This may not be easy to understand without considering the question, but let’s give an example to illustrate:

function C3(a, b){ this.p = a + b; this.alertP = function(){ alert(this.p); Function fake(){this.p = 100;}} // We define a function to override the constructor of the C3 prototype, attempting to change the value of the attribute p. } C3.prototype.constructor = fake; Constructor var C3 = new C3(2,3); c3.alertP(); // The result is still 5Copy the code

The above code manually changes the constructor function in the C3 prototype, but it has no real effect on the creation of the C3 object, as you can see in the new expression, only the constructor itself initializes the object. So what does the constructor property do? In general, we can use the constructor attribute to test the type of an object:

Var myArray on = [1, 2, 3]; (myArray.constructor == Array); // trueCopy the code

This works for simple objects, but not for complex situations such as inheritance or cross-windows:

function f() { this.foo = 1; }function s() { this.bar = 2; }s.prototype = new f(); Var son = new s(); Constructor == s; // Create a subclass object using the constructor (son.constructor == s); // false (son.constructor == f); // trueCopy the code

Such results may not be what you expect, so be careful when using the constructor attribute, or avoid it altogether.