1. Factory mode

Encapsulate functions to create objects with specific interfaces

  • Cannot know the object type
function createPerson(name, age, job){ 
     var o = new Object(); 
     o.name = name; 
     o.age = age; 
     o.job = job; 
     o.sayName = function(){ 
        console.log(this.name); 
     }; 
     return o; 
} 
var person1 = createPerson("Nicholas", 29, "Software Engineer"); 
var person2 = createPerson("Greg", 27, "Doctor");
person1.sayName() // Nicholas
person2.sayName() // Greg
Copy the code

2. Constructor pattern

  • By convention, constructors start with a capital letter
function Person(name, age, job){ 
 this.name = name; 
 this.age = age; 
 this.job = job; 
 this.sayName = function(){ 
    console.log(this.name); 
 }; 
} 
var person1 = new Person("Nicholas", 29, "Software Engineer"); 
var person2 = new Person("Greg", 27, "Doctor");
person1.sayName() // Nicholas
person2.sayName() // Greg
Copy the code

Constructor pattern, compared to factory pattern

  • 1. The created object is not displayed
  • 2. Assign attributes and methods directly to this object
  • 3. No return statement

Creating an object using a constructor goes through four steps

  • 1. Create an object
  • 2. Assign constructor scope to new object (this refers to new object)
  • 3. Execute the code in the constructor (add attributes to the new object)
  • 4. Return a new object

Objects created using constructors have a constructor property pointing to the constructor.

Creating a custom constructor means that an instance of it can be identified as a particular type

The constructor property, used to identify the object type. You can use instanceof detection

person1 instanceof Object // true

Constructor problems:

  • Each method is created on an instance
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; //this.sayName = function(){ // console.log(this.name); / /}; SayName = new Function("alert(this.name)"); Person1 = new Person(); person1 = new Person(); var person2 = new Person(); person1.sayName == person2.sayName; //falseCopy the code

So we can put the function definition in the global scope

function Person(name, age, job){ 
    // some code
    this.sayName= sayName
}

function sayName(){}
Copy the code

Thus, sayName refers to the same function, enabling function sharing. However, if there are too many methods, we need to create multiple functions in the global scope, then our custom reference types will not make much sense. This problem can be solved by prototyping patterns

3. Prototyping

Each function has a prototype property that points to an object (the prototype object).

The purpose of this object is to contain properties and methods that can be shared by all instances of a particular type.

All instances can share prototype’s properties and methods

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

All instances (person1 and person2) access the same set of attributes and a sayName method

Understanding prototype objects

Functions have a prototype attribute that points to the function’s prototype object. By default, prototype objects have a constructor property, which contains a pointer to the function that Prototype has

Person.prototype.constructor === Person // true
Copy the code

Once a custom function is created, the constructor prototype Object contains only the constructor attribute by default, and the rest of the methods inherit from the Object Object.

When the constructor creates an instance, the instance contains an internal property that points to the constructor’s prototype object.

This property exists between the instance and the stereotype object and is not directly related to the constructor

person1.__proto__ === Person.prototype // true
Copy the code

This internal attribute, ECMA5 called [[prototype]], FireFox safari, Chrome called __proto__,

You can use isPrototypeOf to check the pointing of the [[prototype]] attribute

Person.prtotype.isPrototypeOf(person1) // true
Copy the code

You can also use getPrototypeOf to get the prototype object

