When creating objects through Object constructors or object literals, when creating many objects with the same interface, a large amount of duplicate code will be generated. For simplicity, the factory model was introduced.
Factory model
function createPerson(name, age, job) { var obj = new Object(); obj.name = name; obj.age = age; obj.job = job; obj.sayHello(){ alert(this.name); }; return obj;}var p1 = createPerson("xxyh", 19, "programmer");var p2 = createPerson("zhangsan", 18, "student");This way of creating objects greatly simplifies the code, but there is also a shortcoming, that is, the type of object cannot be determined. To solve this problem, the following pattern appears.
Constructor mode
Create a custom constructor to define properties and methods of custom object types.
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function () { alert(this.name); };}var p1 = new Person("xxyh", 19, "programmer");var p2 = new Person("Jack", 18, "student");In the above example, Person() replaces createPerson(). In addition, there are several differences:
•Create objects without display;
• Directly assign attributes and methods to this object
•No return statement
To create a Person object, you must use the new operator. It is divided into 4 steps:
•Create a new object
• Assign the scope of the constructor to a new object
•Execute the code in the constructor
•Return new object
p1 and p2 respectively save an instance of Person.
alert(p1.constructor == Person); // truealert(p2.constructor == Person); // true
It is best to use instanceof when detecting types:
alert(p1 instanceof Object); // truealert(p1 instanceof Person); // truealert(p2 instanceof Object); // truealert(p2 instanceof Person); // truealert(p2 instanceof Person); // true
p1 and p2 are instances of Object, because all objects are inherited from Object.
2.1 Treat constructors as functions
// Use var person = new Person("xxyh", 19, "programmer"); person.sayName(); // "xxyh"// Use as a normal function Person("zhangsan", 18, "student"); // Add to windowwindow.sayName(); // "zhangsan"// Call var obj in the scope of another object obj = new Object(); Person.call(obj, "Jack", 29, "manager"); obj.sayName(); // "Jack", obj has all properties and methods2.2 Constructor problem
The problem with using constructors is that each method needs to be recreated on each instance. p1 and p2 both have a sayName() method, but they are not an instance of Function. In JavaScript, a function is an object, so every time a function is defined, an object is instantiated.
The constructor can also be defined like this:
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = new Function("alert(this.name)");}Therefore, functions of the same name on different instances are not equal:
alert(p1.sayName == p2.sayName); // false
However, creating two functions with the same function is redundant, and there is no need to bind the function to a specific object before executing the code.
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = sayName;}function saysName() { alert(this.name);}var p1 = new Person("xxyh", 19, "programmer");var p2 = new Person("Jack", 18, "student");The above moves the definition of sayName() outside the constructor, and then sets the attribute saysName as the global sayName function inside the constructor. In this way, sayName contains a pointer to the function, and p1 and p2 share the same sayName() function defined in the global scope.
However, there is a new problem with this: functions defined in the global scope can only be called by a certain object. And if the object defines many methods, the reference type loses its encapsulation.
Prototype chain mode
Each function has a prototype property, which is a pointer pointing to an object. The purpose of this object is to include properties and methods that can be shared by all instances of a specific type . prototype is the prototype object of that object instance created by calling the constructor. The advantage of using a prototype object is that all object instances can share the properties and methods it contains. This means that instead of defining the information of the object instance in the constructor, this information is added to the prototype object.
function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = 19;Person.prototype.job = "programmer";Person.prototype.sayName = function () { alert(this.name);};var person1 = new Person(); person1.sayName(); // "xxyh"var person2 = new Person(); person2.sayName(); // "xxyh"alert(person1.sayName == person2.sayName); // true3.1 Understanding prototype objects
Just create a new function, a prototype property will be created for the function, which points to the function's prototype object. By default, all prototype objects will automatically obtain a constructor property. This property contains a pointer to the function where the prototype property is located. Person.prototype.constructor points to Person.
When the constructor is called to create an instance, the inside of the instance will contain a pointer (internal property) to the prototype object of the constructor, called [[Prototype]]. Accessed via _proto in Firefox, Safari and Chrome. This connection exists between the instance and the prototype object of the constructor, not between the instance and the constructor.
The following figure shows the relationship between each object:
Person.prototype points to the prototype object, and Person.prototype.constructor points to Person. In addition to the constructor attribute, there are other added attributes in the prototype. Person instances all contain an internal property that only points to Person.prototype, and they have no direct relationship with the constructor.
Although [[Prototype]] cannot be accessed, the isPrototypeOf() method can be used to determine whether there is such a relationship between objects.
alert(Person.prototype.isPrototypeOf(person1)); // truealert(Person.prototype.isPrototypeOf(person2)); // true
When reading an object's properties, a search is performed, with the goal of the attribute with the given name. The search starts with the object instance itself. The search starts from the object instance itself. If an attribute with the given name is found in the instance, the value of the attribute is returned; if it is not found, continue to search for the prototype object pointed to by the pointer and look for the attribute with the given name in the prototype object. If this property is found in the prototype object, the value of the property is returned.
The values saved in the prototype can be accessed through the object instance, but the values stored in the prototype cannot be rewrited through the object instance . If you add an attribute to the instance with the same name as an attribute in the instance prototype, the attribute will block the attribute in the prototype.
function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () { alert(this.name);};var person1 = new Person();var person2 = new Person();person1.name = "oooo";alert(person1.name); // "oooo"alert(person2.name); // "xxyh"In the above example, the name attribute in person1 blocks the name attribute in the prototype.
When an attribute is added to an object instance, this attribute will block the attributes of the same name saved in the prototype object. This means that the existence of this property will prevent access to that property in the prototype. Use delete to delete instance properties.
function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () { alert(this.name);};var person1 = new Person();var person2 = new Person();person1.name = "oooo";alert(person1.name); // "oooo"alert(person2.name); // "xxyh"delete person1.name;alert(person1.name); // "xxyh"hasOwnProperty() can detect whether a property exists in an instance or in a prototype.
function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () { alert(this.name);};var person1 = new Person();var person2 = new Person();alert(person1.hasOwnProperty("name")); // falseperson1.name = "oooo";alert(person1.hasOwnProperty("name")); // trueThe following figure shows the relationship between implementation and prototype in different situations:
3.2 Prototype and in operator
How to use the in operator: use it alone, in a for-in loop. When used alone, the in operator returns true when accessing a given property through the object , whether it exists in the instance or in the prototype.
function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () { alert(this.name);};var person1 = new Person();alert("name" in person1); // trueperson1.name = "oooo";alert("name" in person1); // trueCombined with the previous hasOwnProperty() feature, it can be determined that a property is a property in the prototype or a property in the instance. If the in operator returns true and hasOwnProperty returns false, the property is a property in the prototype.
function hasPrototypeProperty(object, name) { return !object.hasOwnProperty(name)&& (name in object);}Next, let’s take a look at the usage of hasPrototypeProperty():
function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () { alert(this.name);};var person = new Person();alert(hasPrototypeProperty(person, "name")); // trueperson.name = "oooo";alert(hasPrototypeProperty(person, "name")); // falseWhen using the for-in loop, all enumerable properties that can be accessed through the object, including properties in the instance and properties in the prototype. Instance attributes that block the unenumerable data in the prototype (i.e. attributes marked as false by [[Enumerable]]) will also be returned in for-in, because according to regulations, all attributes defined by developers are enumerable.
To obtain all enumerable instance properties on an object, you can use the Object.keys() method.
function Person() {}Person.prototype.name = "xxyh";Person.prototype.age = "20";Person.prototype.job = "programmer";Person.prototype.sayName = function () { alert(this.name);};var keys = Object.keys(Person.prototype);alert(keys); // name, age, job, sayNamevar p1 = new Person();p1.name = "oooo";p1.age = 15;var p1_keys = Object.keys(p1);alert(p1_keys); // name, ageIf you need to get all instance properties, you can use the Object.getOwnPropertyNames() method
var keys = Object.getOwnPropertyNames(Person.prototype);alert(keys); // "constructor,name,age,job,sayName"
3.3 Simpler prototype syntax
To streamline input, override the integrated prototype object with an object literal containing all properties and methods.
function Person() { }Person.prototype = { name : "xxyh", age : 18, job : "programmer", sayName : function () { alert(this.name); }};The above sets Person.prototype to equal a new object created in object literal form. The result is the same, but the constructor attribute is no longer pointing to Person.
The correct result can be returned through instanceof, but the constructor cannot determine the type of the object:
var boy = new Person();alert(boy instanceof Object); // truealert(boy instanceof Person); // truealert(boy.constructor == Person); // falsealert(boy.constructor == Object); // true
The constructor value can be set in the following ways:
function Person() {}Person.prototype = { constructor : Person, name : "xxyh", age : 18, job : "programmer", sayName : function () { alert(this.name); }};3.4 Dynamicity of prototype chains
Since the process of finding values in a prototype is a search, any modifications made to the prototype object are reflected on the instance. But if the entire prototype object is rewrite, the result will be different. When calling the constructor, a [[prototype]] pointer to the original prototype is added to the instance, and modifying the prototype to another object is equivalent to cutting off the connection between the constructor and the original prototype. The pointer in the instance points to the prototype only, not to the constructor.
function Person() {}var boy = new Person();Person.prototype = { constructor : Person, name : "xxyh", age : 29, job : "programmer", sayName : function () { alert(this.name); }};boy.sayName(); // ErrorThe specific process is as follows:
As can be seen from above, rewriting prototype objects cuts off the connection between existing prototypes and any previously existing object instances; they refer to the original prototype.
3.5 Prototype of native object
All native reference types define methods on the prototype of the constructor. Through the prototype of the native object, not only can the default method be obtained, but new method can also be defined.
String.prototype.startsWith = function (text) { return this.indexOf(text) == 0;};var msg = "good morning";alert(msg.startsWith("good")); // true3.6 Problems with prototype objects
There are two problems with the prototype pattern:
•Everything the same attribute value by default.
•All attributes in the prototype are shared by the instance
Let's see an example below:
function Person() {}Person.prototype = { constructor: Person, name: "xxyh", age : 18, job : "programmer", friends:["Zhang San", "Li Si"], sayName: function () { alert(this.name); }};var p1 = new Person();var p2 = new Person();p1.friends.push("Wang Wu");alert(p1.friends); // Zhang San, Li Si, Wang Wu alert(p2.friends); // Zhang San, Li Si, Wang Wu alert(p1.friends == p2.friends); // trueA item was added above through p1.friends. Since the friends array exists in Person.prototype, it is also reflected in p2.friends. However, instances generally have all their own attributes.
Use constructor mode and prototype mode in combination
The constructor mode is used to define instance properties, and the prototype mode is used to define methods and shared properties. In this way, each instance will have its own copy of the instance attributes, but at the same time share a reference to the method.
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.friends = ["Zhang San", "Li Si"];}Person.prototype = { constructor: Person, sayName: function () { alert(this.name); }}var p1 = new Person("Xiao Xiao Yihan", 18, "programmer");var p2 = new Person("Kuiba", 10, "monster hunt");p1.friends.push("Wang Wu");alert(p1.friends); // Zhang San, Li Si, Wang Wu's alert(p2.friends); // Zhang San, Li Si alert(p1.friends == p2.friends); // falsealsealert(p1.sayName == p2.sayName); // trueIn the above example, the instance properties are defined in the constructor, while the shared property constructor and method sayName() are defined in the prototype. The modification of p1.friends will not affect the results of p2.friends.
Dynamic Prototype Mode
The dynamic prototype pattern encapsulates all information in the constructor, and by initializing the prototype in the constructor, it maintains the advantage of using both the constructor and the prototype. That is to say, it is possible to determine whether the prototype needs to be initialized by checking whether a method that should exist is effective.
function Person(name, age, job) { // Property this.name = name; this.age = age; this.job = job; // Method if (typeof this.sayName != "function") { Person.prototype.sayName = function () { alert(this.name); } }}This will only be added to the prototype when the sayName() method does not exist, and will only be executed when the constructor is called for the first time.
Parasitic constructor pattern
The idea of this pattern is to create a function whose function is to encapsulate the code that creates the object and then return the newly created object.
function Person(name, age) { var obj = new Object(); obj.name = name; obj.age = age; obj.sayName = function () { alert(this.name); } return obj;}var boy = new Person("xxyh", 19, "programmer");boy.sayName();It should be noted: First of all, the returned object has no relationship with the constructor or the prototype attributes of the constructor; the object returned by the constructor is no different from the object created outside the constructor. The instanceof operator cannot be relied on to determine the object type.
Stable constructor pattern
A safe object refers to an object that has no public attributes and its methods do not refer to this. Stable constructors follow a similar pattern to parasitic constructors, but there are two differences:
•The instance method of the newly created object does not refer to this;
•Constructor is not called using the new operator
Rewrite the Person constructor as follows:
function Person(name, age, job) { var obj = new Object(); obj.sayName = function () { alert(name); }; return obj;} function Person(name, age, job) { var obj = new Object(); obj.sayName = function () { alert(name); }; return obj;}The above article briefly talks about the creation of JavaScript objects is all the content I share with you. I hope it can give you a reference and I hope you can support Wulin.com more.