Revisit the JavaScript inheritance mechanism

Source: Internet
Author: User
Tags jquery library

Original: http://mozilla.com.cn/post/21667/

===========================

Last time, the team had several times to share the force, here to the West wind master to share the inheritance mechanism a little to tidy up a bit, appropriate add some colloquial description, stay for the record.

One, tell a story.

Clarified earlier, Java and JavaScript are the relations between Lei Feng and Leifeng Tower. JavaScript formerly known as Mocha, was also called LiveScript, the creator is Brendan Eich, is currently the chief technical Officer of Mozilla company.

In 1994, the first more mature web browser in history,--navigator0.9, was born in Netscape (Netscape) and was a great sensation. However, Navigator0.9 can only be used to browse, do not have the ability to interact with visitors, for example, the user submits a data form, if the form is empty, the browser is not able to judge, can only be directly submitted to the server side, and then return the error of NULL value, let the user re-fill, so it is obviously inefficient and wasteful resources.

At this point, it became necessary to develop a practical client-side scripting language to handle these problems at the forefront of technological innovation, and the task fell to engineer Brendan Eich. Netscape. He thought, wood necessary design is very complex, as long as can handle some simple operation is enough, such as to determine whether the user fill out the form.

1994 is the era of object-oriented programming (Object-oriented programming), C + + is the most popular language, and the Java language version 1.0 will be launched the next year, Brendan Eich inevitably affected by it, He wants to think of all the data types in JavaScript as objects (object), which is very similar to Java. However, he immediately encountered a problem, in the end should not design "inheritance" mechanism?

Ii. Evolution of succession

1. Create an instance with the New keyword

Processing form validation Such a simple feature scripting language obviously does not require an "inheritance" mechanism, but if JavaScript is all objects, there is a way to connect all the objects together. Finally, Brendan Eich also designed "inheritance". Just, he didn't introduce the concept of "class", because once the "class", JavaScript is a complete object-oriented programming language, which seems to be a bit too formal, and the design is far from the original intention, while increasing the beginner's entry difficulty.

References to both C + + and the Java language Use the new command to generate an instance:

C + + writes this:

ClassName *object = new ClassName (param);

Java writes this:

Foo foo = new Foo ();

You can also introduce the new command to JavaScript to generate an instance object from the prototype object. However, there is no "class" in JavaScript, so how do you represent a prototype object? The constructor (constructor) of the class is called when the new command is still referenced in C + + and Java. Brendan Eich simplifies the design, in the JavaScript language, the new command is followed by a constructor, which is no longer a class. For example, there is now a constructor called WD that represents the prototype of a front-end development (Web-developper) object.

function WD (skill) {    This.skill = skill;}

Using the New keyword with this constructor generates an instance of the front-end development object.

var WD1 = new WD (' HTML '); Console.log (Wd1.skill); Html

In the constructor of the This keyword, it actually represents the newly created instance object.

2. Defect of new Object

Using the new keyword, generating an instance object with a constructor cannot share properties and methods. For example, in the constructor of a WD object, set the common attribute skill for an instance object.

function WD (skill) {    This.skill = skill;    This.sex = ' Male ';}

Then, build two instance objects:

var WD1 = new WD (' HTML '); var WD2 = new WD (' CSS ');

The skill property of the two objects is independent, modifying one and not affecting the other.

Wd1.skill= ' Javascript '; Console.log (Wd2.skill);//"CSS", unaffected by WD1

Each instance object has its own copy of the properties and methods. This not only can not do data sharing, but also a huge waste of resources.

3. Introduction of prototype attributes

To implement the sharing of properties and methods, Brendan Eich decides to set a prototype property for the constructor. This property contains an object (hereinafter referred to as the "prototype object"), where all instance objects need to share properties and methods that are placed inside the object, and those that do not need to be shared are placed inside the constructor. Once the instance object is created, the properties and methods of the prototype object are automatically referenced. In other words, the properties and methods of an instance object are divided into two types, one local and the other referenced. Or take the WD constructor as an example, now overwrite with the prototype property:

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); Man

Now, the sex attribute is placed in the prototype object, which is shared by two instance objects. As long as the prototype object is modified, it affects two instance objects at the same time.

WD.prototype.sex = ' female '; Console.log (wd1.sex); Female Console.log (wd2.sex); Woman

Since all instance objects share the same prototype object, it appears from the outside that the prototype object is like a prototype of an instance object, and the instance object is like "inheriting" the prototype object. This is the design idea of the JavaScript inheritance mechanism.

Iii. How constructors Implement inheritance

Now there is a constructor for the "MED" Object (med:marketing Experience design, marketing experience)

function MED () {    This.aim = "marketing experience design";}

is still the constructor of the "WD" object,

function WD (skill,sex) {    This.skill = skill;    this.sex = sex;}

How can I get "WD" to Inherit "MED"?

1) Apply binding constructor implementation

The simplest method, presumably, is to use the call or Apply method to bind the parent object's constructor to a child object, that is, to add a line to the child 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

Our usual practice is to use the prototype property. If the prototype object of "WD" points to an instance of Med, then all instances of "WD" can inherit the Med.

Wd.prototype = new Med ();//We point the WD prototype object to an instance of the MED. WD.prototype.constructor = Wd;var WD1 = new WD ("Html", "male"); Console.log (Wd1.aim); Marketing Experience Design

This sentence

Wd.prototype = new MED ();

The equivalent of completely removing the original value of the prototype object, and then assigning a new value. So what does the second line mean?

WD.prototype.constructor = WD;

