JS is an object – oriented language. When it comes to object – oriented, we have to say its encapsulation of three elements.
The original pattern
var cat1 = {name:"guaiguai".color:"White hair"}
var cat2 = {name:"huaihuai".color:"Black"}
Copy the code
Existing problems:
- Generate a few more instances, and the code becomes redundant and cumbersome to write
- Cat1 and CAT2 have no apparent relationship
The factory pattern
function createCat(name,color) {
return {
name:name,
color:color
}
}
var cat1 = createCat("guaiguai"."White hair")
var cat2 = createCat("huaihuai"."Black hair")
Copy the code
Problems with the factory model
- There is still no apparent connection between CAT1 and CAT2.
- There is a waste of memory, why do you know
function createCat(name,color) {
var obj = {}
obj.name = name;
obj.color = color;
obj.type = "Felines."; // Invariant attributes
obj.eat = function() {
alert("Eat a mouse.")}return obj
}
var cat1 = createCat("guaiguai"."White hair")
var cat2 = createCat("huaihuai"."Black hair")
alert(cat1.type) // Cats
cat1.eat()
cat2.eat()
console.info(cat1.eat == cat2.eat) // false
Copy the code
The function is fine, but for each instance, the type and eat methods are exactly the same, but they are regenerated each time, which takes up too much memory and affects efficiency. Is there a way to generate type and EAT only once in memory? There are two ways:
Public attributes are pulled global
function eat() {
alert("Eat a mouse.")}var typeName = "Felines."
function createCat(name,color) {
var obj = {}
obj.name = name;
obj.color = color;
obj.type = typeName; // Invariant attributes
obj.eat = eat
return obj
}
var cat1 = createCat("guaiguai"."White hair")
var cat2 = createCat("huaihuai"."Black hair")
alert(cat1.type) // Cats
cat1.eat()
cat2.eat()
console.info(cat1.eat == cat2.eat) // true
Copy the code
In this way, the type and EAT methods can be reused, but the variable and method are defined as global. On the one hand, the global variable or method is only called by an object, which is a bit misnamed. Second, if you want to define multiple shared attributes in an object, you have to define multiple global functions or variables
Adopt a prototype
createCat.prototype = {
type:"Felines.".eat:function() {
alert("Eat a mouse.")}}function createCat(name,color) {
var obj = {}
obj.name = name;
obj.color = color;
// __proto__ nonstandard usage
obj.__proto__ = createCat.prototype
return obj
}
var cat1 = createCat("guaiguai"."White hair")
var cat2 = createCat("huaihuai"."Black hair")
alert(cat1.type) // Cats
cat1.eat()
cat2.eat()
console.info(cat1.eat == cat2.eat) // true
console.info(cat1 instanceof createCat) // true
console.info(cat2 instanceof createCat)// true
Copy the code
Reuse the type and EAT methods by setting properties on the prototype of the function. CreateCat. Prototype when accessing type, createCat will first look for the instance object itself. If not, createCat will look for its prototype object. This is the prototype chain
Constructor pattern
Cat.prototype = {
type:"Felines.".eat:function() {
alert("Eat a mouse.")}}function Cat(name,color) {
this.name = name;
this.color = color;
}
var cat1 = new Cat("guaiguai"."White hair")
var cat2 = new Cat("huaihuai"."Black hair")
alert(cat1.type) // Cats
cat1.eat()
cat2.eat()
console.info(cat1.eat == cat2.eat) // true
console.info(cat1 instanceof Cat) // true
console.info(cat2 instanceof Cat) // true
Copy the code
Using Cat as a function name is the same as using createCat as a function name, except that constructors should always start with a capital letter to distinguish them from normal functions
As shown above, you can do four fewer things simply by using the new keyword in front of the function:
- No need to create a new object (var obj = {}), because new will do it for you (in the function you use this to access the new object obj).
- You don’t have to bind the prototype, because new will do it for you
- Don’t return the new object, because new will do it for you
Var cat1 = new Cat(“guaiguai”,” white hair “)
- Create a new object cat1
- Assign the constructor’s scope to the new object cat1 (thus this refers to the new object)
- Execute the code in the constructor (add attributes to the new object);
- Returns a new object.
The new keyword is just a syntactic sugar
Implement the new operator yourself
function create(Con,... args){
var obj = {}
// Associate an obj instance with con. prototype to access properties and methods on the prototype chain corresponding to the constructor Con
Object.setPrototypeOf(obj,Con.prototype) //obj.__proto__ = Con.prototype
// Execute the code in the Con constructor to bind this to the current instance object obj and pass in the remaining arguments
var result = Con.apply(obj,args) // var result = Con.call(obj,... args)
// Return if an object of reference type is returned; Otherwise, the current instance object obj is returned by default
return result instanceof Object ? result : obj
}
Copy the code
Validation:
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.speak = function() {
alert(this.name + "speak!")}var p = create(Person,"Zhang".3)
p.speak() / / zhang SAN speak!
Copy the code