The prototype chain is a bit confusing to understand, and there is a lot of online information. Every time I can’t sleep at night, I always like to find some prototype chains and closures articles online to read, which is very effective.
Don’t worry about those many terms, it really won’t help you except to make your brain twist. Just look at the prototype chain simply and roughly, and think about things that have nothing to do with the code, such as humans, demons and shemale men.
1) People are born by human beings, and monsters are born by demons. Humans and demons are both instances of objects, while humans and demons are prototypes. A prototype is also an object, called a prototype object.
2) A person's mother and his father can give birth to a bunch of babies, and a demon mother and his father can give birth to a bunch of babies. A man's wife and a man can give birth to a bunch of babies. A man is a constructor, commonly known as a man.
3) People can record information about sex, so people can find information about sex through sex, that is, they can find the constructor through prototype objects.
4) People can give birth to many babies in their mothers, but these babies only have one mother, which is the uniqueness of the prototype.
5) People are also born by people, they find people through people, and then find people through people... This relationship is called prototype chain.
6) The prototype chain is not infinite. When you keep looking up through people, you will find that people are fucking... are not fucking humans, that is, the prototype chain finally points to null.
7) People born with a mom will look like people, and monsters born with a mom will be ugly. This is called inheritance.
8) You inherited the skin color of your mother, your mother inherited the skin color of your mother, your mother..., this is the inheritance of the prototype chain.
9) If you don’t have a home, then your home refers to your mother’s home; if your mother doesn’t have a home, then your home refers to your mother’s home... This is the upward search of the prototype chain.
10) You will inherit your mother's appearance, but you can also dye your hair, shampoo, cut and blow, that is, the attributes of the object can be customized and will override the inherited attributes.
11) Although you have washed, cut, blown and dyed yellow hair, you cannot change your mother's appearance. The younger brother and sister born to your mother have nothing to do with your yellow hair washing, cut, and blown yellow hair, that is, the object instance cannot change the properties of the prototype.
12) But if your house is burned by you, it means that your mother and your brothers are burned, and this is the sharing of prototype attributes.
13) Your mother's nickname is Azhen, and her neighbor's aunt calls you Azhener, but after your mother's hair turned from Piaorou to the Golden Lion King, the aunt next door changed her words and called you the Golden Lion Prince. This is called the dynamic nature of the prototype.
14) Your mother loves beauty and went to Korea for plastic surgery. She couldn't even recognize her mother. Even if your mother's hair changed back to softness, the neighbor next door still called you the Golden Lion Prince. Because no one recognized your mother, your mother has returned to the factory after plastic surgery. This is the overall rewriting of the prototype.
Damn it! You're enough! Don't BB! Show me the code!
function Person (name) { this.name = name; }function Mother () { }Mother.prototype = { //Mother's prototype age: 18,home: ['Beijing', 'Shanghai']};Person.prototype = new Mother(); //Person's prototype is Mother//Use the chrome debugging tool to view the prototype, providing the __proto__ interface to view the prototype var p1 = new Person('Jack'); //p1:'Jack'; __proto__:18,['Beijing','Shanghai']var p2 = new Person('Mark'); //p2:'Mark'; __proto__:18,['Beijing','Shanghai']p1.age = 20; /* The instance cannot change the basic value attribute of the prototype, just as you wash, cut, blow and dye the yellow hair has nothing to do with your mother* The ordinary operation of adding an age attribute under the p1 instance has nothing to do with the prototype. Same as var o{}; o.age=20. * p1: There is an additional attribute age below, and __proto__ is the same as Mother.prototype, age=18. * p2: Only attribute name, __proto__ is the same as Mother.prototype*/p1.home[0] = 'Shenzhen'; /* Sharing of reference type attributes in the prototype is just like you burn your home, it is burning your whole family's home* This is a bit of a pass, let's nag it carefully below? * p1:'Jack',20; __proto__:18,['Shenzhen','Shanghai']* p2:'Mark'; __proto__:18,['Shenzhen','Shanghai']*/p1.home = ['Hangzhou', 'Guangzhou']; /* In fact, the same operation as p1.age=20. Change to this understanding: var o{}; o.house=['big','house']* p1:'Jack',20,['Hangzhou','Guangzhou']; __proto__:18,['Shenzhen','Shanghai']* p2:'Mark'; __proto__:18,['Shenzhen','Shanghai']*/delete p1.age; /* After deleting the custom attributes, the originally overwritten prototype value will be re-expected. This is the upward search mechanism, so there is the following dynamics* p1: 'Jack',['Hangzhou','Guangzhou']; __proto__:18,['Shenzhen','Shanghai']* p2: 'Mark'; __proto__:18,['Shenzhen','Shanghai']*/Person.prototype.lastName = 'Jin'; /* Rewrite the prototype and dynamically react to the instance. Just as your mother has become a trendy person, the neighbors say you are the son of a trendy woman when they mention it* Note that we are rewriting the prototype of Person here, which is to add a lastName attribute to Mother, which is equivalent to Mother.lastName='Jin'* This is not to change Mother.prototype. If you change different levels, the effects will often be very different. * p1: 'Jack',['Hangzhou','Guangzhou']; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']* p2: 'Mark'; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']*/Person.prototype = { age: 28, address: { country: 'USA', city: 'Washington' }};var p3 = new Person('Obama'); /* Rewrite the prototype! At this time, Person's prototype had completely become a new object, which means that Person had changed his mother. * To understand it like this: var a=10; b=a; a=20; c=a. So b remains unchanged and becomes c, so p3 changes and has nothing to do with Mother. * p1: 'Jack',['Hangzhou','Guangzhou']; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']* p2: 'Mark'; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']* p3:'Obama';__proto__: 28 {country: 'USA', city: 'Washington'}*/Mother.prototype.no = 9527;/* Rewrite the prototype of the prototype and dynamically react to the instance. Just as your mother has become a new trend, the neighbors say that you are really a trendy grandma* Note that we are rewriting Mother.prototype here, p1p2 will change, but the above p3 has nothing to do with Mother, and it will not affect him. * p1: 'Jack',['Hangzhou','Guangzhou']; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai'],9527* p2: 'Mark'; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai'],9527* p3: 'Obama'; __proto__: 28 {country: 'USA', city: 'Washington'}*/Mother.prototype = { car: 2, hobby: ['run','walk']};var p4 = new Person('Tony');/* Rewrite the prototype of the prototype! At this time, Mother's prototype has completely become a new object! * Since Person and Mother have been disconnected from above, the change of Mother will no longer affect Person. * p4:'Tony';__proto__: 28 {country: 'USA', city: 'Washington'}*/Person.prototype = new Mother(); //Bind var again p5 = new Person('Luffy');//If you need to apply these changes at this time, you must re-bound Person's prototype to mother// p5:'Luffy';__proto__: 2, ['run','walk']p1.__proto__.__proto__.__proto__.__proto__ //null, do you think the end point of the prototype chain is not null? Mother.__proto__.__proto__.__proto__ //null, do you think the end point of the prototype chain is not null?You can basically understand after reading it?
Now let’s talk about the difference between p1.age = 20, p1.home = ['Hangzhou', 'Guangzhou'] and p1.home[0] = 'Shenzhen'. p1.home[0] = 'Shenzhen'; To sum up, it is a form such as p1.object.method, p1.object.property.
p1.age = 20; p1.home = ['Hangzhou', 'Guangzhou']; These two sentences are easy to understand. Forget the prototype first and think about how we add attributes to an ordinary object:
var obj = new Object();obj.name='xxx'; obj.num = [100, 200];
Do you understand this way? It's the same.
Then why doesn't p1.home[0] = 'Shenzhen' create a home array property under p1 and then set its first position to 'Shenzhen'? Let’s forget this first, think about the obj object above. If it is written like this: var obj.name = 'xxx', obj.num = [100, 200], can you get the result you want? Obviously, you won’t get anything except for an error. Because obj has not been defined yet, how can you add something to it? Similarly, the home in p1.home[0] is not defined under p1, so it is impossible to directly define home[0]. If you want to create a home array under p1, of course it is written like this:
p1.home = []; p1.home[0] = 'Shenzhen';
Isn’t this the most commonly used method?
The reason why p1.home[0] = 'Shenzhen' does not directly report an error is because there is a search mechanism in the prototype chain. When we enter p1.object, the search mechanism of the prototype chain is to search for the corresponding value in the instance first. If it cannot be found, it will be searched in the prototype. If it cannot be found, it will search in the previous level of the prototype chain... It will reach the end of the prototype chain, that is, if it has not been found yet, it will return an undefined. When we enter p1.home[0], the same search mechanism is also true. First search p1 to see if there are any attributes and methods named home, and then search upward step by step. Finally we found it in Mother's prototype, so modifying it is equivalent to modifying Mother's prototype.
In summary: p1.home[0] = 'Shenzhen' is equivalent to Mother.prototype.home[0] = 'Shenzhen'.
From the above analysis, we can see that the main problem of prototype chain inheritance lies in the sharing of attributes. Many times we only want to share methods but not attributes. Ideally, each instance should have independent attributes. Therefore, there are two ways to improve prototype inheritance:
1) Combination inheritance
function Mother (age) {this.age = age;this.hobby = ['running','football']}Mother.prototype.showAge = function () {console.log(this.age); };function Person (name, age) { Mother.call(this, age); //Second execution this.name = name; }Person.prototype = new Mother(); //First execution Person.prototype.constructor = Person;Person.prototype.showName = function () {console.log(this.name);}var p1 = new Person('Jack', 20); p1.hobby.push('basketball'); //p1:'Jack'; __proto__:20,['running','football']var p2 = new Person('Mark', 18); //p2:'Mark'; __proto__:18,['running','football']The result is purple:
When the first execution is performed here, you get Person.prototype.age = undefined, Person.prototype.hobby = ['running','football']. The second execution is that var p1 = new Person('Jack', 20) and you get p1.age =20, p1.hobby = ['running','football']. After pushing, it becomes p1.hobby = ['running','football', 'basketball']. In fact, it is relatively simple to understand the changes of this. You can get this result by simply replacing this. If you feel that it is a bit confusing to understand, try to throw away the concepts in your mind and execute the code from top to bottom as a browser. Will it come out?
By executing the prototype constructor Mother() for the second time, we copied a copy of the prototype's properties in the object instance, so that we can separate and separate from the prototype properties. If you are careful, you will find that the first time we called Mother(), it seems that there is no use. How can we not call it? Yes, there is the following parasitic combination inheritance.
2) Parasitic combination inheritance
function object(o){function F(){}F.prototype = o;return new F();}function inheritPrototype(Person, Mother){var prototype = object(Mother.prototype); prototype.constructor = Person; Person.prototype = prototype; }function Mother (age) {this.age = age; this.hobby = ['running','football']}Mother.prototype.showAge = function () {console.log(this.age); };function Person (name, age) { Mother.call(this, age); this.name = name; }inheritPrototype(Person, Mother); Person.prototype.showName = function () {console.log(this.name);}var p1 = new Person('Jack', 20); p1.hobby.push('basketball');//p1:'Jack'; __proto__:20,['running','football']var p2 = new Person('Mark', 18); //p2:'Mark'; __proto__:18,['running','football']The result is purple:
There are no longer age and hobby attributes in the prototype, there are only two methods, which are exactly the result we want!
The key point is in object(o), where a temporary object is borrowed here to cleverly avoid calling new Mother(), and then return a new object instance with prototype o, thus completing the setting of the prototype chain. It's very confusing, right? That's because we can't set Person.prototype = Mother.prototype directly.
summary
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Having said so much, there is actually only one core: attribute sharing and independent control. When your object instance needs independent attributes, the essence of all practices is to create attributes in the object instance. If you don't think too much, you can directly define the independent attributes you need in Person to overwrite the properties of the prototype. In short, when using prototype inheritance, you should pay special attention to the attributes in the prototype, because they are all existences that affect the whole body.
Below is a simple list of various methods for creating objects in js. The most commonly used method now is the combination mode. Familiar students can skip to the end of the article and like it.
1) Original mode
//1. Original mode, object literal mode var person = { name: 'Jack',age: 18,sayName: function () { alert(this.name); }};//1. Original mode, Object constructor mode var person = new Object(); person.name = 'Jack'; person.age = 18; person.sayName = function () {alert(this.name);};Obviously, when we want to create batches of person1, person2..., we have to type a lot of code every time, and even senior copypasters can't stand it! Then there is a factory model of mass production.
2) Factory model
//2. Factory mode, define a function to create object function createPerson (name, age) {var temp = new Object(); person.name = name;person.age = age;person.sayName = function () {alert(this.name);};return temp; }The factory mode is mass production, and you can enter the man-making mode with a simple call (papapapa...). You can create a bunch of babies by specifying your name and age, and free your hands. However, since it is operated in a factory, you cannot identify what type of the object is, whether it is a human or a dog (instanceof test is Object). In addition, every time you create a human, you have to create an independent temp object, the code is bloated, and the butterfly is elegant.
3) Constructor
//3. Constructor mode, define a constructor function for the object function Person (name, age) {this.name = name;this.age = age;this.sayName = function () {alert(this.name);}; }var p1 = new Person('Jack', 18); //Create a p1 object Person('Jack', 18); //Attribute methods are given to the window object, window.name='Jack', window.sayName() will output JackThe constructor is similar to the constructors of classes in C++ and JAVA, and is easy to understand. In addition, Person can be used as type recognition (instanceof test is Person and Object). However, all instances are still independent, and methods of different instances are actually different functions. Forgot the word function here, just treat sayName as an object and understand it. That is to say, Zhang San's sayName and Li Si's sayName have different existences, but obviously what we expect is to share a sayName to save memory.
4) Prototype mode
//4. Prototype mode, directly define the prototype attribute function Person () {}Person.prototype.name = 'Jack';Person.prototype.age = 18;Person.prototype.sayName = function () { alert(this.name); };//4. Prototype, literal definition method function Person () {}Person.prototype = {name: 'Jack',age: 18,sayName: function () { alert(this.name); }};var p1 = new Person(); //name='Jack'var p2 = new Person(); //name='Jack'What needs to be noted here is the sharing of prototype attributes and methods, that is, all instances only refer to the attribute methods in the prototype, and changes generated in any place will cause changes in other instances.
5) Mixed mode (construction + prototype)
//5. Prototype construct combination mode, function Person (name, age) {this.name = name;this.age = age;}Person.prototype = {hobby: ['running','football'];sayName: function () { alert(this.name); },sayAge: function () { alert(this.age); }};var p1 = new Person('Jack', 20); //p1:'Jack',20; __proto__: ['running','football'],sayName,sayAgevar p2 = new Person('Mark', 18); //p1:'Mark',18;__proto__: ['running','football'], sayName, sayAgeThe approach is to put the property methods that need to be independent into the constructor, and the parts that can be shared are placed into the prototype. This can maximize memory savings while retaining the independence of object instances.