Summarize several modes of creating objects in JS and their advantages and disadvantages
Factory mode
function createPerson(name,age,job){ var obj = new Object(); obj.name = name; obj.age = age; obj.job = job; obj.sayName = function(){ console.log(this.name); }; return obj; } var person1 = createPerson('John',22,engineer);
Process:
- Create an obj object using the new Object() display
- Add properties and methods directly to obj objects
- return returns the obj object
Disadvantages: the factory pattern does not recognize the type of object.
Constructor Pattern
Rewrite the above code:
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('John',22,engineer); var person2 = new Person('Lin',22,engineer);
The createPerson function has been changed to the Person function
There are other differences between constructor mode and factory mode:
- Create an object without displaying it (without using new Object())
- Add properties and methods directly to this object
- No return statement is required
Process:
- Create a new object through new Person()
- The scope of the constructor Person points to the new object, that is, this points to the new object
- Execute the code in the constructor, that is, add properties and methods to this
- Return new object
be careful:
person1 and person2 hold different instances of person.
Both objects have a constructor attribute, which points to Person;
console.log(person1.constructor); //Person console.log(person2.constructor); //Person
That is, an instance of a custom constructor can be uniquely identified as a specific type through the constructor attribute. (this is not possible in factory mode)
alert(person1 instanceof Person); //true; alert(person2 instanceof Person); //true; alert(person1 instanceof Object); //true; alert(person2 instanceof Object); //true;
Disadvantages of constructor pattern
Disadvantage 1: multiple Function instances with the same name will be created to complete the same task
Same as the above example:
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('John',22,engineer); var person2 = new Person('Lin',22,engineer);
The two instances of Person, person1 and person2, each have a sayName method. But person1 sayName and person2 sayName is not the same, that is, the two methods are each an instance of Function.
Because all ECMAScript functions are objects, they can be written as new Function():
this.sayName = function(){ console.log(this.name); } //Can write this.sayName = new Function("console.log(this.name)");
In other words, through the custom constructor mode, a new Function instance is created every time a new object is instantiated through new Person(). The sayName method in each person is different and is a different instance. Although they have the same name and process the same code.
Every time a new Person instance is created, a new Function instance is created. These Function instances do the same thing with the same name. It's really unnecessary!
How to avoid?
Put the definition of sayName function in Person outside the constructor and rewrite it as follows:
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ console.log(this.name); }
It is equivalent to setting the sayName property inside the constructor Person to the global function sayName(). this.sayName is a pointer to the global function.
This allows multiple Person instances to this The sayname attribute points to this global Function, so there are not too many Function instances with the same name (do the same thing).
Disadvantage 2: global function
It seems that the problem can be solved by defining the internal method of the constructor to the outside as a global function.
But this function defined in the global scope can only be used for certain types of objects. It sounds strange.
Also, if a constructor needs many methods, in order to avoid creating too many Function instances with the same name, should we define many functions in the global scope?!
Prototype mode
Prototype mode can improve the disadvantages of constructor mode:
function Person(){ Person.prototype.name = 'John'; Person.prototype.age = 22; Person.prototype.job = 'engineer'; Person.prototype.sayName = function(){ console.log(this.name); } } var person1 = new Person(); var person2 = new Person();
About prototype objects:
- The functions we create have a prototype attribute, which is a pointer to the prototype object of the function.
- Prototype object: all instances of an object can share the properties and methods it contains
- Prototype objects have a constructor attribute, which is also a pointer to the function where the prototype attribute is located.
Because of Person Prototype prototype object, which allows all instances of Person to share its properties and methods.
Then, like the constructor mode, you don't need to create many Function instances with the same name or define many functions in the global scope.
That is, person Prototype points to the prototype object;
Person.prototype.constructor points to person;
The instances created by Person, person1 and person2, [[prototype]], only point to Person Prototype (prototype object), which is not directly related to the constructor Person.
Prototype pattern search
When the code reads a property of an object instance, it first searches the instance for the existence of the property. If it check s the instance itself, it returns the value of the property; If it cannot be found on the instance, continue to look up and find the prototype object (Person.prototype) of the instance to see if there is this attribute.
This is why different instances can share properties and methods in the prototype object.
Simple grammar
It can be written as follows:
function Person(){}; Person.prototype = { name : 'John', age : 22, job : 'enginee', sayName : function(){ console.log(this.name); } } var person1 = new Person; console.log(person1.constructor == Object);//true; console.log(person1.constructor == Person);//false;
Because I said, Person Prototype will have a constructor attribute, which points to the function where the prototype attribute is located. It can be seen that the prototype is not written in Person, but on Object.
However, it can be modified manually
function Person(){}; Person.prototype = { constructor: Person, name : 'John', age : 22, job : 'enginee', sayName : function(){ console.log(this.name); } }
Combining constructor pattern with prototype pattern
The prototype prototype object in the prototype pattern provides all shared methods and properties for the instance, but some are not suitable for sharing if they are reference types.
Then in the constructor pattern, define the instance attribute (which you don't want to share); Prototype patterns are used to define properties and methods that can be shared for instances.
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.friends = ['Kay','Alex']; } Person.prototype = { constructor: Person; sayName : function(){ console.log(this.name); } }