In-depth understanding of JavaScript object-oriented programming

Source: Internet
Author: User
Tags function prototype gety mul object object hasownproperty

Read Catalogue

    • One: Understanding the constructor prototype (prototype) mechanism
    • Second: Understanding the concept of prototype domain chain
    • Three: Understanding the prototype inheritance mechanism
    • IV: Understanding the use of class inheritance (better alternatives to inheritance)
    • V: We recommend using encapsulation classes to implement inheritance
    • VI: Understanding the use of replication inheritance
Back to Top

One: Understanding the constructor prototype (prototype) mechanism

Prototype is a mechanism for JavaScript to implement and manage inheritance. It is also an object-oriented design idea. The prototype of a constructor stores a pointer to a reference object, which points to a prototype object that stores the original properties and methods of the function, and we can access the properties and methods inside the prototype with the help of the prototype property.

When the constructor is materialized, all instance objects can access the constructor's prototype members, and if a member is declared in the prototype, all the real-column methods can share it, such as the following:

Constructor a its prototype has a GetName method function a (name) {    this.name = name;} A.prototype.getname = function () {    return this.name;} The 2 real columns have a prototype GetName method after 2, and the following code is var Instance1 = new A ("Longen1"), var instance2 = new A ("Longen2"); Console.log (Instance1 . GetName ()); Longen1console.log (Instance2.getname ()); Longen2

The prototype has a common object structure, which can set any ordinary object as a prototype object; In general, objects are inherited with object, and you can understand that object is a superclass of all objects, object is not a prototype, and the constructor has a prototype, so the actual object is also a real column of object, the following code:

A Console.log object is a real column of constructors (Instance1 instanceof A); Trueconsole.log (Instance2 instanceof A); The true//object is also a real column of object Console.log (Instance1 instanceof object); Trueconsole.log (Instance2 instanceof Object); The True//object object is a superclass of all objects, so the constructor is also the real column of object Console.log (A instanceof object); true//but the actual column of the object is not a function object as follows code Console.log (Instance1 instanceof function); Falseconsole.log (Instance2 instanceof Function); false//but the object is related to function as follows Code description Console.log (function instanceof Object);  Trueconsole.log (Object instanceof Function);  True

As the code above, the function is the real column of object, or it can be the real column of the function; they are 2 different constructors, and we continue to look at the following code:

var f = new Function (), var o = new Object (), Console.log ("------------"); Console.log (f instanceof Function);  Trueconsole.log (o instanceof Function);  Falseconsole.log (f instanceof Object);    Trueconsole.log (o instanceof Object);   True

We understand that by adding a member property or method to a prototype, it is shared by all the properties and methods of the object being instantiated, but if the actual object has the same member name as the prototype, then the member it takes is a real-world object, and if it is not present in the actual Column object, it will go to the prototype to find the member. If the prototype is found, it returns, otherwise the undefined is returned, and the following code tests

function B () {    this.name = "Longen2";} B.prototype.name = "AA"; B.prototype.getname = function () {    return this.name;}; var B1 = new B ();//In this real column lookup, find on the return, otherwise to the prototype find Console.log (B1.name); longen2//found the method in this real column, the prototype to find Console.log (B1.getname ()),//longen2//if not found in this real column, to the prototype is not found, Return to Undefinedconsole.log (b1.a); undefined//Now I use the delete operator to delete the local real-column property, then it is the prototype attribute, the following code: Delete B1.name;console.log (b1.name); Aa
Back to Top

Second: Understanding the concept of prototype domain chain

The advantage of a prototype is the ability to create a large number of real columns based on the object structure, which can share members (properties and methods) in the prototype, and also use prototypes to implement an object-oriented inheritance mechanism ~ The following code: Let's look at this constructor AA and the constructor bb, when Bb.prototype = New AA (11); When you do this, then B inherits from the prototype in a A, a, a, a, a, a, a, X has a property value of 11.

function AA (x) {    this.x = x;} function BB (x) {    this.x = x;} Bb.prototype = new AA (one); Console.log (bb.prototype.x); 11//we come to understand the concept of prototype inheritance and prototype chain, the code is as follows, there is comment function A (x) {    this.x = x;} Define an attribute on a prototype x = 0a.prototype.x = 0;function B (x) {    this.x = x;} B.prototype = new A (1);

