Tidy up the eight ways that JavaScript creates objects

  • 2020-09-28 08:44:41
  • OfStack

javascript creates objects in the following way:

1. Use the Object constructor to create 1 object

The following code creates an person object and prints out the Name attribute values in two ways.


 var person = new Object();
 person.name="kevin";
 person.age=31;
 alert(person.name);
 alert(person["name"])

Another way of writing this is to create an object using object literals. Don't be surprised that person[" 5 "] is legal here. In addition, there can be Spaces between fields using this parenthesis as in person[" my age "].


var person = 
 {
 name:"Kevin",
 age:31,
 5:"Test"
 };
 alert(person.name);
 alert(person["5"]);

While Object constructors or object literals can be used to create a single object, these methods have an obvious disadvantage: creating many objects using the same interface creates a lot of duplicate code. To solve this problem, people started using a variant of the factory pattern.

2. Factory mode

The factory pattern is a well-known design pattern in software engineering that abstracts the process of creating concrete objects. Considering that classes cannot be created in ECMAScript, developers have invented a function that encapsulates the details of creating objects with a specific interface, as shown in the following example.


function createPerson(name, age, job){
 var o = new Object();
 o.name = name;
 o.age = age;
 o.job = job;
 o.sayName = function(){
 alert(this.name);
 };
 return o;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

The factory pattern solves the problem of creating multiple similar objects, but it does not solve the problem of object identification (that is, how to know the type of an object). As JavaScript
A new model has emerged.

3. Constructor pattern

Constructors like Object and Array appear automatically in the execution environment at run time. In addition, you can create custom constructors that define properties and methods for custom object types. For example, you can rewrite the previous example as follows using the constructor pattern.


function Person(name, age, job){
 this.name = name;
 this.age = age;
 this.job = job;
 this.sayName = function(){
 alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

In this example, the Person() function replaces the createPerson() function. We note that in addition to the same parts of the code in Person() as in createPerson(), the following differences exist:

1. No object is explicitly created;

2. Assign attributes and methods directly to the this object;

3. No return statement.

To create a new instance of Person, you must use the new operator. Calling the constructor this way actually goes through four steps:

(1) Create a new object;
(2) Assign the scope of the constructor to the new object (so this points to the new object);
(3) Execute the code in the constructor (add a property to the new object);
(4) Return the new object.

At the end of the previous example, person1 and person2 hold a different instance of Person, respectively. Both objects have an constructor (constructor) attribute that points to Person, as shown below.

alert(person1.constructor == Person); //true
alert(person2.constructor == Person); //true

The constructor attribute of the object was originally used to identify the object type. However, when it comes to detecting object types, the instanceof operator is more reliable. All the objects we create in this example are instances of Object as well as Person, which can be verified by the instanceof operator.

alert(person1 instanceof Object); //true
alert(person1 instanceof Person); //true
alert(person2 instanceof Object); //true
alert(person2 instanceof Person); //true

Creating a custom constructor means that its instance can be identified as a specific type in the future; This is where the constructor pattern trumps the factory pattern. In this example, person1 and person2 are both instances of Object because all objects inherit from Object.

Problem with constructors

The constructor pattern, while useful, is not without its drawbacks. The main problem with constructors is that each method is recreated 1 time on each instance.

Functions in ECMAScript are objects, so for every function defined, one object is instantiated. Logically, the constructor at this point can also be defined this way.

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = new Function("alert(this.name)"); // Is logically equivalent to declaring a function
}

From this perspective, the constructor makes it easier to understand the nature of each Person instance containing a different Function instance to show the name attribute. To be clear, creating functions this way results in different scope chains and identifier resolution, but the mechanism for creating new instances of Function remains the same. Therefore, functions with the same name on different instances are not equal, as the following code can prove.

alert(person1.sayName == person2.sayName); //false

However, there is really no need to create two instances of Function that do the same thing; Moreover, there are this objects in which you don't have to bind functions to a particular object at all before executing the code. Therefore, you can solve this problem by moving the function definition outside the constructor, as follows.


function Person(name, age, job){
 this.name = name;
 this.age = age;
 this.job = job;
 this.sayName = sayName;
}
function sayName(){
 alert(this.name);
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

If an object needs to define many methods, then it needs to define many global functions, so our custom reference type is not encapsulated at all. Fortunately, these problems can be solved by using the prototype pattern.

4. Prototype mode


function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
 alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true

To understand prototype objects, see my other post: JavaScript prototype details

Person.prototype is typed once for each property and method added in the previous example. To reduce unnecessary input and visually encapsulate the functionality of the stereotype, it is more common to rewrite the entire stereotype object with an object literal that contains all the attributes and methods, as shown in the following example.


function Person(){
}
Person.prototype = {
 name : "Nicholas",
 age : 29,
 job: "Software Engineer",
 sayName : function () {
 alert(this.name);
 }
};

In the code above, we set ES155en.prototype to equal to 1 new object created as an object literal. The end result is the same, with one exception: the constructor attribute no longer points to Person. As mentioned earlier, every time a function is created, its prototype object is created, and this object automatically gets the constructor attribute. The syntax we use here essentially overwrites the default prototype object, so that the constructor attribute becomes the constructor attribute of the new object (pointing to the Object constructor) and no longer points to the Person function. At this point, although the instanceof operator still returns the correct result, it is no longer possible to determine the type of object using constructor, as shown below.


var friend = new Person();
alert(friend instanceof Object); //true
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
alert(friend.constructor == Object); //true

Here, testing Object and Person with the instanceof operator still returns true, but the constructor attribute is equal to Object and not Person. If the value of constructor is really important, you can deliberately set it back to the appropriate value as follows.


function Person(){
}
 Person.prototype = {
 constructor : Person,
 name : "Nicholas",
 age : 29,
 job: "Software Engineer",
 sayName : function () {
 alert(this.name);
 }
};

One thing to note is that the pointer to the instance only points to the prototype, not to the constructor.

The problem with archetypal objects: The archetypal pattern is not without its drawbacks. First, it omits passing an initialization parameter to the constructor, resulting in all instances having the same property value by default. While this is somewhat inconvenient, it's not the biggest problem with the prototype. The biggest problem with prototype patterns is caused by their Shared nature.


function Person(){
}
Person.prototype = {
 constructor: Person,
 name : "Nicholas",
 age : 29,
 job : "Software Engineer",
 friends : ["Shelby", "Court"],
 sayName : function () {
 alert(this.name);
 }
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court,Van"
alert(person1.friends === person2.friends); //true

5. Combining constructor patterns and prototype patterns (most commonly used)

The most common way to create custom types is to use a combination of the constructor pattern and the stereotype pattern. The constructor pattern is used to define instance properties, and the stereotype pattern is used to define methods and Shared properties. As a result, each instance will have its own copy of instance attributes, but at the same time share references to methods, minimizing memory savings. In addition, this blending pattern supports passing parameters to constructors; This is the length of the two modes.


var person = 
 {
 name:"Kevin",
 age:31,
 5:"Test"
 };
 alert(person.name);
 alert(person["5"]);
0

6. Dynamic prototype mode

Developers with experience with other OO languages are likely to be confused when they see separate constructors and prototypes. The dynamic prototyping pattern is one solution that addresses this problem by encapsulating all the information in constructors, while maintaining the advantage of using both constructors and prototypes by initializing them in constructors (only if necessary). In other words, you can determine whether a prototype needs to be initialized by checking whether a method that should exist is valid. Let's do an example.


var person = 
 {
 name:"Kevin",
 age:31,
 5:"Test"
 };
 alert(person.name);
 alert(person["5"]);
1

7. Parasitic constructor pattern

In general, you can use the parasitic (parasitic) constructor pattern in cases where none of the previous patterns are applicable. The basic idea behind this pattern is to create a function that merely encapsulates the code that created the object, and then returns the newly created object. But on the surface, this looks like a typical constructor. Here is an example.


var person = 
 {
 name:"Kevin",
 age:31,
 5:"Test"
 };
 alert(person.name);
 alert(person["5"]);
2

In this example, the Person function creates a new object, initializes the object with the appropriate properties and methods, and returns the object. Apart from using the new operator and calling the wrapper function used a constructor, this pattern is actually 1-to-1 like the factory pattern. The constructor returns a new object instance by default if it does not return a value.

8. Secure constructor pattern

By secure objects, I mean objects that have no public properties and whose methods do not refer to this. Secure objects are best used in secure environments where this and new are prohibited, or to prevent data from being modified by other applications such as Mashup. The secure constructor follows a similar pattern to the parasitic constructor, except that the instance method of the newly created object does not refer to this; 2 is calling the constructor without using the new operator. The preceding Person constructor can be rewritten as follows, in accordance with the requirements of a sound constructor.


function Person(name, age, job){
 // Create the object to return 
 var o = new Object();
 // You can define private variables and functions here 
 // Add methods 
 o.sayName = function(){
 alert(name);
 };
// Returns the object 
return o;
}

Related articles: