There are three main types of object creation: factory mode, constructor mode and prototype mode. This paper mainly analyzes the characteristics, advantages and disadvantages of these three modes, as well as some details. Reference: JS Elevation Little Red Book (4th edition)
I. Factory model
function createPerson(name, age, job) {
let o = new Object(a); o.name = name; o.age = age; o.job = job; o.sayName =function() {
console.log(this.name);
};
return o;
}
let person1 = createPerson("Nicholas".29."Software Engineer");
let person2 = createPerson("Greg".27."Doctor");
Copy the code
- Advantages: The problem of creating multiple similar objects
- Disadvantages: Does not solve the object recognition problem (what type is the newly created object?)
Constructor pattern
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
console.log(this.name);
};
}
let person1 = new Person("Nicholas".29."Software Engineer");
let person2 = new Person("Greg".27."Doctor");
person1.sayName(); // Nicholas
person2.sayName(); // Greg
Copy the code
1. The constructor schema is similar to the factory schema, with the following differences:
- No object is explicitly created
- Properties and methods are assigned directly to this
- There is no return
- The function name Person starts with a capital letter
2. Calling the constructor with new does the following:
- Create a new object in memory.
- The [[Prototype]]_ property inside this new object is assigned to the constructor’s Prototype property.
- This inside the constructor is assigned to the new object (that is, this refers to the new object).
- Executes the code inside the constructor (adding attributes to the new object).
- If the constructor returns a non-empty object, that object is returned; Otherwise, the newly created object is returned.
3. Constructor problems:
- The methods are created on each instance, not the same Function instance. (Functions are objects in JS, so an object is initialized each time a Function is defined.)
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = new Function("console.log(this.name)"); // Logical equivalence
}
Copy the code
To solve this problem, move 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() {
console.log(this.name);
}
let person1 = new Person("Nicholas".29."Software Engineer");
let person2 = new Person("Greg".27."Doctor");
person1.sayName(); // Nicholas
person2.sayName(); // Greg
Copy the code
The sayName attribute in the constructor contains only a pointer to the external global function, so person1 and person2 share the sayName() function defined on the global scope. But there are drawbacks:
- The problem of repeating functions with the same logic was solved, but the global scope was messed up. If the object needs more than one function, you need to define more than one function in the global scope.
- This problem can be solved by prototyping patterns.
Prototype mode
Each function creates a Prototype property, which is an object containing properties and methods that should be shared by instances of a particular reference type.
function Person() {}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function() {
console.log(this.name);
};
let person1 = new Person();
person1.sayName(); // "Nicholas"
let person2 = new Person();
person2.sayName(); // "Nicholas"
console.log(person1.sayName == person2.sayName); // true
Copy the code
Summary of methods related to prototype:
1. IsPrototypeOf () : determines the relationship between the instance and the prototype object;
console.log(Person.prototype.isPrototypeOf(person1)); // true
console.log(Person.prototype.isPrototypeOf(person2)); // true
Copy the code
Object.getprototypeof () : Returns the value of the parameter’s internal property [[Prototype]].
console.log(Object.getPrototypeOf(person1) == Person.prototype); // true
console.log(Object.getPrototypeOf(person1).name); // "Nicholas"
Copy the code
3. Object.setprototypeof () : Writes a new value to the instance’s private property [[Prototype]]. Can seriously affect code performance, not recommended! You can use object.create () instead
4. Object.create() : Creates a new Object and specifies a prototype Object for it
let biped = {
numLegs: 2
};
let person = Object.create(biped);
person.name = 'Matt';
console.log(person.name); // Matt
console.log(person.numLegs); // 2, access the properties on the prototype
console.log(Object.getPrototypeOf(person) === biped); // true
Copy the code
5. The hasOwnProperty() method is used to determine whether a property is on an instance or a prototype object. Property returns true if it exists on the instance of the object calling it
console.log(person1.hasOwnProperty("name")); // false
person1.name = "Greg";
console.log(person1.name); // "Greg", from example
console.log(person1.hasOwnProperty("name")); // true
Copy the code
6. Stereotypes and in operators
The in operator can be used in two ways: alone or in a for-in loop.
- When used alone, the IN operator returns true when the specified property is accessible through the object, whether it is on an instance or a stereotype.
If you want to determine whether an attribute exists on a stereotype, you can use both the hasOwnProperty() and in operators as follows:
function hasPrototypeProperty(object, name){
return! object.hasOwnProperty(name) && (namein object);
}
Copy the code
- When the IN operator is used in a for-in loop, all properties that can be accessed through an object and can be enumerated are returned, including instance and stereotype properties.
7.object.keys () : Gets all enumerable instance properties on an Object, returning an array of strings.
8. Object. GetOwnPropertyNames () : list all instance attributes, whether or not can be enumerated.
let keys = Object.getOwnPropertyNames(Person.prototype);
console.log(keys); // "[constructor,name,age,job,sayName]"
Copy the code
Notice that the returned result contains an attribute called constructor that is not enumerable.
Fourth, object iteration
The two static methods Object.values() and object.entries () receive an Object and return an array of their contents.
1. Other prototype syntax:
function Person() {};
Person.prototype = {
name: "Nicholas".age: 29.job: "Software Engineer".sayName() {
console.log(this.name); }};Copy the code
There’s a problem: The Person.prototype constructor property doesn’t point to Person.
- When a function is created, its Prototype object is automatically created and its constructor property is automatically assigned.
- This completely overrides the default Prototype Object, so its constructor property also points to a completely different new Object (Object constructor) than the original constructor.
let friend = new Person();
console.log(friend instanceof Object); // true
console.log(friend instanceof Person); // true
console.log(friend.constructor == Person); // false
console.log(friend.constructor == Object); // true
Copy the code
Don’t worry, just make a few modifications:
function Person() {}
Person.prototype = {
// Constructor: Person, restoring the constructor property in this way creates an attribute that [[Enumerable]] is true. The native constructor property is not enumerable by default
name: "Nicholas".age: 29.job: "Software Engineer".sayName() {
console.log(this.name); }};// Restore the constructor attribute
Object.defineProperty(Person.prototype, "constructor", {
enumerable: false.value: Person
});
Copy the code
2. Prototype dynamics
let friend = new Person();
Person.prototype.sayHi = function() {
console.log("hi");
};
friend.sayHi(); // "hi", no problem!
Copy the code
After the prototype is rewritten:
function Person() {}
let friend = new Person();
Person.prototype = {
constructor: Person,
name: "Nicholas".age: 29.job: "Software Engineer".sayName() {
console.log(this.name); }}; friend.sayName();/ / error
Copy the code
The [[Prototype]] pointer to the instance is automatically assigned when the constructor is called and points to the original Prototype. (When the stereotype is overwritten, it is another stereotype object, severing the connection between the original stereotype and the constructor.)
3. Prototype problems
(1) The prototype mainly has the following two problems:
- Weakened ability to pass initialization parameters to constructors, resulting in all instances taking the same property values by default.
- The main problem with the stereotype stems from its shared nature, where all properties on the stereotype are shared between instances.
So the prototype pattern is usually not used in isolation in actual development.
(2) Analysis of application scenarios of prototype sharing feature:
- For functions;
- For properties that contain original values, you can simply mask the properties on the stereotype by adding properties of the same name on the instance;
- This is bad for attributes that contain reference values
function Person() {}
Person.prototype = {
constructor: Person,
name: "Nicholas".age: 29.job: "Software Engineer".friends: ["Shelby"."Court"].sayName() {
console.log(this.name); }};let person1 = new Person();
let person2 = new Person();
person1.friends.push("Van"); // The friends property is prototypical, and it will also be present in other instances
console.log(person1.friends); // "Shelby,Court,Van"
console.log(person2.friends); // "Shelby,Court,Van"
console.log(person1.friends === person2.friends); // true
Copy the code