When a new A (1) is manifested, this.x =1 in a function, B.prototype = new A (1);  B.prototype is the real column of a, that is, b inherits from a, that is b.prototype.x = 1; The following code:

Console.log (b.prototype.x); 1//defines the constructor of C function C (x) {    this.x = x;} C.prototype = new B (2);

C.prototype = new B (2); That is, C.prototype is the real column of B, c inherits from B; then new B (2) is this.x = 2 in the constructor of B; then C's prototype will have an attribute x =2 = c.prototype.x = 2; The following code:

Console.log (c.prototype.x); 2

The following is a real-listing var d = new C (3); When the constructor of C is actually listed, then this.x = 3 within the constructor of C; Therefore, after printing the d.x = 3, the following code:

var d = new C (3); Console.log (d.x); 3

Delete D.x when you visit d.x, this object is deleted and can only be found from the prototype, because C.prototype = new B (2); That is, c inherits from B, so the prototype of C also has x = 2; i.e. c.prototype.x = 2; The following code:

Delete D.x;console.log (d.x);  2

After deleting the c.prototype.x, we know from the above code that C is inherited from B, and that its prototype is deleted, it will find the prototype chain of the parent element, so it finds x = 1 on the prototype of B; The following code:

Delete C.prototype.x;console.log (d.x);  1

When the prototype attribute X of B is removed, since B is inherited from a, it looks for the attribute of X on the prototype chain of the parent element, and if so, returns if there is an inheritance, no inheritance, and then goes to object to find, if not found, returns to undefined So when you delete the prototype X of B, delete b.prototype.x; Print out the prototype x=0 on A; The following code:

Delete B.prototype.x;console.log (d.x);  0//continues to delete the prototype x after the result is not found, returned to undefined; Delete A.prototype.x;console.log (d.x);  Undefined

In JavaScript, everything is an object, function and object are the real columns of functions, and the parent prototype of the constructor points to the functional prototype, Function.prototype's parent prototype points to the prototype of object, and the parent prototype of object also points to the function prototype, Object.prototype is the top layer of all prototypes;

The following code:

Function.prototype.a = function () {    Console.log ("I am the parent prototype function");} Object.prototype.a = function () {    Console.log ("I am the parent prototype object");} function A () {    THIS.A = "A";} A.prototype = {    b:function () {        console.log ("B");}    } Function and object are the actual columns of functions as follows: Console.log (A instanceof function);  Trueconsole.log (A instanceof Object); true//A.prototype is an object that is a real column of object, but not a real column of function console.log (a.prototype instanceof function); Falseconsole.log (A.prototype instanceof Object); true//function is the real column of object with the real column of object and function Console.log (function instanceof Object);   Trueconsole.log (Object instanceof Function); true/* * Function.prototype is a real column of object but Object.prototype is not a real column of Function * Description Object.prototype is the top-level */console.log of all parent prototypes ( Function.prototype instanceof Object);  Trueconsole.log (Object.prototype instanceof Function);  False
Back to Top

Three: Understanding the prototype inheritance mechanism

Constructors have a pointer to the prototype, Object.prototype is the top level of all prototype objects, such as the following code:

var obj = {};object.prototype.name = "Tugenhua"; Console.log (obj.name);//Tugenhua

To define a property for Object.prototype, the object constructed by the literal will get the Object.prototype attribute from the parent class;

From the above code we know that the method of prototype inheritance is: If a needs to inherit from B, then A.prototype (a prototype) = new B () (as a real column of B) can be implemented as a inherits from B; So we can initialize an empty constructor below, then assign the object to the constructor's prototype, and return the constructor's real column, and then implement the inheritance; The following code:

if (typeof object.create!== ' function ') {    object.create = function (o) {        var F = new function ();        F.prototype = O;        return new F ();}    } var a = {    name: ' Longen ',    getname:function () {        return this.name;    }}; var b = {};b = Object.create (a); Console.log (typeof B); Objectconsole.log (b.name);   Longenconsole.log (B.getname ()); Longen

As above code: we first detect whether the object has object.create the method, if not, create one, the method creates an empty constructor, passes the parameter object to the constructor's prototype, and finally returns the constructor's real column, then implements the inheritance mode , as on the test code: First define a object, there are member properties Name= ' Longen ', there is a getname () method, and finally return the Name property; Then define a b null object, use Object.create (a), and inherit the A object to the B object, so the B object also has the attribute name and member method GetName ();

