Recently, I was looking at the JavaScript advanced programming design (the third edition). The object-oriented chapter has more than 20 pages, and I went back and forth for three or five times. The results of each reading were different. The first time I went over it, I was confused, as a result, when I went to bed at night, I found a lot of problems and I couldn't understand anything. I looked at it again and found it was like this. After a few days, I found that my handwriting was still based on my memory, so next time, next time...
It is very unreliable to identify things by memory alone, with a long blank head. In particular, there are a lot of technical ideas and principles that can only be ignored. Even if you think clearly at the time, you will forget it after a long time. In addition, there are some things on the Internet, which can only be said to provide a convenient way to view them. After all, most of them are personal summaries, and some concepts are hard to be clearly explained, in addition, when two people talk about the same thing, generally the steps and chapters are different. This makes it easy to form cross-memory, and the more cross-memory, the more chaotic. It's better to look at things with a skeptical attitude. Let's give it a try and find out what it looks like. High-quality and assured books or official stuff are good sources.
You can see it clearly, and your head is clear. record it and make a memo. Conceptual things are written in books, reducing future misleading. The example is hand-written and verified, and a picture is drawn for later understanding.
I. Encapsulation
Object definition: The ECMA-262 defines an object as a collection of unordered attributes, where attributes can include basic values, objects, or functions ".
Create Object: each Object is created based on a reference type. The reference type can be native (Object, Array, Date, RegExp, Function, Boolean, Number, String ), it can also be a custom type.
1. constructor Mode
The Code is as follows:
Function Person (name, age ){
This. name = name;
This. age = age;
This. sayName = function (){
Alert (this. name );
}
}
The above constructor can use the new operator to create an object instance.
Var zhangsan = new Person ('hangsan', 20 );
Var lisi = new Person ('lisi', 20 );
Zhangsan. sayName (); // zhangsan
Lisi. sayName (); // lisi
Four steps to create an object using new
1. Create a new Object. [var o = new Object ();]
2. Assign the scope of the constructor to the new object (so this points to this new object); [Person. apply (o)] [the original this of Person points to window]
3. Execute the code in the constructor (add attributes for the new object );
4. Return the new object.
Steps to restore new by code:
The Code is as follows:
Function createPerson (P ){
Var o = new Object ();
Var args = Array. prototype. slice. call (arguments, 1 );
O. _ proto _ = P. prototype;
P. prototype. constructor = P;
P. apply (o, args );
}
Test the new instance creation method.
Var wangwu = createPerson (Person, 'wangw', 20 );
Wangwu. sayName (); // wangwu
2. Prototype
Prototype Object Concept: whenever a new function is created, a prototype attribute is created for the function according to a set of specific rules. This attribute points to the prototype object of the function. By default, all prototype objects automatically obtain a constructor attribute, which contains a pointer to the function of the prototype attribute. With this constructor, you can continue to add other attributes and methods for the prototype object. After a custom constructor is created, its prototype Object only obtains the constructor attribute by default. Other methods are inherited from the Object. After a constructor is called to create a new instance, the instance contains a pointer (internal attribute) pointing to the constructor's prototype object. The pointer to ECMA-262 version 5th is called [Prototype]. There is no standard way to access [[Prototype] in the script, but Firefox, Safari, and Chrome support an attribute _ proto __on each object. In other implementations, this attribute is completely invisible to the script. However, it should be clear that this connection exists between the sample and the prototype object of the constructor, rather than between the instance and the constructor.
This section provides an overview of the relationships between constructors, prototypes, and examples.
The Code is as follows:
Function Person (name, age ){
This. name = name;
This. age = age;
}
Person. prototype. country = 'China ';
Person. prototype. sayCountry = function (){
Alert (this. country );
}
Var zhangsan = new Person ('hangsan', 20 );
Var lisi = new Person ('lisi', 20 );
Zhangsan. sayCountry (); // chinese
Lisi. sayCountry (); // chinese
Alert (zhangsan. sayCountry = lisi. sayCountry); // true
Note: The prototype object of the constructor is used to share the attributes and methods contained by Multiple object instances. But this is also prone to problems. If the prototype object contains a reference type, the reference type should be stored as a pointer, so the value will be shared. As follows:
The Code is as follows:
Person. prototype. friends = ['wangwu']; // Add an array type for Person
Zhangsan. friends. push ('zhaoliu'); // The modification may affect the performance of Lisi.
Alert (zhangsan. friends); // wangwu, zhaoliu
Alert (lisi. friends); // wangwu, zhaoliu Li Si also has one more
3. Combined use of the constructor mode and prototype mode
This mode is the most widely used and the most consistent way to create a custom type. The constructor mode is used to define instance attributes, while the prototype mode is used to define methods and shared attributes. In this way, each instance has its own copy of the Instance attributes, and there is a shared reference to the method, saving the maximum memory.
The prototype is transformed as follows:
The Code is as follows:
Function Person (name, age ){
This. name = name;
This. age = age;
This. friends = ['wangwu'];
}
Person. prototype. country = 'China ';
Person. prototype. sayCountry = function (){
Alert (this. country );
}
Var zhangsan = new Person ('hangsan', 20 );
Var lisi = new Person ('lisi', 20 );
Zhangsan. friends. push ('zhaoliu ');
Alert (zhangsan. friends); // wangwu, zhaoliu
Alert (lisi. friends); // wangwu
Ii. Inheritance
Inherit Basic Concepts
ECMAScript mainly relies on the prototype chain for inheritance (or copy attributes for inheritance ).
The basic idea of prototype chain is to use prototype to inherit the attributes and methods of another reference type. Constructor, prototype, and example: Each constructor has a prototype object that contains a pointer to the constructor, the instance contains an internal pointer pointing to the prototype. Therefore, by making the prototype object equal to another type of instance, the prototype object will contain a pointer to another prototype, correspondingly, another prototype also contains this pointer to another constructor. If another prototype is another type of instance, the above relationship is still established, so that the progressive layers constitute the chain between the instance and the prototype. This is the basic concept of prototype chain.
Reading is not easy to understand. Verify the instance directly.
1. prototype chain inheritance
The Code is as follows:
Function Parent (){
This. pname = 'parent ';
}
Parent. prototype. getParentName = function (){
Return this. pname;
}
Function Child (){
This. cname = 'child ';
}
// Configure the sub-constructor prototype as an instance of the parent constructor to form a prototype chain so that Child has the getParentName method.
Child. prototype = new Parent ();
Child. prototype. getChildName = function (){
Return this. cname;
}
Var c = new Child ();
Alert (c. getParentName (); // parent
Illustration:
The problem of prototype chain. If the parent class contains the reference type. prototype = new Parent () will bring the reference type in the Parent class to the prototype of the subclass, and the prototype property of the reference type value will be shared by all instances. The problem is returned to [1, 2.
2. Combined inheritance-the most common inheritance Method
Combination inheritance is a combination of prototype chains and borrow Constructors (apply, call. The idea is to use the prototype chain to inherit the prototype attributes and methods, and use constructors to inherit the instance attributes. In this way, you can define methods in the prototype to achieve function reuse, and ensure that each instance has its own attributes.
The Code is as follows:
Function Parent (name ){
This. name = name;
This. colors = ['red', 'yellow'];
}
Parent. prototype. sayName = function (){
Alert (this. name );
}
Function Child (name, age ){
Parent. call (this, name); // The second call to Parent ()
This. age = age;
}
Child. prototype = new Parent (); // The first time you call Parent (), the attributes of the Parent class will
Child. prototype. sayAge = function (){
Alert (this. age );
}
Var c1 = new Child ('hangsan', 20 );
Var c2 = new Child ('lisi', 21 );
C1.colors. push ('Blue ');
Alert (c1.colors); // red, yellow, blue
C1.sayName (); // zhangsan
C1.sayAge (); // 20
Alert (c2.colors); // red, yellow
C2.sayName (); // lisi
C2.sayAge (); // 21
The problem with combination inheritance is that two super-Type constructor calls each time: the first is when the sub-type prototype is created, and the other is inside the sub-Type constructor. This will overwrite the attributes. The child Type constructor contains the attributes of the parent class, and the prototype object of the Child class also contains the attributes of the parent class.
3. Parasitic combination inheritance-the perfect inheritance mode
The so-called parasitic combination Inheritance refers to inheriting attributes by borrowing constructor and inheriting methods through the mixed form of prototype chains. The basic idea behind it is that we do not need to call a super-Type constructor to specify the prototype of the subclass. What we need is a copy of the super-type prototype.
The Code is as follows:
Function extend (child, parent ){
Var F = function () {}; // defines an empty constructor.
F. prototype = parent. prototype; // the prototype of the parent class.
Child. prototype = new F (); // the prototype of the subclass is set to F to form a prototype chain.
Child. prototype. constructor = child; // specify the subclass constructor pointer again.
}
Function Parent (name ){
This. name = name;
This. colors = ['red', 'yellow'];
}
Parent. prototype. sayName = function (){
Alert (this. name );
}
Function Child (name, age ){
Parent. call (this, name );
This. age = age;
}
Extend (Child, Parent); // implement inheritance
Child. prototype. sayAge = function (){
Alert (this. age );
}
Var c1 = new Child ('hangsan', 20 );
Var c2 = new Child ('lisi', 21 );
C1.colors. push ('Blue ');
Alert (c1.colors); // red, yellow, blue
C1.sayName (); // zhangsan
C1.sayAge (); // 20
Alert (c2.colors); // red, yellow
C2.sayName (); // lisi
C2.sayAge (); // 21