JS inheritance is used to do what:
JS does not really like other object-oriented language as the concept of inheritance, JS inside the said inheritance refers to the simulation of inheritance.
Specific JS inheritance is what to do, just start to do the front end when I was used for the interview (the earliest write small effect when basic use, why to see, because the interviewer is very fond of asking this question AH), so take a look at the approximate, interview can say a general, in this question is an interview party. Later followed slowly actually although the concept is not very clear also used some.
What is really used to do, is mainly used to reuse the code we have written before. For example, write a function, an object, or with someone else to write something, we have to add something to their own, can not change the other people's things, direct inheritance to use a bit better, this is the true use of inheritance.
JS inheritance how to achieve:
Before the code, first talk about the idea. In fact, the inheritance is to find ways to other objects (JS inside all objects ha) attributes or methods to get to our own objects, so that our own object can be used. This will also achieve the purpose of reuse.
Objective to understand, the following is the means of implementation.
According to the characteristics of JS, implementation is nothing but the following methods of one or combination of the use.
1, the constructor, JS seems to have no strict definition of the constructor, but you can use new to create an object. Constructors are also said to be strict object-oriented language implementation of the method, then JS certainly can be simulated, so the people who learned the OOP language will first think of this.
2, the use of functional prototypes, the use of prototype chain to link two objects, because the JS prototype chain is relatively unique so think of this is also very easy.
There are also several types of prototypes, which are the prototypes of the inherited objects, the prototypes of the inherited objects or instances of the inherited objects, or directly successors. These kinds of prototypes as inherited objects have different inheritance effects.
3, replication properties and methods, the inherited objects of the properties or methods of copying all the clones to become our own objects of the attributes and methods is good ah, we can be extremely smooth use. Of course, this is also divided into two types of replication and deep replication.
4, using the call and apply these two methods, these two methods are more magical, can change the function of the execution of the context (this), so the use of these two methods can also implement the inherited objects of the inheritance reuse.
The total to JS to achieve the path of inheritance is probably these, the ever-changing implementation methods are based on the combination of several methods to upgrade the perfect, for the majority of the hair to be combined use, of course, because the effect of using a single method is not ideal AH. Of course, according to the actual requirements of their own projects to choose which way to use, as long as meet their own needs and did not say which method must be used to achieve. Like to say from Beijing to Shijiazhuang, the fastest of course is the plane. But if you are far from the airport, count on the airport, go to the city from the airport, the overall calculation is not as fast as high-speed rail, then you can do high-speed rail. Another example of their own car can drive, want to challenge can also ride a bicycle, this according to their own actual situation to choose.
Code implementation, the following combined with the code to say several of the above implementation methods, some are picked from other places, add a little comment on what.
One, constructor implementation (borrow constructor):
function Super (ARG) {
THIS.ARR1 = "I ' m Super" +ARG;
This.show = function () {
alert (THIS.ARR1);
}
}
Super.prototype.say = function () {
alert (THIS.ARR1);
}
function Suber (ARG) {
Super.apply (this, arguments); Running super in the context of Suber
}
var sub =new suber ("Suber");
var sub2 = new Suber ("Suber1");
Console.log (SUB.ARR1); I ' M Super Suber
Console.log (sub.show); function () {alert (THIS.ARR1);}
Console.log (Sub.say); Undefined
Console.log (sub.show = = = Sub2.show); False
Alas, found Sub.say is undefined, which means that it has not been inherited over Ah, the bottom two objects sub,sub2 show is not equal, that two functions point to two different objects, that is, copied two out.
So this method implements inheritance. The properties and methods on the prototype object are not inherited, and the properties and methods on super are copied separately for each new object.
So it's not a good idea to use this method alone, because the methods on the prototype are not inherited. So the great gods thought of archetypal inheritance.
second, prototype inheritance:
function Super (ARG) {
THIS.ARR1 = "I ' m Super" +ARG;
This.show = function () {
alert (THIS.ARR1);
}
}
Super.prototype.say = function () {
alert (THIS.ARR1);
}
function Suber (ARG) {}
Suber.prototype = new Super ();
var sub = new Suber ("Suber1");
var sub2 = new Suber ("Suber2");
Console.log (SUB.ARR1); I ' m super undefined
Console.log (sub.show); function () {alert (THIS.ARR1);}
Console.log (Sub.say); function () {alert (THIS.ARR1);}
Console.log (sub.show = = = Sub2.show); True
Console.log (Sub.say = = = Sub2.say); True
This is arr1 inherited, but the parameter is not added, is undefined, so this method subclass declaration When this parameter passed in the payment class inherited this attribute cannot receive. Everything else is normal. Show and say all inherited it. But one thing to note is that say is inherited through a super prototype object, and show is the property of the instance when you create the new Super object instance.
Then how to achieve the parameters of the transmission can be the prototype inside the East inheritance, of course, the top two methods of combination of good Ah, so the predecessors also invented the following method
Iii. Combining Inheritance (borrowing constructors and setting prototypes):
function Super (ARG) {
THIS.ARR1 = "I ' m Super" +ARG;
This.show = function () {
alert (THIS.ARR1);
}
}
Super.prototype.say = function () {
alert (THIS.ARR1);
}
function Suber (ARG) {
Super.apply (this, arguments);
}
Suber.prototype = new Super ();
var sub = new Suber ("Suber1");
var sub2 = new Suber ("Suber2");
Console.log (SUB.ARR1); I ' M Super Suber1
Console.log (sub.show); function () {alert (THIS.ARR1);}
Console.log (Sub.say); function () {alert (THIS.ARR1);}
Console.log (sub.show = = = Sub2.show); False
Console.log (Sub.say = = = Sub2.say); True
This time it's almost perfect, but you can find sub.show. And sub2.show is not equal Ah, this is why, because apply this place makes show become Suber's own attributes, then the Suber prototype of the show (super as the Suber prototype object of the example object) to cover, so it becomes every copy one, of course, this There is no way to avoid it. In order not to produce this redundant, the common function can be put into the prototype object more.
Because the call inside the Suber, and the call to the Suber prototype object, resulted in super being called two times, each time the new Suber object called Two super, two times it would produce two instance objects, which would consume the extra resources.
So the predecessors to solve this problem opened the brain hole, developed the following method.
four, parasitic combination inheritance:
The main difference between the method and the method is to assign the parent prototype to the subclass prototype instead of the parent class example, see Example
function Super (ARG) {
THIS.ARR1 = "I ' m Super" +ARG;
}
Super.prototype.show = function () {//This method is placed on the prototype object.
alert (THIS.ARR1);
}
Super.prototype.say = function () {
alert (THIS.ARR1);
}
function Suber (ARG) {
Super.apply (this, arguments);
}
The role of the/*inherit function, a new NULL function is used to cut off the direct connection between the prototype object of the parent object and the subclass prototype object, but to implement inheritance through this empty constructed instance object, which avoids changing the properties or methods of the subclass prototype and affects the properties or methods of the parent prototype object. */
function inherit (obj) {
function F () {}
F.prototype = obj;
return new F ();
}
Suber.prototype = Inherit (Super.prototype);
var sub = new Suber ("Suber1");
var sub2 = new Suber ("Suber2");
Console.log (SUB.ARR1); I ' M Super Suber1
Console.log (sub.show); function () {alert (THIS.ARR1);}
Console.log (Sub.say); function () {alert (THIS.ARR1);}
Console.log (sub.show = = = Sub2.show); True
Console.log (Sub.say = = = Sub2.say); True
OK, so the drawbacks of the three method to kill, this can be perfect use of it.
v. Replication attribute Implementation
Copy we can write a copy function to achieve.
function Extend (super,suber) {
Suber = Suber | | {};
for (var i in Super) {
if (Super.hasownproperty (i)) {
Suber[i] = Super[i];
}
}
return suber;
}
var parent = {
Name: "Dad",
num:[1,2,3],
Say:function () {alert ("Dad");}
}
var child = {
Age:5,
Sex: "Boy"
};
Child = Extend (parent, child);
The following tests
Console.log (child); /*{
Age:5,
Sex: "Boy",
Name: "Dad",
num:[1,2,3],
Say:function () {alert ("Dad");}
}*/
Console.log (Child.say = = = Parent.say); True
Console.log (Child.num = = = Parent.num); True
Replication succeeded, then the child succeeded in inheriting some of the attributes of parent, but the next two tests found that they were equal, indicating that they shared the same array, the same function, the function, but the array has a problem, if a chiild changes the array, The array of several inherited objects has also changed, which is not a force.
Why is this happening? JS inside the object is stored is a pointer, and then this pointer to this value, we are copying in this is actually pointing to the value of the object's pointer, so both the inherited object and the inherited object all point to the same object, and then see how to use deep replication to solve this problem.
Deep Copy Object properties:
function Extenddeep (Super, suber) {
var tostr = Object.prototype.toString, Astr = "[Object Array]";
Suber = Suber | | {};
for (var i in Super) {
if (Super.hasownproperty (i)) {
if (typeof super[i] = = = "Object") {
Suber[i] = (Tostr.call (super[i]) = = astr)? [] : {};
Extenddeep (Super[i],suber[i]);
}else {
Suber[i] = Super[i];
}
}
}
return suber;
}
var parent = {
Name: "Papa",
num:[1,2,3],
Say:function () {alert ("I ' m father of my son!");}
}
var child = {
Name: "Jone",
Sex: "Boy",
}
var kid = extenddeep (parent, child);
Console.log (Kid); {name: ' Papa '
NUM:ARRAY[3]
Say: ()
Sex: "Boy"
// }
Console.log (Kid.say = = = Parent.say); True
Console.log (Kid.num = = = Parent.num); False
Console.log (Kid.name); Papa
Well, the depth of the copy is complete, but there is a problem with the discovery of the wood, name is parent, that is, if the inherited object has a property name that is the same as the inherited object, it will be replaced if it is not processed. Then we can do the processing, first declare a property, save the things in the parent, the rest of course is the child of their own things, and finally the attribute to the child object can be.
use call and apply these two methods (borrow method).
This is the purpose of reusing other objects by call and apply.
var one = {
Name: "Object",
Say:function (greet) {
Return greet + ', ' + this.name;
}
}
var tow = {
Name: "Two"
}
One.say.call (Tow, "HI"); Hi, two.
This is borrowed, OK, class.
Well, well, actually there's something else to look at. You can use a method that is not "with a table" to assign value to someone and then continue with something that hasn't happened. So we usually use the borrowed time to pay attention to the context, the following look at the error-prone areas.
The context changes when the assignment is given to a variable
var say = One.say;
Console.log (Say (' HoHo ')); "HoHo, undefined."
Also changes as a callback function
var yetother = {
Name: "Yetother obj",
Method:function (callback) {
Return callback ("Hola");
}
}
Console.log (Yetother.method (One.say)); "Hola,"
What is the meaning of God's horse, that is this.name is undefined, When the One.say assignment to say is, in fact, say stores a pointer to a function object, say the variable is clearly a property of the global variable, then the actual context becomes windows when it runs, and of course the name becomes undefined at this time. The callback is the same, and return is the result of the function running. If we set up windows.name= "Windows" in advance, the result becomes "HoHo, Windows" and "Hola, Windows."
function bind (o, m) {
return function () {
Return m.apply (O, [].slice.call (arguments));
}
}
var Othersay = bind (Yetother, One.say);
Othersay ("Hola"); "Hola, Yetother obj."
By using apply to change the context in which the method executes, we construct a function to implement a change in the context through the use of method calls, so that the context is not the context that we expect it to be.
This paragraph is copied directly.
ECMAScript 5 adds a bind () method to Function.prototype to make it easy to use apply () and call ().
if (typeof Function.prototype.bind = = ' undefined ') {
Function.prototype.bind = function (Thisarg) {
var fn = this,
Slice = Array.prototype.slice,
args = Slice.call (arguments, 1);
return function () {
Return fn.apply (Thisarg, Args.concat (slice.call (arguments)));
};
};
}
var twosay2 = One.say.bind (two);
Console.log (Twosay2 (' Bonjour ')); "Bonjour, another object"
var twosay3 = One.say.bind (two, ' enchanté ');
Console.log (Twosay3 ()); "Enchanté, another object"
Introduction finished, should say their doubts, when the Replication property method encountered by the inherited object inside the method, how to copy out, now is directly shared, because after all, the method generally will not change often. Ask for answers?
The following is reproduced in the jquery extend method, as if there is no special processing function of this block, inherited two functions are also shared.
$.extend Source
Jquery.extend = JQuery.fn.extend = function () {
var options, name, SRC, copy, Copyisarray, clone,
target = Arguments[0] | | {},
i = 1,
Length = Arguments.length,
Deep = false;
Handle a deep copy situation
If the first argument is a Boolean type
Fix the parameter and use the second parameter as target
if (typeof target = = "Boolean") {
Deep = target;
Skip the Boolean and the target
target = arguments[I] | | {};
I++ is for the follow-up i = = length judgment
i++;
}
Handle case as Target is a string or something (possible in deep copy)
If the target is neither an object nor a method (for example, extending property methods and properties to the base type does not complain but is useless), fix target as a JS object
if (typeof target!== "Object" &&!jquery.isfunction (target)) {
target = {};
}
Extend JQuery itself if only one argument is passed
If there is only one argument, the Fixup object is a jquery function or a jquery object
if (i = = length) {
target = this;
Fix target location, followed by objects to be added to target
i--;
}
for (; i < length; i++) {
Only deal with non-null/undefined values
if (options = arguments[i])!= null) {
Extend the Base Object
for (name in options) {
src = target[name];
copy = options[name];
Prevent never-ending Loop
If target and copy are the same object, skip over to prevent their properties from referencing the circular references that are caused by their own objects, so that the GC cannot reclaim
if (target = = copy) {
Continue;
}
recurse if we ' re merging plain objects or arrays
If Deep is true, and the copy you want to add to target is an array of objects
if (deep && copy && jquery.isplainobject (copy) | | (Copyisarray = Jquery.isarray (copy)) ) {
if (Copyisarray) {
Copyisarray = false;
clone = src && jquery.isarray (src)? SRC: [];
} else {
clone = src && jquery.isplainobject (src)? src: {};
}
Never move original objects, clone them
Very clever, with a recursive, to implement the deep cloning of reference objects, recursive return condition is attribute stone basic type, basic types are deep cloning
target[name] = Jquery.extend (deep, clone, copy);
Don ' t bring in undefined values
else if (copy!== undefined) {
Shallow clones
target[name] = copy;
}
}
}
}
Return the Modified Object
return target;
};