(Object.getPrototypeOf(person1) == Person.prototype // true
Copy the code

The process of reading properties

Whenever your code reads a property, it looks at the object instance itself, and when it finds it, it returns; [[prototype]] (__proto__) until object.prototype is found. (This lookup mechanism is called the prototype chain.)

When you add a property to an object, the stereotype’s property of the same name is automatically masked, but not modified.

Even if this property is set to NULL, the link to the stereotype will not be restored

However, the link can be restored by deleting an attribute on the instance using the DELETE operator

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(); var person2 = new Person(); person1.name = "Greg"; console.log(person1.name); //"Greg" -- instance console.log(person2.name); //"Nicholas" -- prototype delete person1.name; console.log(person1.name); / / "Nicholas" prototypeCopy the code

HasOwnProperty checks if a property exists in an instance

alert(person1.hasOwnProperty("name")); //false person1.name = "Greg"; alert(person1.name); //"Greg" -- instance alert(person1.hasownProperty ("name")); //true alert(person2.name); //"Nicholas" -- prototype alert(person2.hasownProperty ("name")); //false delete person1.name; alert(person1.name); //"Nicholas" -- prototype alert(person1.hasownProperty ("name")); //falseCopy the code

Use the IN operator to determine if the property is on the stereotype chain

person1.hasOwnProperty("name"); //false "name" in person1; //true person1.name = "Greg"; person1.name; //"Greg" -- instance person1.hasownProperty ("name"); //true "name" in person1; //trueCopy the code
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person = new Person(); alert(hasPrototypeProperty(person, "name")); Person. Name = "Greg"; alert(hasPrototypeProperty(person, "name")); // Override the name attribute in the false instance, so name exists in the instanceCopy the code

Object.keys() returns all enumerable properties in the instance

A for-in loop that returns enumerable properties accessible through objects, including instances and prototypes

Object. GetOwnPropertyNames () obtain all instance attributes, including an enumeration

var keys = Object.getOwnPropertyNames(Person.prototype); 
console.log(keys); //"constructor,name,age,job,sayName"
Copy the code

Note:

When creating a new object using a literal approach, pay attention to the constructor direction

function Person(){ 
} 
Person.prototype = { 
  name : "Nicholas", 
  age : 29, 
  job: "Software Engineer", 
  sayName : function () { 
  alert(this.name); 
  } 
}
Person.prototype.constructor === Person; // false 
Person.prototype.constructor=== Object ; // true 
Copy the code

When prototype is rewritten, constructor no longer points to Person, but to new Object constructors that need to be specified manually

Person.prototype.constructor = Person

At this point, however, the constructor property will become enumerable

Object.keys(Person.prototype) // ["name", "age", "job", "sayName", "constructor"]
Copy the code

use

Object.defineProperty(Person.prototype, "constructor", { 
    enumerable: false, 
    value: Person 
});
Copy the code

The dynamics of prototypes

The process of finding a value in the prototype is a search, so any changes we make to the prototype object are immediately visible on the instance. This is true even if the instance is created first.

Function Person(){} var p1 = new Person(){//Person.prototype.sayHi = function(){// alert("hi"); / /}; //p1.sayHi(); Person. Prototype = {name: "Nicholas", age: 29, job: "Software Engineer", sayName: function () { alert(this.name); } } p1.sayName() //p1.sayName is not a function console.log(Person.prototype.constructor === Person); // falseCopy the code

The prototype object is rewritten and will be different.

When the constructor is called, a [[prototype]](or __proto__) pointer is added to the instance to point to the prototype, and rewriting the prototype breaks the link between the constructor and the prototype.

The p1.sayname () call failed

Object instance corresponds to the stereotype object, which still refers to the stereotype before overwriting.

Problems with prototype objects

Reference value sharing

function Person(){ this.hobby = ['basket ball','tennis'] } 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"); console.log(person1.friends); //"Shelby,Court,Van" console.log(person2.friends); //"Shelby,Court,Van" console.log(person1.friends === person2.friends); //true person1.hobby.push('ping-pong') console.log(person1.hobby) // properties in constructor ['basket ball', 'tennis', 'ping-pong'], Console.log (person2.hobby) // ['basket ball', 'tennis']Copy the code

The attributes and methods of all instances in the stereotype are shared, saving a lot of memory, but also causing problems with shared reference values (person1.friends=[‘Ann’] does not cause this problem – adding attributes of the same name to the instance will mask attributes on the stereotype)

So how to solve the application value sharing problem of prototype objects? Use a combination of stereotypes and constructors

4. Use a combination of stereotype and constructor patterns

Using a combination of stereotype and constructor patterns is the most common way to create custom types. The stereotype pattern defines shared properties and methods, and the constructor pattern defines instance properties

Each instance has its own copy of instance attributes and shares references to methods, maximizing memory savings.

In addition, passing parameters like constructors is supported

function Person(name, age, job){
 this.name = name; 
 this.age = age; 
 this.job = job; 
 this.friends = ["Shelby", "Court"]; 
} 
Person.prototype = { 
  constructor : Person, 
  sayName : function(){ 
    console.log(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
Copy the code

5. Dynamic prototyping

That is, to determine whether a stereotype needs to be initialized by checking whether an existing method is valid

// Method if (typeof this.sayName! Person.prototype.sayName = function(){alert(this.name); }; }Copy the code

Note: you can’t assign a literal to a stereotype, because the relationship between the constructor and the stereotype will be severed and the if judgment will be invalid

6. Parasitic constructor patterns

How it works: Create a function that simply encapsulates the method used to create an object and then returns the newly created object

function Person(name, age, job){
 var o = new Object(); 
 o.name = name; 
 o.age = age; 
 o.job = job; 
 o.sayName = function(){ 
    console.log(this.name); 
 }; 
 return o; 
} 
var friend = new Person("Nicholas", 29, "Software Engineer"); 
friend.sayName(); //"Nicholas"
Copy the code

It is the same as factory mode, except that it uses the new operator.

Objects created in this mode have no relationship to constructors, and you cannot use instanceOf to detect types

7. Secure constructor patterns

A secure object has no public properties and its methods do not refer to this object.

function Person(name, age, job){ var o = new Object(); O.sayname = function(){// Add the method alert(name); }; // return object return o; }Copy the code

In this mode, its data members can only be accessed by calling sayName().

Also, objects created in this mode have no relationship to constructors, and you cannot use instanceOf to detect types.