Clarify the relationship between Java and Javascript as Lei Feng tower. Javascript, formerly known as Mocha, was also called LiveScript. It was created by Brendan Eich and is now the chief technology officer of Mozilla.
In 1994, Navigator0.9, the first mature web browser in history, was born in Netscape.
However, Navigator0.9 can only be used for browsing and does not have the ability to interact with visitors. For example, if a user submits a data form and the form is empty, the browser cannot judge it, it can only be submitted directly to the server, and then the null value error is returned, so that users can enter it again, which is obviously inefficient and a waste of resources.
At this time, for Netscape, which is at the forefront of technological innovation, it is necessary to develop a practical client scripting language to deal with these problems, so this task falls into engineer Brendan Eich. In his opinion, it is necessary to make the design complex, as long as some simple operations can be done, such as determining whether the user has entered a form.
In 1994, object-oriented programming (object-oriented programming) was booming. C ++ was the most popular language, and Java version 1.0 was about to be released in the next year, brendan Eich is inevitably affected. He wants to regard all the data types in Javascript as objects, which is very similar to Java. However, he immediately encountered a problem. Do he need to design an inheritance mechanism?
Ii. Inheritance sources and Evolution
1. Use the new Keyword to generate an instance
A simple functional scripting language like Form Verification obviously does not require the "inheritance" mechanism. However, if Javascript contains all objects, there is a way to link all objects. Finally, Brendan Eich designed "inheritance ". However, he didn't introduce the concept of "class" because Javascript is a complete object-oriented programming language once "class" is introduced,
This seems a little too formal, far from the original design, and increases the difficulty of getting started for beginners.
Refer to C ++ and Java to use the new command to generate an instance:
Write C ++ as follows:
ClassName * object = new ClassName (param );
Write Java as follows:
Foo foo = new Foo ();
You can also introduce the new command to Javascript to generate an instance object from the prototype object. However, if Javascript does not contain a "class", how does one represent a prototype object?
Constructor is called when C ++ and Java use the new command ). Brendan Eich simplifies the design. In Javascript, the new command is followed by a constructor instead of a class.
For example, there is a prototype called WD constructor that represents a web-developper object.
Function WD (skill ){
This. skill = skill;
}
Using the new keyword for this constructor generates an instance of the front-end development object.
Var WD1 = new WD ('html ');
Console. log (WD1.skill); // html
The this keyword in the constructor actually represents the newly created instance object.
2. Defects of new objects
Using the new keyword, instance objects generated using constructors cannot share attributes and methods.
For example, in the WD object constructor, set a common property skill for an instance object.
Function WD (skill ){
This. skill = skill;
This. sex = 'male ';
}
Then, two instance objects are generated:
Var WD1 = new WD ('html ');
Var WD2 = new WD ('css ');
The skill attributes of these two objects are independent. Modifying one of them does not affect the other.
WD1.skill = 'javascript ';
Console. log (WD2.skill); // "css", not affected by WD1
Each instance object has its own copy of attributes and methods. This is not only unable to achieve data sharing, but also a great waste of resources.
3. Introduce prototype attributes
To share attributes and methods, Brendan Eich decided to set a prototype attribute for the constructor.
This attribute contains an object (hereinafter referred to as "prototype object"). All the attributes and methods to be shared by instance objects are placed in this object. Those attributes and methods that do not need to be shared are not included in this object, put it in the constructor.
Once an instance object is created, the attributes and methods of the prototype object are automatically referenced. That is to say, the attributes and methods of the Instance Object are divided into two types: local and referenced.
Taking the WD constructor as an example, we can rewrite it with the prototype attribute:
Function WD (skill ){
This. skill = skill;
}
WD. prototype = {sex: 'male '};
Var WD1 = new WD ('html ');
Var WD2 = new WD ('css ');
Console. log (WD1.sex); // male
Console. log (WD2.sex); // male
Now, the sex property is stored in the prototype object, which is shared by two instance objects. If the prototype object is modified, the two instance objects are affected at the same time.
WD. prototype. sex = 'female ';
Console. log (WD1.sex); // female
Console. log (WD2.sex); // female
Because all instance objects share the same prototype object, prototype objects seem to be prototype objects, while instance objects seem to "inherit" prototype objects. This is the design idea of the Javascript Inheritance Mechanism.
Iii. How to Implement inheritance of Constructors
Now there is a "MED" object constructor (MED: Marketing Experience Design, Marketing Experience Design)
Function MED (){
This. aim = "marketing experience design ";
}
Still the constructor of the "WD" object,
Function WD (skill, sex ){
This. skill = skill;
This. sex = sex;
}
How can we make "WD" inherit "MED?
1. apply binding constructor implementation
The simplest method is to use the call or apply method to bind the constructor of the parent object to the sub-object, that is, to add a row to the sub-object constructor:
Function WD (skill, sex ){
MED. apply (this, arguments );
This. skill = skill;
This. sex = sex;
}
Var WD1 = new WD ("Html", "male ");
Console. log (WD1.aim); // "marketing experience design"
2. prototype mode implementation
We usually use the prototype attribute. If the prototype object of "WD" points to a MED instance, all "WD" instances can inherit the MED.
WD. prototype = new MED (); // we direct the WD prototype object to a MED instance.
WD. prototype. constructor = WD;
Var WD1 = new WD ("Html", "male ");
Console. log (WD1.aim); // marketing experience design
This sentence
WD. prototype = new MED ();
It is equivalent to completely deleting the original value of the prototype object, and then assigning a new value. So what does the second line mean?
WD. prototype. constructor = WD;
Originally, any prototype object has a constructor attribute pointing to its constructor. That is to say, the constructor attribute of the object WD. prototype points to WD.
We have deleted the original value of this prototype object in the previous step. Therefore, the new prototype object does not have the constructor attribute. We need to manually add it. Otherwise, the subsequent "inheritance chain" will cause problems. This is what the second line means.
Note that this is an important point. It is necessary to follow this point in programming. In the following example, if prototype object is replaced,
O. prototype = {};
Then, the next step is to add the constructor attribute to the new prototype object and direct the attribute back to the original constructor.
O. prototype. constructor = o;
3. Directly inherit the implementation from prototype
Because the attributes of the MED object can be directly written to the MED. prototype. Therefore, we can also let WD () skip MED () and inherit MED. prototype directly.
Now, we will first rewrite the MED object:
Function MED (){}
MED. prototype. skill = "MED ";
Next, point the WD prototype object to the MED prototype object, and the inheritance is completed.
WD. prototype = MED. prototype;
WD. prototype. constructor = WD;
Var WD1 = new WD ("Html", "male ");
Console. log (WD1.skill); // MED
Compared with the previous method, this method has the advantage of high efficiency (no execution or creation of MED instances) and saves memory. The disadvantage is that WD. prototype And MED. prototype point to the same object. Any modifications to WD. prototype will be reflected in MED. prototype.
Therefore, the above Code is actually problematic. See the second line.
WD. prototype. constructor = WD;
This statement actually removes the constructor attribute of the MED. prototype object!
Console. log (MED. prototype. constructor); // WD
4. Using an empty object as an intermediary
Because prototype is inherited directly, an empty object can be used as an intermediary.
Var F = function (){};
F. prototype = MED. prototype;
WD. prototype = new F ();
WD. prototype. constructor = WD;
F is a null object, so it hardly occupies memory. In this case, modifying the prototype object of WD does not affect the prototype object of MED.
Console. log (MED. prototype. constructor); // MED
5. encapsulate functions in prototype mode
We encapsulate the above method into a function for ease of use.
Function extend (Child, Parent ){
Var F = function (){};
F. prototype = Parent. prototype;
Child. prototype = new F ();
Child. prototype. constructor = Child;
}
The method is as follows:
Extend (WD, MED );
Var WD1 = new WD ("Html", "male ");
Console. log (WD1.aim); // marketing experience design
This extend function is how the YUI library implements inheritance.
6. Copy inheritance implementation
The prototype method is used to implement inheritance. In fact, since the Sub-object will have the attributes and methods of the parent object, we can directly use the "copy" method to achieve the effect. Simply put, if we copy all the attributes and methods of the parent object into the sub-object, can we still implement inheritance?
First, put all the unchanged attributes of MED on its prototype object.
Function MED (){}
MED. prototype. aim = "marketing experience design ";
Then, write a function to copy the attributes.
Function extendCopy (Child, Parent ){
Var p = Parent. prototype;
Var c = Child. prototype;
For (var I in p ){
C [I] = p [I];
}
}
This function is used to copy the attributes of the prototype object of the parent object to the prototype object of the Child object.
Write as follows:
ExtendCopy (WD, MED );
Var WD1 = new WD ("Html", "male ");
Console. log (WD1.aim); // marketing experience design
Iv. How to Implement inheritance of non-Constructor
For example, there is now an object called "MED"-marketing experience design.
Var MED = {
Aim: 'marketing experience Design'
}
Another object is called "front-end development ".
Var WD = {
Skill: 'html'
}
How can we let "front-end development" inherit "marketing experience design", that is, how can I generate a "marketing experience design front-end development" object?
Note that these two objects are common objects. They are not constructor and cannot be used to implement "inheritance ".
1. object () method
Douglas Crockford, inventor of Json format, proposed an object () function to achieve this.
Function object (o ){
Function F (){}
F. prototype = o;
Return new F ();
}
This object () function is actually only used to direct the prototype attribute of the Child object to the parent object so that the child object can be connected with the parent object.
When used, the first step is to generate sub-Objects Based on the parent object:
Var WD = object (MED );
Then, add the attributes of the sub-object:
WD. skill = 'html ';
At this time, the sub-object has inherited the attributes of the parent object.
Console. log (WD. aim); // marketing experience design
2. Shallow copy
In addition to the prototype chain, there is another idea: copying all attributes of the parent object to the sub-object can also realize inheritance.
The following function is used for copying:
Function LightCopy (p ){
Var c = {};
For (var I in p ){
C [I] = p [I];
}
// C. uber = p;
Return c;
}
Write as follows:
Var WD = LightCopy (MED );
WD. aim = 'frontend developer ';
However, there is a problem with such a copy. That is, if the attribute of the parent object is equal to an array or another object, in fact, the sub-object only obtains a memory address rather than a real copy, so there is a possibility that the parent object will be tampered.
See, now add a "skill" attribute to MED. Its value is an array.
MED. skills = [''html '', 'css ', 'javascript'];
Through the LightCopy () function, WD inherits the MED.
Var WD = LightCopy (MED );
Then, we add an attribute for the "skill" of WD:
WD. skills. push ('teamwork ');
What happened? MED's "skills" have also been tampered!
Console. log (WD. skills); // 'html ', 'javascript', 'css ', 'teamwork'
Console. log (MED. skills); // 'html ', 'javascript', 'css ', 'teamwork'
Therefore, LightCopy () is just a copy of the basic data type. We call this copy a "shortest copy ". This is an early Method for jQuery to implement inheritance.
3. Deep copy
The so-called "Deep copy" means to copy arrays and objects in the true sense. Its implementation is not difficult, as long as it recursively calls the "Shallow copy.
Function deepCopy (p, c ){
Var c = c || {};
For (var I in p ){
If (typeof p [I] === 'object '){
C [I] = (p [I]. constructor = Array )? []: {};
DeepCopy (p [I], c [I]);
} Else {
C [I] = p [I];
}
}
Return c;
}
Write as follows:
Var WD = deepCopy (MED );
Now, add an attribute to the parent object and the value is an array. Then, modify this attribute on the sub-object:
MED. skills = [''html '', 'css ', 'javascript'];
WD. skills. push ('teamwork ');
In this case, the parent object will not be affected.
Console. log (WD. skills); // 'html ', 'css', 'javascript ', 'teamwork'
Console. log (MED. skills); // 'html ', 'css', 'javascript'
Currently, the jQuery library uses this inheritance method.