preface
Although object constructors or object literals can be used to create a single object, these methods have a significant drawback: creating many objects using the same interface creates a lot of duplicate code. The following patterns emerge.
The factory pattern
Use functions to encapsulate objects created with a specific interface.
function createPerson(name, age) { const o = new Object() o.name = name o.age = age o.sayName = function() { console.log(this.name) } return o } let person1 = createPerson('chen', 25) let person2 = createPerson('wu', 26) person1.sayName()Copy the code
The createPerson function builds a Person object with all the necessary information based on the parameters it accepts. Solved the problem of creating multiple similar objects, but did not solve the problem of object recognition (how to know the type of an object)
Constructor pattern
Constructors can create objects of a specific type, and native constructors such as Object and Array appear automatically in the execution environment at runtime. You can also create custom constructors to define properties and methods of a custom object type.
function Person(name, age) {
this.name = name
this.age = age
this.sayName = function() {
console.log(this.name)
}
}
let person1 = new Person('chen', 20)
let person2 = new Person('wu', 22)
Copy the code
The difference in code between the Person function and the createPerson function
- 1. No object is explicitly created in the Person function
- 2. The Person function assigns properties and methods directly to this object
- 3. No return statement
- 4. The Person method starts with a capital letter (by default, constructors always start with a capital letter and non-constructors with a lowercase letter)
How does the constructor pattern create new instances
Because there are no objects created in the Person function, to create a new instance of Person, you must use the new operator. Calling the constructor in this way actually goes through the following four steps:
- 1. Create an object
- 2. Assign the scope of the constructor to the new object (so this refers to the object)
- 3. Execute the code in the constructor (add attributes to the new object)
- Return a new object
The examples person1 and person2 each hold a different instance of Person, and both objects have a constructor property that points to Person
console.log(person1.constructor === Person) // true
console.log(person2.constructor === Person) // true
Copy the code
Constructors can identify instances as a specific type, which is an advantage of the constructor pattern over the factory pattern
- The difference between constructor and instanceof
console.log(person1.constructor === Person) // true
console.log(person1.constructor === Object) // false
console.log(person1 instanceof Person) // true
console.log(person1 instanceof Object) // true
Copy the code
Constructor refers to the directly inherited constructor, while instanceof is the constructor that appears in the test instance and prototype chain, and returns true
Constructor characteristics
The only difference between constructors and other functions is the way they are called. Any function that is called through the new operator is a constructor, whereas any function that is not called through new is a normal function.
Constructor problem
The main problem with using constructors is that each method is created on each instance. Person1 and person2 in the example both have a method named sayName, which is not the same Function instance.
console.log(person1.sayName === person2.sayName) // false
Copy the code
However, it’s not really necessary to create two instances of Function that do the same thing, and with this there’s no need to bind the Function to a particular object before executing the code.
The prototype pattern
Each function we create has a Prototype property, which is a pointer to an object whose purpose is to contain properties and methods that can be shared by all instances of a particular type. So instead of defining information about the object instance in the constructor, you add that information directly to the prototype object.
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayName = function() { console.log(this.name) }
let person1 = new Person('chen', 20)
let person2 = new Person('wu', 22)
console.log(person1.sayName === person2.sayName) // true
console.log(Person.prototype.isPrototypeOf(person1)) // true
console.log(Object.getPrototypeOf(person1) === Person.prototype) // true
Copy the code
SayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName, sayName
Object property Lookup
Whenever code reads an attribute of an object, a search is performed for the attribute with the given name, starting with the object instance itself. If an attribute with the given name is found in the instance, the value of that attribute is returned. If not, search continues for the prototype object to which the pointer points, and return the value of the property, if found in the prototype object.
function Person(name, Age) {this.name = name this.age = age this.sayName = function() {console.log(' return method in instance ')}} person.prototype.sayname = function() {console.log(this.name)} let person1 = new Person(' Chen ', 20) let person2 = new Person('wu', 22) Return the method console.log(person1.sayname ()) in the instanceCopy the code
hasOwnProperty
The hasOwnProperty method can be used to detect whether a property exists in an instance or in a stereotype, returning true only if the given property exists in an object instance.
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayName = function() { console.log(this.name) }
let person1 = new Person('chen', 20)
let person2 = new Person('wu', 22)
console.log(person1.hasOwnProperty("name")) // true
console.log(person1.hasOwnProperty("age")) // true
console.log(person1.hasOwnProperty("sayName")) // false
Copy the code
The in operator
There are two ways to use the IN operator: alone and in for-in loops
- Used alone
Using the IN operator alone returns true if a given property is accessible through an object, whether it exists in an instance or stereotype.
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayName = function() { console.log(this.name) }
let person1 = new Person('chen', 20)
let person2 = new Person('wu', 22)
console.log('name' in person1) // true
console.log('age' in person1) // true
console.log('sayName' in person1) // true
Copy the code
With the hasOwnProperty method, you can determine whether the property comes from an instance or a prototype object
function hasPrototypeProperty(obj, name) { return ! obj.hasOwnProperty(name) && (name in obj) }Copy the code
- Used in for-in loops
Returns all Enumerable ([[Enumerable]] is true) properties that can be accessed through the object, which contains properties in the instance as well as in the prototype object.
function Person(name, age) { this.name = name this.age = age } Person.prototype.sayName = function() { console.log(this.name) } let person1 = New Person(' Chen ', 20) let person2 = new Person('wu', 22) name age sayName for (let key in person1) { console.log(key) }Copy the code
Object.keys
The object. keys method gets all the enumerable instance properties of an Object
function Person(name, age) { this.name = name this.age = age } Person.prototype.sayName = function() { console.log(this.name) } let person1 = New Person(' Chen ', 20)huou let person2 = new Person('wu', 22) name age console.log(object.keys (person1))Copy the code
Object.getOwnPropertyNames
Gets all instance attributes, whether or not they are enumerable
function Person(name, age) { this.name = name this.age = age } Person.prototype.sayName = function() { console.log(this.name) } let person1 = New Person(' Chen ', 20) // Default Enumerable as false object.defineProperty (person1, 'sex', {value: 'boy' }) // ["name", "age", "sex"] console.log(Object.getOwnPropertyNames(person1)) // ["name", "age"] console.log(Object.keys(person1))Copy the code
Simpler prototype syntax
Overriding the entire prototype object through object literals causes the constructor property to no longer point to Person. Because every time a function is created, its Prototype object is also created, which automatically acquires the constructor attribute, our current syntax essentially overrides the default Prototype object, The constructor property therefore becomes the constructor property of the new Object (pointing to the Object constructor).
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype = {
sayName: function() { console.log(this.name) },
sayAge: function() { console.log(this.age) }
}
let person1 = new Person('chen', 20)
console.log(person1 instanceof Object) // true
console.log(person1 instanceof Person) // true
console.log(person1.constructor === Person) // false
console.log(person1.constructor === Object) // true
Copy the code
If the constructor value is important, we can set it back to the appropriate value as follows (which would cause the Constructor property’s Enumerable to be set to true, If you want the constructor property to be non-enumerable, set it with Object.definedProperty.)
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype = {
constructor: Person,
sayName: function() { console.log(this.name) },
sayAge: function() { console.log(this.age) }
}
let person1 = new Person('chen', 20)
console.log(person1 instanceof Object) // true
console.log(person1 instanceof Person) // true
console.log(person1.constructor === Person) // true
console.log(person1.constructor === Object) // false
Copy the code
- Pay attention to
Because rewriting prototype objects disconnects existing prototypes from any pre-existing object instances, they still refer to the original prototype.
function Person(name, age) { this.name = name this.age = age } let person1 = new Person('chen', 20) Person.prototype = { constructor: Person, sayName: function() { console.log(this.name) }, sayAge: Function () {console.log(this.age)}} person1.sayname () // errorCopy the code
That’s fine
function Person(name, age) {
this.name = name
this.age = age
}
let person1 = new Person('chen', 20)
Person.prototype.sayName = function() { console.log(this.name) }
person1.sayName() // chen
Copy the code