It turns out that any prototype object has a constructor property that points to its constructor. That is, the constructor attribute of the Wd.prototype object is directed to WD. We have removed the original value of this prototype object in the previous step, so the new prototype object does not have constructor attribute, we need to add it manually, otherwise the "inheritance chain" will be problematic later. This is the meaning of the second line.

Note that this is an important point to keep in mind when programming, and follow this, that is, if you replace the prototype object,

O.prototype = {};

The next step, then, must be to add the constructor property to the new prototype object and refer to this property back to the original constructor.

O.prototype.constructor = O;

3) Direct inheritance from prototype implementation

The invariant properties can be written directly to Med.prototype because of the Med object. So, we can also let WD () skip MED () and inherit Med.prototype directly. Now, we'll rewrite the Med object:

function MED () {}med.prototype.skill = "Med";

The WD prototype object is then directed to the prototype object of the Med, which completes the inheritance.

Wd.prototype = Med.prototype; WD.prototype.constructor = Wd;var WD1 = new WD ("Html", "male"); Console.log (Wd1.skill); MED

The advantage of doing this compared to the previous method is that it is more efficient (without having to execute and establish an instance of the Med), and saves memory. The disadvantage is that Wd.prototype and Med.prototype now point to the same object, so any changes to the Wd.prototype will be reflected in the Med.prototype. So, the above piece of code is actually problematic. Take a look at the second line

WD.prototype.constructor = WD;

This sentence actually changed the constructor attribute of the Med.prototype object too!

Console.log (MED.prototype.constructor); Wd

4) Use an empty object as an intermediary to implement

Since the "Direct inheritance prototype" has these drawbacks, 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 an empty object, so it hardly accounts for memory. At this point, modifying the WD prototype object will not affect the prototype object of the Med.

Console.log (MED.prototype.constructor); MED

5) Encapsulation function using prototype mode

We encapsulate the above method into a function that is easy to use.

function extend (child, Parent) {    var F = function () {};    F.prototype = Parent.prototype;    Child.prototype = new F ();    Child.prototype.constructor = child;}

When used, 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 Yui library implements the inheritance method.

6) Copy Inheritance implementation

The above is implemented using the prototype method to implement inheritance. In fact, since the child object will have the parent object's properties and methods, we directly adopt the "copy" method can also achieve the effect. Simply put, if you copy all the properties and methods of the parent object into the sub-object, can you also implement inheritance? First, all the invariant properties of the Med are put on its prototype object.

function MED () {}med.prototype.aim = "marketing experience Design";

Then, write a function that implements the purpose of the property copy.

function extendcopy (Child, Parent) {    var p = parent.prototype;    var c = child.prototype;    for (var i in P) {        c[i] = p[i];}    }

This function is to copy the attributes from the parent object's prototype object to the prototype object of the child object. One by one When used, write this:

Extendcopy (WD, MED), var WD1 = new WD ("Html", "male"); Console.log (Wd1.aim); Marketing Experience Design

Iv. How to implement inheritance of "non-constructors"

For example, there is now an object called "MED" – The marketing experience design.

var MED = {    aim: ' Marketing experience design '}

There is also an object called "front-end development".

var WD ={    skill: ' HTML '}

How can I let "front-end development" to inherit "marketing experience design", that is, how can I generate a "marketing experience design front-end development" object? It is important to note that both objects are ordinary objects, not constructors, and cannot be implemented using constructor methods for "inheritance."

1. Object () method

The inventor of the JSON format, Douglas Crockford, presents an object () function that can do this.

function Object (o) {    function F () {}    f.prototype = O;    return new F ();

This object () function, in fact, only do one thing, is the prototype property of the object, pointing to the parent object, so that the child object and the parent object together. When used, the first step is to create a child object based on the parent object:

var WD = object (MED);

Then, add the properties of the child object itself:

Wd.skill = ' html ';

At this point, the child object has inherited the properties of the parent object.

Console.log (Wd.aim); Marketing Experience Design

2. Shallow copy

In addition to using the "prototype chain", there is another way of thinking: The Parent object's properties, all copied to the child object, can also implement inheritance. The following function is making a copy:

function Lightcopy (p) {    var c = {};    for (var i in P) {        c[i] = P[i];    }    C.uber = p;    return c;}

When used, write this:

var WD = lightcopy (MED); Wd.aim = ' Front-end development ';

However, there is a problem with such a copy. That is, if the parent object's property is equal to an array or another object, then actually the child object obtains only one memory address, not a real copy, so there is a possibility that the parent object will be tampered with. See, now add a "skill" attribute to Med, whose value is an array.

Med.skills = [' html ', ' CSS ', ' Javascript '];

WD inherits the Med through the Lightcopy () function.

var WD = lightcopy (MED);

We then add a property for WD's "skills":

WD.skills.push (' teamwork ');

What happened? Med's "skills" have also been tampered with!

Console.log (Wd.skills); ' HTML ', ' Javascript ', ' css ', ' Teamwork ' Console.log (med.skills); ' HTML ', ' Javascript ', ' css ', ' teamwork '

So, lightcopy () just copies the basic types of data, and we call this copy "shallow copy." This is how early jquery implements inheritance.

3. Deep copy

The so-called "deep copy" is the ability to make real-world copies of arrays and objects. Its implementation is not difficult, as long as the recursive call "shallow copy" on the line.

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;}

Use this to write:

var WD = deepcopy (MED);

Now, add an attribute to the parent object, and the value is an array. Then, modify this property on the child object:

Med.skills = [' html ', ' CSS ', ' Javascript ']; WD.skills.push (' teamwork ');

At this point, 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 is using this method of inheritance.

Revisit the JavaScript inheritance mechanism

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.