Home>

Here's how javascript creates objects:

1. Use the object constructor to create an object

The following code creates a person object and prints out the value of the name attribute in two ways.

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

Another expression of the above is to create an object using object literals,Don't be surprised person ["5"], this is legal;In addition, using this method of parentheses, there can be spaces between fields such as person ["my age"].

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

Although either the object constructor or the object literal can be used to create a single object,But these methods have an obvious disadvantage:using the same interface to create many objects,Will generate a lot of duplicate code.To solve this problem,People started using a variation of the factory model.

Factory mode

The factory pattern is a well-known design pattern in the field of software engineering.This pattern abstracts the process of creating concrete objects,Considering that classes cannot be created in ecmascript,The developer invented a function,Use functions to encapsulate the details of creating an object with a specific interface,This is 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");

Although the factory pattern solves the problem of creating multiple similar objects,But it does not solve the problem of object recognition (that is, how to know the type of an object). With javascript

Development, another new model has emerged.

3. Constructor pattern

Constructors like object and array,It will automatically appear in the execution environment at runtime.Alternatively, you can create custom constructors,Thereby defining the properties and methods of the custom object type.For example, you can use the constructor pattern to rewrite the previous example as follows.

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 have noticed,The code in person () is the same as in createperson (),The following differences also exist:

1. Objects are not explicitly created;

2. Assign properties and methods directly to this object;

3. There is no return statement.

To create a new instance of person,You must use the new operator. Calling the constructor this way actually goes through the following 4 steps:

(1) create a new object;

(2) Assign the scope of the constructor to the new object (so this points to this new object);

(3) Execute the code in the constructor (add attributes to this new object);

(4) Return the new object.

At the end of the previous example,person1 and person2 each hold a different instance of person.Both objects have a constructor property that points to person as shown below.

alert (person1.constructor == person);//true

alert (person2.constructor == person);//true

The object's constructor property was originally used to identify the type of object.However, when it comes to detection object types,The instanceof operator is more reliable.All the objects we created in this example are both instances of object and instances of person. This 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;And this is where the constructor pattern outperforms the factory pattern.In this example,person1 and person2 are both instances of object because all objects inherit from object.

Constructor problem

Although the constructor pattern is easy to use,But it is not without its disadvantages.The main problem with using constructors,That is, each method must be recreated on each instance.

Functions in ecmascript are objects,So every time you define a function,That is, an object is instantiated.From a logical perspective,The constructor at this time can also be defined in 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 a declared function

}

Looking at the constructor from this perspective,It's easier to understand the essence of each person instance containing a different function instance (to show the name attribute). To be clear,Create functions this way,Will result in different scope chains and identifier resolution,But the mechanism for creating new instances of function is still the same.Therefore, functions with the same name on different instances are not equal.The following code can prove this.

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

However, it is really unnecessary to create two function instances that accomplish the same task;What's more, there is this object, so there is no need to bind functions to specific objects before executing code.Therefore, it might look like this,Solve this problem by moving the function definition outside the constructor.

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 the object needs to define many methods,Then we need to define many global functions,So our custom reference type has no encapsulation 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 article:Detailed explanation of javascript prototype

In the previous example, you would type person.prototype every time you add a property or method. To reduce unnecessary input,In order to better encapsulate the functionality of the prototype visually,It is more common to rewrite the entire prototype object with an object literal containing all properties and methods,This is shown in the following example.

function person () {
}
person.prototype={
 name:"nicholas", age:29, job:"software engineer", sayname:function () {
 alert (this.name);
 }
};

In the above code,We set person.prototype equal to a new object created as an object literal.The end result is the same,There is one exception:the constructor property no longer points to person. As mentioned earlier,Every time a function is created,Will create its prototype object at the same time, this object will automatically get the constructor property. And the syntax we use here,Essentially completely rewrites the default prototype object, so the constructor property becomes the constructor property 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,But the type of the object can no longer be determined through the constructor.As follows.

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, using the instanceof operator to test object and person still returns true, but the constructor attribute is equal to object and not equal to person. If the value of the constructor is really important,It can be intentionally set back to the appropriate value as shown below.

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 in the instance only points to the prototype,Without pointing to the constructor.

The problem with prototype objects:The prototype pattern is not without its drawbacks.First, it omits the passing of initialization parameters to the constructor,As a result, all instances will get the same attribute value by default.Although this may cause some inconvenience,But it's not the biggest problem with prototypes.The biggest problem with the prototype pattern is caused by its 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, the combination of constructor mode and prototype mode (most commonly used)

The most common way to create custom types,Is a combination of the constructor pattern and the prototype pattern.The constructor pattern is used to define instance properties,The prototype pattern is used to define methods and shared attributes.As a result, each instance will have its own copy of the instance properties,But also sharing references to methods,Maximize memory savings.In addition, this hybrid mode also supports passing parameters to the constructor;Can be described as the strength of the two models.

function person (name, age, job) {
 this.name=name;
 this.age=age;
 this.job=job;
 this.friends=["shelby", "court"];
}
person.prototype={
 constructor:person, sayname:function () {
 alert (this.name);
 }
}
var person1=new person ("nicholas", 29, "software engineer");
var person2=new person ("greg", 27, "doctor");
person1.friends.push ("van");
alert (person1.friends);//"shelby, count, van"
alert (person2.friends);//"shelby, count"
alert (person1.friends === person2.friends);//false
alert (person1.sayname === person2.sayname);//true

6.Dynamic prototype mode

When developers with other oo language experience see independent constructors and prototypes,It is likely to be very confusing.The dynamic prototyping model is exactly a solution dedicated to solving this problem.It encapsulates all the information in the constructor,By initializing the prototype in the constructor (only if necessary), the advantages of using both the constructor and the prototype are maintained.in other words,You can check if a method that should exist is valid,To decide if you need to initialize the prototype.Look at an example.

function person (name, age, job) {
 //Attributes
 this.name=name;
 this.age=age;
 this.job=job;
 //method
 ---------------------------------------------
 if (typeof this.sayname!="function") {
 person.prototype.sayname=function () {
  alert (this.name);
 };
 }
 --------------------------------------------
}
var friend=new person ("nicholas", 29, "software engineer");
friend.sayname ();

7, parasitic constructor mode

In general, when none of the previous modes are applicable,A parasitic constructor pattern can be used.The basic idea of ​​this pattern is to create a function,The function is just to encapsulate the code that creates the object,Then return to the newly created object;But on the surface,This function is very similar to a typical constructor.Below is an example.

function person (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 friend=new person ("nicholas", 29, "software engineer");
friend.sayname ();//"nicholas"

In this example,The person function creates a new object,And initialize the object with corresponding properties and methods,This object was then returned.In addition to using the new operator and calling the wrapper function used as a constructor,This model is exactly the same as the factory model.The constructor does not return a value,New object instances are returned by default.

8.Prudent Constructor Mode

The so-called safe object,Means there is no public attribute,And its methods do not reference this's object. The prudent object is best used in some secure environments (the use of this and new is prohibited in these environments), or when preventing data from being changed by other applications, such as mashup programs.Robust constructors follow a similar pattern to parasitic constructors,But there are two differences:one is that the instance method of the newly created object does not reference this;the other is that the constructor is not called using the new operator.As required by the safe constructor,The previous person constructor can be rewritten as follows.

function person (name, age, job) {
 //Create the object to be returned
 var o=new object ();
 //You can define private variables and functions here
 //Add method
 o.sayname=function () {
 alert (name);
 };
//return object
return o;
}

Related articles