js prototype chain that has been confused for many years

Keywords: Attribute

1. Attribute Descriptor (Attribute Label)
Each attribute of an object has multiple tags, also known as attribute descriptors.
Writtable
Is enumerable enumerable
Is configurable for deletion
Value attribute value
get method set method


Get and set are keywords inside objects. They are different from other attributes. They do not exist in the form of key-value pairs. They can be directly followed by function expressions at the beginning of get set keywords. The default method is as follows.
Get method: get attribute name () {return this. $attribute name}

Set method: set attribute name (val){this. $attribute name = val}

var student={
     name:"Xiao Ming",
     get age(){
         if(this.$age){
             return this.$age;
         }else{
	     return new Date().getFullYear()-1988;
         }
     },
     set age(val){
         this.$age=val-0;
     }
}
console.log(student.age);=>29
student.age=100;
console.log(student.age);=>100

In addition, looping through object attributes for...in will also traverse attributes on the prototype chain, unless the attribute descriptor enumerable=false

for( obj in Object){ ...}
It should be noted that: the order of traversal is uncertain; when the object's attribute descriptor enumerable is false, it will not be enumerated; it will be affected by the object prototype chain;

JS delete operator:
Object attribute descriptor configurable=false, the attribute can not be deleted, return false; global variables, local variables can not be deleted, implicitly declare that global variables can be deleted; Object.prototype can not be deleted; delete object does not exist properties will still return true.




Normally, the default label values of the attributes of the custom created object in the code are all true, and some attributes inherited from Object are labeled false, which can be viewed by the following methods:
Take the label enumerable for example. Other labels are used the same way.
var cat={ leg:4}
Cat. propertyIsEnumerable ("leg") => true can be enumerated
Cat. propertyIsEnumerable ("toString") => false
If you modify the attribute label, you can do the following
Object. defineProperty (object name, attribute name, {enumerable:boolean value, {attribute value,} get:function(){},set:function(){})
Object.defineProperty(cat,"leg",{enumerable:false,value:"4"});
Look again
Cat. propertyIsEnumerable ("leg") => false is not enumerable


You can also list all tags for an attribute of an object in the following ways
Object. getOwnProperty Descriptor (object name, attribute name);
Object.getOwnPropertyDescriptor({age:12},"age")=>
Object{writable:true,enumerable:true,configurable:true,value:12}

2. Object prototype chain (a bit difficult)
Create objects: new object constructor (), Object. create (object prototype)


The prototype _proto_of the object created by I.new points to the prototype attribute of its constructor, which is also an object, while the prototype of prototype points to the Object.prototype attribute, which is also an object, whose prototype points to null, so Object is the end of all prototype chains. When a function declaration creates a function, it presupposes a prototype attribute, as follows

var foo=function(){this.x=1}
foo.prototype=>{constructor:foo,_proto_:Object.prototype,x:1}
Only function objects preset prototype attributes. Object objects also have prototype attributes. No other objects have prototype attributes.


II. The prototype_proto_of the custom object points directly to the prototype attribute of the Object

var foo=function(){}
foo.prototype.y=1;
var obj=new foo();
obj.x=2;
console.log(obj.x)//2 Because the obj object itself contains the x attribute, there's nothing to say.
console.log(obj.y)//1. The obj object attribute has no y attribute. It will go to its prototype _proto_that is, its constructor's prototype attribute (foo.prototype), and if not, continue to search until the end of the prototype chain object, it will return undefined.

If it is necessary to determine whether an attribute belongs to the object, the hasOwnProperty method can be called to determine whether the attribute belongs to the object or not. If the attribute is not in the object itself and comes from the prototype chain of the object, it will return false as well.

obj.hasOwnProperty("x")=>true
obj.hasOwnProperty("y")=>false
foo.hasOwnProperty("y")=>false
foo.prototype.hasOwnProperty("y")=>false
As mentioned above, the prototype chain:
obj._proto_=>foo.prototype
foo.prototype._proto_=>Object.prototype
Object.prototype._proto_=null
But not all objects have the _proto_attribute, such as var obj=Object.create(null), where obj._proto_is undefined.


III. Object. create (parameters) takes parameters as prototypes of new objects

var a={x:1}
var obj=Object.create(a);//At this point obj._proto_points to object a, while prototype a. _proto=> Object. prototype
obj.hasOwnProperty("x");//false
a.hasOwnProperty("x");//true

To sum up, objects in js are inherently objects inherited from the end of the prototype chain.


3. Talking about prototype chains, I think it's time to talk about inheritance in Js. In the following example, we define a parent class Person and a subclass Student.
The parent Person contains the attribute name age legs head and the behavior (method) hi walk, where the attributes legs and head are fixed

In addition to the parent class properties and behaviors, the child class Student also includes the className and the study behavior. It also overrides the parent class's hi behavior.

function Person(name,age){
	//The attribute name and age of the parent class, where this is the calling object of the directed function
	this.name=name;
	this.age=age;
}
//The hi behavior of the parent class
Person.prototype.hi=function(){
	console.log("Hello, everyone. I am"+this.name+",I am this year"+this.age+"Years old!");
}
//Parent walk Behavior
Person.prototype.walk=function(){
	console.log(this.name+"I'm taking a walk....");
}
//Parents often have invariant attributes
Person.prototype.legs=2;
Person.prototype.head=1;


function Student(name,age,className){
	//Call the parent class and pass the current invocation object to the parent class. This code is just to better reflect inheritance, you can use this. name = name directly; this. age = age, but you can't withdraw inheritance.
	Person.call(this,name,age);
	//Attributes of Subclass Student Extension
	this.className=className;
}
/*If you want to inherit Person from Student, you must let Student.prototype point to Person.prototype on the prototype chain, that is, Student.prototype. _prototype = Person.prototype. The next sentence is to perform this operation, of course, not the only way, through Student.prototype=new Person(); the same can be done. There are several misunderstandings here:
a.  Student=new Person();//Instead of inheriting Person, it assigns the Person object directly to Student and overrides the original Student object.
b.  Student.prototype=Person.prototype;//This is not an inheritance, but a direct assignment of Person.prototype to Student.prototype, so that their prototypes point to Object.prototype, that is, Student.prototype. _prototype = Person.prototype. _prototype = Object.prototype, the parent class is Object, and when extending Student, Person will be modified as well.*/

Student.prototype=Object.create(Person.prototype);
//This code has no practical significance, just to ensure consistency between Student.prototype.constructor and the current object, because after executing the previous code, Student.prototype.constructor=Person, if not modified, will not affect inheritance.
Student.prototype.constructor=Student;


Student.prototype.study=function(){
	console.log(this.name+"I'm learning");
}
Student.prototype.hi=function(){
	console.log("Hello, everyone. I'm from"+this.className+"Ben"+this.name+",I am this year"+this.age+"Years old!")
}
var tom=new Student("tom","20","3");
tom.hi(); //Hello, everyone. I'm tom from Class 3. I'm 20 years old.
tom.walk();//tom is walking.
tom.study();//tom is learning


Note: object.create() is a prototype of ES5 inheritance parent class. It does not support versions below ie9. You can use the following code to be compatible with versions below IE9.

if(!Object.create){
	Object.create=function(_proto_){
		function F(){};
		F.prototype=_proto_;
		return new F;
	}
}

Posted by Catz on Thu, 13 Jun 2019 10:46:55 -0700