Understanding the Prototype Lookup principle: Object Lookup first finds the corresponding property within the constructor, if the object does not have that property,

Then JavaScript will try to look it up from the prototype, and if there is no such attribute in the prototype object, then they'll find it from the prototype in the prototype, until the object.prototype of the lookup does not have the attribute, then it will return undefined; So we want to find only within that object, in order to improve performance, we can use hasOwnProperty () to determine if there is a property within that object, and if so, execute the code (using for-in Loop Lookup): The following:

var obj = {    "name": ' Tugenhua ',    "age": ' 28 '};//uses for-in loop for (var i in obj) {    if (Obj.hasownproperty (i)) {        Console.log (Obj[i]);//tugenhua}    }

For example, using the For-in loop to find properties inside an object, but what we need to understand is that the for-in loop looks for the properties of the object, which is not guaranteed in order, for-in loops and for loops; The most essential difference is that the for loop is sequential, and the for-in loop iterates over the object is unordered, So if we need the object guarantee order, we can convert the object to an array and then use the For loop to iterate.

Let's talk about the pros and cons of prototype inheritance

First look at the following code://Define constructor A, define privileged properties and privileged methods function A (x) {    this.x1 = x;    THIS.GETX1 = function () {        return this.x1;    }} Define constructor B, define privileged properties and privileged methods function B (x) {    this.x2 = x;    THIS.GETX2 = function () {        return this.x1 + this.x2;    }} B.prototype = new A (1);

B.prototype = new A (1); When this code executes, the prototype of B inherits from a, so B.prototype also has the properties and methods of a, namely: B.prototype.x1 = 1; B.prototype.getx1 method; But B also has its own privileged attributes X2 and privileged methods getX2; The following code:

function C (x) {    this.x3 = x;    THIS.GETX3 = function () {        return this.x3 + this.x2;    }} C.prototype = new B (2); C.prototype = new B (2); When this code executes, the prototype of C inherits from B, so c.prototype.x2 = 2; The C.prototype.getx2 method and C also have their own privileged properties x3 and Privileged methods Getx3,var B = new B (2), var c = new C (3); Console.log (b.x1);  1console.log (C.X1);  

When the b.x1 is in the constructor, it will first look for the X1 attribute, not found, because the prototype of B inherits from a, so a has the X1 attribute, so b.prototype.x1 = 1 is found; var c = new C (3); When actually listing C, from the above code can see that c inherits from B,b inherited from a, so in the C function did not find the X1 property, will continue to find the prototype, until the parent element A has X1 attribute, so c.x1 = 1;c.getx3 () method; Returns THIS.X3+THIS.X2 this.x3 = 3;this.x2 is a property of B, so this.x2 = 2;c.getx2 (); Find the same method, no longer explain

the disadvantages and advantages of prototype are as follows:

The advantage is that multiple objects can be allowed to share the members and methods of the prototype object.

Disadvantages are: 1. Each constructor has only one prototype and therefore does not directly support multiple inheritance;

2. A parent class that does not support multi-parameter or dynamic parameters well. During the prototype inheritance phase, the user is not yet able to decide

What parameters to actually list the constructor.

Back to Top

IV: Understanding the use of class inheritance (better alternatives to inheritance)

Class inheritance is also called constructor inheritance, the constructor of the parent class is executed in the subclass, and the implementation principle is that a method of one constructor a can be assigned to another constructor B, and then the method is called so that constructor a is executed inside constructor B, when constructor B has the properties and methods in constructor a. This is the basic principle of implementing B inheritance and a with class inheritance;

The following code implements the demo:

