Each function we create has a prototype (prototype) attribute, which is a pointer to an object that is used to contain properties and methods that can be shared by all instances of a particular type . If it is understood literally, then prototype is the prototype object of the object instance created by invoking the constructor. The advantage of using a prototype object is that you can have all object instances share the properties and methods that it contains. In other words, instead of defining the information for an object instance in the constructor, you can add that information directly to the prototype object, as shown in the following example.
function person () {}person.prototype.name= "Nicholas"; Person.prototype.age= 29; person.prototype.job= "Software Engineer"; Person.prototype.sayname= function () { alert (this.name);}; var person1 = new Person ();p erson1.sayname ();//"Nicholas" var person2 = new Person ();p erson2.sayname ();//"Nicholas" Alert (person1.sayname== person2.sayname); True
Here, we add the Sayname () method and all properties directly to the prototype property of the person, and the constructor becomes an empty function . Even so, you can still create new objects by calling the constructor, and the new objects will have the same properties and methods. However, unlike the constructor pattern, these properties and methods of the new object are shared by all instances. In other words,person1 and person2 Access both the same set of properties and the same sayname () function. to understand the working principle of prototype mode, we must first understand the nature of ECMAScript object.
Understanding prototype Objects
Whenever a new function is created, a prototype property is created for the function based on a specific set of rules, which points to the prototype object of the function. By default, all prototype objects automatically get a constructor (constructor) property that contains a pointer to the function where the prototype property is located.
Take the previous example, Person.prototype. constructor points to person.
With this constructor, we can continue to add additional properties and methods to the prototype object. Once a custom constructor has been created, its prototype object will only get the constructor property by default, and the other methods are inherited from object. When the constructor is called to create a new instance, the inside of the instance contains a pointer (internal property) that points to the constructor's prototype object. ECMA-262 the 5th edition of this pointer is called [[Prototype]]. Although there is no standard way to access [[Prototype] in scripts, Firefox, Safari, and Chrome support a property __proto__ on each object, and in other implementations, this property is completely invisible to the script. However, it is really important to be clear that this connection exists between the instance and the constructor's prototype object, not between the instance and the constructor. As an example of the code that previously used the person constructor and the Person.prototype to create an instance, figure 6-1 shows the relationship between the individual objects.
Here, Person.prototype points to the prototype object, and Person.prototype.constructor refers back to the person. In addition to containing the constructor property, the prototype object includes additional properties that were added later. Each instance of person,--person1 and Person2, contains an intrinsic property that points only to person.prototype; in other words, they have no direct relationship to the constructor function. In addition, it is important to note that although none of the two instances contain properties and methods, we can call Person1.sayname (). This is accomplished by looking up the properties of the object.
Although [[Prototype]] is inaccessible in all implementations, the isPrototypeOf () method can be used to determine whether the relationship exists between objects. Essentially, if [[Prototype]] points to an object that calls the isPrototypeOf () method (Person.prototype), then this method returns True as follows:
<span style= "White-space:pre" ></span>alert (Person.prototype.isPrototypeOf (Person1));//truealert ( Person.prototype.isPrototypeOf (Person2));//true
Here, we tested the Person1 and Person2 with the isPrototypeOf () method of the prototype object. Because they have a pointer to person.prototype inside, they all return true.
ECMAScript 5 Adds a new method called Object.getprototypeof (), which returns the value of [[Prototype]] in all supported implementations. For example:
<span style= "White-space:pre" ></span>alert (object.getprototypeof (person1) = = Person.prototype); Truealert (Object.getprototypeof (person1). name);//"Nicholas"
The first line of code here just determines that the object returned by Object.getprototypeof () is actually the object's prototype. The second line of code gets the value of the name attribute in the prototype object, which is "Nicholas". Using object.getprototypeof () makes it easy to get a prototype of an object, which is important in cases where inheritance is implemented using prototypes.
Browsers that support this approach are ie9+, Firefox 3.5+, Safari 5+, Opera 12+, and Chrome.
Each time the code reads a property of an object, the search is performed once, and the target is a property with the given name. The search begins first from the object instance itself.
If a property with the given name is found in the instance, the value of the property is returned;
If it is not found, continue searching for the prototype object pointed to by the pointer, looking for the property with the given name in the prototype object.
If this property is found in the prototype object, the value of the property is returned.
In other words, when we call Person1.sayname (), we perform two searches successively. First, the parser asks: "Does the instance Person1 have a sayname attribute?" "Answer:" No. ”
Then, it continues the search, and then asks, "Does the Person1 prototype have a Sayname attribute?" "A:" Yes. ”
As a result, it reads the function that is stored in the prototype object. When we call Person2.sayname (), we will reproduce the same search process and get the same results.
This is where multiple object instances share the fundamentals of the properties and methods saved by the prototype.
Although the values saved in the prototype can be accessed through an object instance, the values in the prototype cannot be overridden through an object instance. If we add a property to the instance with the same name as an attribute in the instance prototype, we create the property in the instance that will mask that property in the prototype. Take a look at the following example:
function person () {}person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName =function () { alert (this.name);}; var person1 = new Person (), var person2 = new Person ();p erson1.name = "Greg", Alert (person1.name),//"Greg"-from Instance alert ( Person2.name);//"Nicholas"--from the prototype
In this example, the name of Person1 is masked by a new value. However, both access person1.name and access Person2.name can return the values normally, namely "Greg" (from the object instance) and "Nicholas" (from the prototype). When accessing Person1.name in alert (), it is necessary to read its value, so a property named name is searched on this instance. This property does exist, so it returns its value without having to search the prototype again. When accessing Person2 in the same way. Name, the property is not found on the instance, so the prototype continues to be searched, and the Name property is found there.
When you add a property to an object instance, this property masks the property of the same name saved in the prototype object; in other words, adding this property will only prevent us from accessing that property in the prototype, but not modifying that property. Even if this property is set to NULL, this property is set only in the instance, not its connection to the prototype. However, using the delete operator allows you to completely remove the instance properties, allowing us to revisit the properties in the prototype, as shown below.
function person () {}person.prototype.name= "Nicholas"; Person.prototype.age= 29; person.prototype.job= "Software Engineer"; Person.prototype.sayname= function () { alert (this.name);}; var person1 = new Person (), var person2 = new Person ();p erson1.name= "Greg"; alert (person1.name);//"Greg"-from Instance alert ( Person2.name);//"Nicholas"-from prototype Deleteperson1.name;alert (person1.name);//"Nicholas"-from prototype
In this modified example, we use the delete operator to delete the Person1.name, which previously saved the "Greg" value, which masked the prototype attribute of the same name. After deleting it, the connection to the name attribute in the prototype is restored. Therefore, when you call Person1.name again, the value of the name attribute in the prototype is returned.
use hasOwnProperty () method can detect whether a property exists in an instance or exists in a prototype. This method (do not forget that it is inherited from object) returns true only if the given property exists in the object instance . Take a look at the following example.
function person () {}person.prototype.name= "Nicholas"; Person.prototype.age= 29; person.prototype.job= "Software Engineer"; Person.prototype.sayname= function () { alert (this.name);}; var person1 = new Person (), var person2 = new Person (), Alert (Person1.hasownproperty ("name"));//falseperson1.name= "Greg" alert (person1.name);//"Greg"-from Instance Alert (Person1.hasownproperty ("name")),//true alert (person2.name);/"Nicholas "--From the prototype alert (Person2.hasownproperty (" name "));//false Delete Person1.name;alert (person1.name);//" Nicholas "-- From the prototype alert (Person1.hasownproperty ("name"));//false
When you access an instance property by using the hasOwnProperty () method, it is clear when the prototype attribute is accessed. When you call Person1.hasownproperty ("name"), it returns true only if Person1 overrides the Name property, because only then name is an instance property, not a prototype property. Figure 6-2 shows the relationship between the implementation of the above example in different situations and the prototype (for simplicity, the diagram omits the relationship to the person constructor).
Introduction to JavaScript Design Patterns (iii) prototype mode