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:

  1. Generate a few more instances, and the code becomes redundant and cumbersome to write
  2. 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

  1. There is still no apparent connection between CAT1 and CAT2.
  2. 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:

  1. 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).
  2. You don’t have to bind the prototype, because new will do it for you
  3. Don’t return the new object, because new will do it for you

Var cat1 = new Cat(“guaiguai”,” white hair “)

  1. Create a new object cat1
  2. Assign the constructor’s scope to the new object cat1 (thus this refers to the new object)
  3. Execute the code in the constructor (add attributes to the new object);
  4. 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