function A (x) {    this.x = x;    This.say = function () {        return this.x;    }} function B (x, y) {    this.m = A;//use constructor A as a normal function to refer to the temporary method m    this.m (x);  Execute constructor A;    Delete this.m; Clear Temporary method this.m    this.y = y;    This.method = function () {        return this.y;    }} var a = new A (1), var B = new B (2,3); Console.log (A.say ()); Output 1, execute the Say method in constructor a Console.log (B.say ()); Output 2, can execute the method description is inherited from a method Console.log (B.method ()); Output 3, the constructor also has its own method

The above code implements simple class inheritance, but in complex programming, the above method is not used because the code above is not rigorous, the code is highly coupled, and we can use a better method as follows:

function A (x) {    this.x = x;} A.prototype.getx = function () {    return this.x;} Instantiate Avar a = new A (1); Console.log (a.x); 1console.log (A.getx ()); Output 1//Now let's create constructor B, let its b inherit with a, the following code: function B (x, y) {    this.y = y;    A.call (this,x);} B.prototype = new A ();  Prototype inheritance Console.log (B.prototype.constructor); Output constructor A, pointer pointing to constructor AB.prototype.constructor = B;          Reset the constructor so that it points to Bconsole.log (B.prototype.constructor); Point to constructor BB.prototype.getY = function () {    return this.y;} var B = new B (on); Console.log (b.x); 1console.log (B.getx ()); 1console.log (B.gety ()); 2//Below is a demonstration of how to override the constructor GetX as follows: B.prototype.getx = function () {    return this.x;} var b2 = new B (10,20); Console.log (B2.getx ());  Output 10

Let's analyze the above code:

Within constructor B, use A.call (this,x); The meaning of this code is: we all know that using the call or the Apply method can change the this pointer to point, so that the class can be implemented, so in the B constructor, the x parameter is passed to the A-constructor, and inherit from the properties and methods in constructor A;

Use this code: B.prototype = new A (); Prototype inheritance can be achieved, that is, B can inherit all the methods of the prototype in A; Console.log (B.prototype.constructor); Print out the output constructor A, pointer to the constructor A; we understand that when a constructor is defined, its prototype object defaults to an instance of type object, and its constructor defaults to the constructor itself, and if you change the constructor prototype property value, So that it points to another object, the new object will not have the original constructor value, such as the first print console.log (b.prototype.constructor); Point to the constructor a after being instantiated, overriding the property value of setting B's constructor, the second print points to itself B, so B inherits all the properties and methods of constructing a and its prototype, and of course we can override the method in constructor a for constructor B, As the last few lines of code is the constructor a in the Getx method to rewrite, to achieve their own business ~;

Back to Top

V: We recommend using encapsulation classes to implement inheritance

Encapsulation class implementation of the basic principle of inheritance: first define a wrapper function extend, the function has 2 parameters, the sub represents the subclass, the SUP represents the superclass, in the function, the first definition of an empty function f, to implement the function of the relay, first set F prototype for the superclass prototype, and then the empty function instance passed to the child class prototype, The advantage of using an empty function is that avoiding the direct instantiation of a superclass can result in system performance problems, such as a large instance of a superclass, which consumes a lot of memory;

The following code:

function Extend (sub,sup) {    //sub denotes subclass, Sup denotes superclass    //first defines an empty function    var F = function () {};    Set the prototype of the empty function to be the prototype of the superclass    f.prototype = sup.prototype;//Instantiate an empty function and pass the superclass prototype reference to subclass    Sub.prototype = new F ();                The constructor that resets the subclass prototype is the subclass itself    Sub.prototype.constructor = Sub;                The prototype of superclass is saved in subclasses, and the subclass and super-class coupling    Sub.sup = Sup.prototype are avoided.    if (Sup.prototype.constructor = = = Object.prototype.constructor) {        //The constructor that detects the superclass prototype is the prototype itself        Sup.prototype.constructor = Sup;    }} The test code is as follows://Below we define 2 classes A and B, we aim to implement B inheriting from Afunction A (x) {    this.x = x;    This.getx = function () {        return this.x;    }} A.prototype.add = function () {    return this.x + this.x;} A.prototype.mul = function () {    return this.x * this.x;} Constructor bfunction B (x) {    a.call (this,x);//Inherit all properties and methods in constructor A}extend (b,a);  b inherits from Avar B = new B (one); Console.log (B.getx ()); 11console.log (B.add ());  22console.log (B.mul ());  121

Note: in the encapsulation function, there is a code: Sub.sup = Sup.prototype; We can now understand what it means:

For example, after B inherits with a, I give the prototype of the B function the same method of the same prototype as the "a" add ();

The following code

Extend (b,a);  b inherits from Avar B = new B (11); B.prototype.add = function () {    return this.x + "" + this.x;} Console.log (B.add ()); 1111

The Add method in the B function overrides the Add method in the A function, so in order not to overwrite the Add () method in Class A, and to call the Add method in the A function, you can write code like this:

B.prototype.add = function () {    //return this.x + "" + this.x;    Return B.sup.add.call (this);} Console.log (B.add ()); 22

B.sup.add.call (this); The b.sup in is a pointer to the constructor a function, so it contains all the properties and methods of the A function, so you can call the Add method in the A function;

As above are several ways to implement inheritance, class inheritance and prototype inheritance, but these inheritance can not inherit the DOM object, also does not support inheriting system static objects, static methods, such as the Date object is as follows:

Use the class to inherit the Date object function D () {    date.apply (this,arguments);//Call the Date object, reference it, implement inheritance}var d = new D (); Console.log ( D.tolocalestring ()); [Object Object]

As the code runs to print out object, we can see that using class inheritance cannot implement the system static method of the Date object's inheritance, because he is not a simple function structure, the Declaration, assignment and initialization are encapsulated, and therefore cannot inherit;

Let's take a look at the use of prototypes to inherit date objects;

Function d () {}d.prototype = new D (); var d = new D (); Console.log (d.tolocalestring ());//[object Object]

As we can see from the code, it is not possible to inherit the date static method using prototype inheritance, but we could encapsulate code inheritance as follows:

Function d () {    var d = new Date ();  Instantiates a Date object    d.get = function () {//Defines the local method, and indirectly calls the method Console.log of the Date object        (D.tolocalestring ());    }    return D;} var d = new D ();d. get (); 2015/12/21 12:08:38
Back to Top

VI: Understanding the use of replication inheritance

The basic principle of copy inheritance is to design an empty object, then use the for-in loop to iterate over the members of the object, copy the members of the object to a new empty object, and then implement the copy inheritance; The following code:

function A (x, y) {    this.x = x;    This.y = y;    This.add = function () {        return this.x + this.y;    }} A.prototype.mul = function () {    return this.x * THIS.Y;} var a = new A (2,3), var obj = {};for (var i in a) {    obj[i] = a[i];} Console.log (obj); Objectconsole.log (obj.x); 2console.log (OBJ.Y); 3console.log (Obj.add ()); 5console.log (Obj.mul ()); 6

As the code above: first define a constructor a, the function has 2 properties x, Y, and an Add method, the constructor prototype has a Mul method, first of all, after the completion of a, then create an empty object obj, iterate over the objects to the empty object obj, from the above print effect, We can see that replication inheritance has been implemented, and for replication inheritance we can encapsulate the following methods to invoke:

Copy the inheritance method for the function extension Function.prototype.extend = function (o) {    for (var i in O) {        //) to copy the members of the parameter object to the constructor prototype object of the current object        This.constructor.prototype[i] = o[i];}    } The test code is as follows: var o = function () {};o.extend (new A); Console.log (o.x);  1console.log (O.Y);  2console.log (O.add ()); 3console.log (O.mul ()); 2

The This object in the extended inheritance method encapsulated above points to the currently-manifested object, not to the constructor itself, so to use the prototype extension member, you need to use the constructor property to point to its constructor, and then point to the constructor's prototype through the prototype property ;

Replication inheritance has the following advantages:

1. It cannot inherit read-only methods and properties of system core objects

2. If the object data is very many, so that each copy, the performance is very low;

3. Only if the object is actually listed, it is relatively inflexible to traverse the object's members and attributes;

4. Copy inheritance is simply an assignment, so if the assigned object is a reference type object, there may be some side effects; as we see above, we can use Clone (clone) to optimize the following:

The basic idea is to extend a method for a function that assigns a parameter object to a prototype object of an empty constructor, and then actually lists the constructor and returns the actual Column object, so that the object has all the members of that object; The code is as follows:

Function.prototype.clone = function (o) {    function Temp () {};    Temp.prototype = O;    return Temp ();} The test code is as follows: Function.clone (new A); Console.log (o.x);  1console.log (O.Y);  2console.log (O.add ()); 3console.log (O.mul ()); 2

Original Author Address: http://www.cnblogs.com/tugenhua0707/p/5068449.html

In-depth understanding of JavaScript object-oriented programming

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.