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.