In my work, I sometimes see the two properties of prototype and __proto__. I have always been a little confused about these two properties, but I decided to make a summary to deepen my understanding by looking up relevant materials, and please point out any errors.

  • prototype
  • __proto__
  • Two methods associated with the __proto__ attribute
  • Determine whether an attribute exists in an instance object or a method in a prototype object
  • Methods of getting or traversing properties in an object
  • Prototype chain

1, the prototype

Each function has a Prototype property, which is a pointer to an object. The purpose of this object is to contain properties and methods shared by all instances of a particular type. The advantage of using this object is that all instance objects share its properties and methods. This property is only available for classes in JS (or objects that can be used as constructors)

2、 __proto__

Each instance object has a __proto__ attribute that points to the constructor’s prototype object. The __proto__ attribute is generated when the constructor is called to create the instance object. This property exists between the instance and the constructor’s prototype object, not between the instance and the constructor.

function Person(name, age, job){    
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        console.log(this.name);
    }; // This is logically equivalent to the declared function
}
var person1=new Person("Nicholas".29."Software Engineer");
console.log(person1);
console.log(Person);
console.log(person1.prototype);//undefined
console.log(person1.__proto__);
console.log(Person.prototype);
console.log(person1.__proto__===Person.prototype);//true
Copy the code

Conclusion:

The constructor’s prototype property is undefined. The constructor’s prototype is an object. The __proto__ attribute is generated when the constructor is called to create the instance object. The __proto__ property of the instance object created by calling the constructor refers to the constructor’s prototype, essentially inheriting the constructor’s __proto__ property. 4. By default, all prototype objects automatically get a constructor property that contains a pointer to the function where the Prototype property resides.

3. Two methods related to the __proto__ attribute

IsPrototypeOf (): Although __proto__ is not accessible in any implementation, the isPrototypeOf() method can be used to determine whether this relationship exists between objects.

alert(Person.prototype.isPrototypeOf(person1)); //true
alert(Person.prototype.isPrototypeOf(person2)); //true
Copy the code

Object.getprototypeof (): In all supported implementations, this method returns the value of __proto__. Such as:

alert(Object.getPrototypeOf(person1) == Person.prototype); //true
alert(Object.getPrototypeOf(person1).name); //"Nicholas" person1Is the example in the following codeCopy the code

Note: Although values stored in stereotypes can be accessed through object instances, values in stereotypes cannot be overridden through object instances. If we add a property to the instance that has the same name as one of the properties in the instance stereotype, we create that property in the instance, and that property will mask that property in the stereotype. Here’s an 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();
person1.name = "Greg";
alert(person1.name); //"Greg" -- from the instance
alert(person2.name); //"Nicholas" -- from the prototype
Copy the code

4. To determine whether an attribute exists in an instance object or a prototype object, there are the following methods

HasOwnProperty (): Can check whether a property exists in the instance or in the stereotype. A return value of true indicates that the property exists in the instance object, otherwise false.

The in operator: whether the property exists in the instance or in the stereotype. Returns true whenever it exists in an object. But you can use both the hasOwnProperty() method and the in operator to determine whether the property exists in the object or in the stereotype.

var person1 = new Person();
var person2 = new Person();
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true
person1.name = "Greg";
alert(person1.name); //"Greg" -- from the instance
alert(person1.hasOwnProperty("name")); //true
alert("name" in person1); //true
alert(person2.name); //"Nicholas" -- from the prototype
alert(person2.hasOwnProperty("name")); //false
alert("name" in person2); //true
delete person1.name;
alert(person1.name); //"Nicholas" -- from the prototype
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true
Copy the code

5. Methods to get or iterate over attributes in an object

For-in: Returns an enumerable property that can be accessed through a for-in loop, whether the property is in the instance or in the stereotype.

function Person(name, age, job) {
	this.name = name;
	this.age = age;
	this.job = job;	
}
Person.prototype={
	sayName:function(){
		return this.name; }}var p=new Person("Li Ming".30."Poet");
for(var prop in p){
	console.log(prop);Name, age, job, sayName
}
console.log(Object.keys(p));//["name", "age", "job"]
console.log(Object.keys(Person.prototype));//["sayName"]
console.log(Object.getOwnPropertyNames(Person.prototype))
// ["constructor", "sayName"] 
Copy the code

Object.keys() : Retrieves all enumerable properties on an instance Object. Object. GetOwnPropertyNames () : for instance objects all attributes, whether it can be enumerated.

Note: When you use an Object literal to override an entire prototype Object, you essentially override the default Prototype Object completely, so that the constructor property becomes the new Object’s constructor property (pointing to the Object constructor) and no longer points to Person. However, you can make it point to the original constructor by specifying the constructor property when you override the prototype object. At this point, although the instanceof operator can still return the correct result, it is no longer possible to determine the type of the object through Constructor.

Object instanceof constructor: Checks whether constructor. Prototype exists on the prototype chain of parameter object.

function Person() {}
var friend2 = new Person();
Person.prototype = {
	//constructor : Person,
	name: "Nicholas".age: 29.job: "Software Engineer".sayName: function() {
		alert(this.name); }};var friend = new Person();
console.log(friend2 instanceof Object); //true
console.log(friend2 instanceof Person); //false,
console.log(friend2.constructor == Person); //true
console.log(friend2.constructor == Object); //false

console.log(friend instanceof Object); //true
console.log(friend instanceof Person); //true
console.log(friend.constructor == Person); //false
console.log(friend.constructor == Object); //true
Copy the code

Because of the dynamic nature of stereotypes, constructor calls add a Prototype pointer to the original Prototype to the instance, and changing the Prototype to another object breaks the link between the constructor and the original Prototype. Look at the following example

function Person(){}var friend = new Person();
Person.prototype = {
    constructor: Person,
    name : "Nicholas".age : 29.job : "Software Engineer".sayName : function () {
        alert(this.name); }};var friend2=new Person();
friend.sayName(); //Uncaught TypeError: friend.sayName is not a function 
friend2.sayName();//Nicholas
console.log(friend instanceof Person);//false
console.log(friend instanceof Object);//true
console.log(friend2 instanceof Person);//true
Copy the code

This is because friend1’s prototype refers to the original person. prototype object before the override of person. prototype. Friend2’s prototype points to person. prototype after overwriting person. prototype. See the figure below

6. Prototype chain

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
};
function SubType(){
    this.subproperty = false;
}
// SuperType is inherited
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
    return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true
Copy the code

SubType. Prototype = new SuperType (); This code makes all properties and methods that previously existed in instances of SuperType now exist in subType.prototype. Cause instance constructor to point to SuperType.

console.log(instance.constructor===SuperType);//true
Copy the code

Bottom line: When you access an instance property, you first search for that property in the instance. If this property is not found, the search continues for the instance stereotype. In the case of inheritance through the prototype chain, the search process can continue up the prototype chain. When no properties or methods can be found, the search process always goes round and round until it stops at the end of the prototype chain.

In the example above, calling instance.getsupervalue () goes through four search steps:

  1. Search for instance instance;
  2. Search SubType. The prototype;
  3. Search for instances of SuperType;
  4. Search for superType.prototype and you’ll find it in the last step.