Chapter 6 Object-Oriented Programming (ii) JavaScript Advanced Programming

Source: Internet
Author: User
6.2 inheritance

Many oo languages support two inheritance Methods: interface inheritance and implementation inheritance. Interface inheritance only inherits the method signature, while implementation inheritance inherits the actual method.

Because the function does not have a signature, interface inheritance cannot be implemented in ecmascript. Ecmascript only supports implementation inheritance, and its implementation inheritance mainly relies on the prototype chain.

6.2.1 prototype chain

The basic idea of prototype chain is to use prototype to let one reference type inherit the attributes and methods of another reference type.

Constructor, prototype, and instance relationships: Each constructor has a prototype object that contains a pointer to the constructor, the instance contains an internal pointer to the prototype object.

Let the prototype object be equal to another type of instance. In this case, the prototype object will contain a pointer pointing to another prototype. Correspondingly, the other prototype also contains a pointer pointing 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.

<SCRIPT> function supertype () {This. property = true;} supertype. prototype. getsupervalue = function () {return this. property ;}; function subtype () {This. subproperty = false;} // inherits the supertypesubtype. prototype = new supertype (); subtype. prototype. getsubvalue = function () {return this. subproperty;}; var instance = new subtype (); console. log (instance. getsupervalue (); // trueconsole. log (instance instanceof object); // trueconsole. log (instance instanceof supertype); // trueconsole. log (instance instanceof subtype); // trueconsole. log (object. prototype. isprototypeof (Instance); // trueconsole. log (supertype. prototype. isprototypeof (Instance); // trueconsole. log (subtype. prototype. isprototypeof (Instance); // true </SCRIPT>

1. Do not forget the default prototype.

All reference types inherit objects by default, and this inheritance is also implemented through the prototype chain. The default prototype of all functions is an object instance. Therefore, the default prototype contains an internal pointer pointing to object. prototype. This is also the root cause that all custom types will inherit default methods such as tostring () and valueof.

2. determine the relationship between the prototype and the instance

You can determine the relationship between the prototype and the instance in two ways. The first method is to use the instanceof operator. If you use this operator to test the constructor that has occurred in the instance and prototype chain, true is returned.

The second method is to use the isprototypeof () method. Similarly,Any prototype that has appeared in the prototype chain can be said to be the prototype of the Instance derived from the prototype chain..

3. Define methods with caution

A sub-type sometimes needs to overwrite a method of the super type or add a method that does not exist in the super type. However, the Code for adding methods to the prototype must be placed after the statement for replacing the prototype.

<SCRIPT> function supertype () {This. property = true;} supertype. prototype. getsupervalue = function () {return this. property ;}; function subtype () {This. subproperty = false;} // inherits the supertypesubtype. prototype = new supertype (); // Add the subtype method. prototype. getsubvalue = function () {return this. subproperty;}; // rewrite the subtype method in the supertype. prototype. getsupervalue = function () {// remember that the prototype method in supertype is only blocked !!! Return false;} var instance = new subtype (); console. Log (instance. getsupervalue (); // false </SCRIPT>

When the prototype chain is used for inheritance, you cannot use the object literal to create the prototype method. This will overwrite the prototype chain.

<SCRIPT> function supertype () {This. property = true;} supertype. prototype. getsupervalue = function () {return this. property ;}; function subtype () {This. subproperty = false;} // inherits the supertypesubtype. prototype = new supertype (); // adding a new method using the literal will result in the previous line of code being invalid subtype. prototype = {getsubvalue: function () {return this. subproperty;}, someothermethod: function () {return false ;}} var instance = new subtype (); console. log (instance. getsupervalue (); // error </SCRIPT>

4. prototype chain problems

The main problem is the prototype that contains the reference type value.

The prototype property that contains the reference type value is shared by all instances. Therefore, you must define the property in the constructor rather than in the prototype object.

When prototype is used to implement inheritance, the prototype will actually become another type of instance. Therefore, the original Instance property becomes the current prototype property.

<SCRIPT> function supertype () {This. colors = ["red", "blue", "green"]} function subtype () {}// inherits supertypesubtype. prototype = new supertype (); var instance1 = new subtype (); instance1.colors. push ("black"); // "red, blue, green, black" console. log (instance1.colors); var instance2 = new subtype (); console. log (instance2.colors); // "red, blue, green, black" </SCRIPT>

Remember that this problem occurs as long as the reference type does not exist. If it is not a reference type, the subclass tries to modify the attribute in prototype. In fact, the subclass itself defines an attribute with the same name.

<SCRIPT> function supertype () {This. colors = 5;} function subtype () {}// inherits supertypesubtype. prototype = new supertype (); var instance1 = new subtype (); instance1.colors = 6; // 6console. log (instance1.colors); var instance2 = new subtype (); console. log (instance2.colors); // 5 // The main reason is that the prototype attributes cannot be modified in the subclass instance, however, you can modify the attributes of the object to which the reference type points. // remember that the above instance1.colors = 6 does not modify the attributes in prototype, but you have customized a new colorsdelete instance1.colors; console. log (instance1.colors); </SCRIPT>

The second problem with the prototype chain is that when creating a child-type instance, you cannot pass parameters to a super-Type constructor. In fact, it should be said that there is no way to pass parameters to super-type constructors without affecting all object instances.

6.2.2 borrow Constructors (counterfeit objects or classic inheritance)

Basic Idea: Call a super-Type constructor within a sub-Type constructor.

A function is only an object that executes code in a specific environment. Therefore, you can use the apply () and call () Methods to execute constructors on newly created objects (in the future.

<SCRIPT> function supertype () {This. colors = ["red", "blue", "green"]} function subtype () {// inherits the supertypesupertype. call (this);} var instance1 = new subtype (); instance1.colors. push ("black"); alert (instance1.colors); // "red, blue, green. black "Var instance2 = new subtype (); alert (instance2.colors); //" red, blue, green "</SCRIPT>

1. PASS Parameters

You can pass parameters to the super-Type constructor In the subtype constructor.

<SCRIPT> function supertype (name) {This. name = Name;} function subtype () {// inherits the supertype, And the supertype parameter is also passed. call (this, "Nicolas"); // instance property this. age = 29;} var instance = new subtype (); console. log (instance. name); // "Nicolas" console. log (instance. age); // 29 </SCRIPT>

To ensure that the suprtype constructor does not overwrite the attributes of the Child type, you can add the attributes that should be defined in the Child type after calling the super-Type constructor.

2. Borrow Constructors

If you just borrow a constructor, you cannot avoid the constructor pattern. methods are defined in constructor. Therefore, function reuse is impossible. In addition, the methods defined in the super-type prototype are invisible to sub-types, and only the constructor mode can be used for all types of results.

<SCRIPT> function supertype (name) {This. name = Name;} supertype. prototpe. getname = function () {console. log (this. name);} function subtype () {// inherits the supertype, And the supertype parameter is also passed. call (this, "Nicolas"); // instance property this. age = 29;} var instance = new subtype (); console. log (instance. name); // "Nicolas" console. log (instance. age); // 29console. log (instance. getname (); // erros </SCRIPT>

6.2.3 combination inheritance (pseudo-classic inheritance)

Combine the prototype chain with the borrow constructor technology to take full advantage of an inheritance mode. The idea behind it is to use the prototype chain to inherit the prototype attributes and methods, and use constructors to inherit the instance attributes. In this way, function reuse is realized by defining the method on the prototype, and each instance can have its own attributes.

6.2.4 original type inheritance

A group prototype allows you to create new objects based on existing objects without creating custom types.

<SCRIPT> // within the object () function, a temporary constructor is created, and the input object is used as the prototype of the constructor, // a new instance of this temporary type is returned. // In essence, object () performs a shortest copy on the objects passed in. Function object (o) {function f () {} f. prototype = O; return new F ();} var person = {name: "Nicolas", friends: ["shellby", "Court", "Van"]}; vaR anotherperson = Object (person); anotherperson. name = "Greg"; anotherperson. friends. push ("Rob"); var yetanotherperson = Object (person); yetanotherperson. name = "Linda"; yetanotherperson. friends. push ("Barbie"); console. log (person. friends); console. log (anotherperson. friends); console. log (yetanotherperson. friends); </SCRIPT>

Attributes that contain reference type values always share the corresponding values, just as in the prototype mode.

It is not necessary to create constructors in a crowd, but to keep an object similar to another, the original type inheritance is fully competent.

6.2.5 parasitic inheritance

Create a function that is only used to encapsulate the inheritance process. The function enhances the object in some way internally, and finally returns the object just like it does all the work.

<SCRIPT> function object (o) {function f () {} f. prototype = O; return new F ();} function createanother (original) {var clone = Object (original); // create a new object clone by calling the function. sayhi = function () {// enhance the console of this object in some way. log ("hi") ;}; return clone; // return this object} var person = {name: "Nicolas", friends: ["Shelby", "Court ", "Van"]}; var anotherperson = createanother (person); anotherperson. sayhi (); // "hi" </SCRIPT>

Parasitic inheritance is also a useful mode when you consider objects rather than custom types and constructors. The object () function used in the inheritance mode is not required. Any function that can return new objects applies to this mode.

Adding a function to an object using parasitic inheritance will reduce the efficiency of function reuse. This is similar to the constructor mode.

6.2.6 parasitic combined inheritance

The biggest problem with combination inheritance is that, under any circumstances, super-Type constructor is called twice: one is when the sub-type prototype is created, and the other is inside the sub-Type constructor. The child type will eventually contain all instance attributes of the super-type object, but you have to override these attributes when calling the child Type constructor.

<SCRIPT> function supertype (name) {This. name = Name; this. colors = ["red", "blue", "green"];} supertype. prototype. sayname = function () {console. log (this. name) ;}; function subtype (name, age) {supertype. call (this, name); // The second call to supertypethis. age = age;} subtype. prototype = new supertype (); // call supertype () subtype for the first time. prototype. sayage = function () {console. log (this. age) ;}; </SCRIPT>

Parasitic combined inheritance means that the constructor is used to inherit attributes and the methods are inherited by the prototype chain. The basic idea behind it is that we don't have to call a super-Type constructor to specify a sub-type prototype. What we need is nothing more than a copy of the super-type. Essentially, it is to use parasitic inheritance to inherit the super-type prototype and then specify the result to the sub-type prototype.

<SCRIPT> function inheritprototype (subtype, supertype) {var prototype = Object (supertype. prototype); // create the prototype object. constructor = subtype; // enhancement object subtype. prototype = prototype; // specify the object} function supertype (name) {This. name = Name; this. colors = ["red", "blue", "green"];} supertype. prototype. sayname = function () {console. log (this. name) ;}; function subtype (name, age) {supertype. call (this, name); this. age = age;} inheritprototype (subtype, supertype); subtype. prototype. sayage = function () {console. log (this. age) ;}; </SCRIPT>

The efficiency in this example is that it only calls a supertype constructor once, and thus avoids creating unnecessary and redundant attributes on subtype. prototype. At the same time, the prototype chain can remain unchanged; therefore, instanceof and isprototypeof () can be used normally ().
Conclusion 6.3

Objects can be created and enhanced during code execution, so they are dynamic rather than strictly defined entities.

Object Creation Mode:

  • Factory mode: Create an object using a simple function, add attributes and methods to the object, and then return the object.
  • The constructor mode allows you to create a custom reference type and use the new operator like creating a built-in object instance. However, the constructor mode also has the disadvantage that every member of the constructor cannot be reused, including functions. Since functions can be not limited to any objects (I .e., they are loosely coupled with objects), there is no reason not to share functions among multiple objects.
  • Prototype: Specify the attributes and methods that should be shared using the prototype attribute of the constructor. When combining the constructor mode and the prototype mode, you can use the constructor to define instance attributes, and use the prototype to define shared attributes and methods.

Javascript mainly implements inheritance through prototype chain. The prototype chain is constructed by assigning a type of instance to the prototype of another constructor. In this way, the child type can access all properties and methods of the super type, which is similar to class-based inheritance. The prototype chain problem is that the object instance shares all the inherited attributes and methods, so it is not suitable for separate use. The technique to solve this problem is to borrow constructors, that is, to call the super-Type constructor within the sub-Type constructor. In this way, each instance has its own attributes, and the type can be defined only in the constructor mode. The most commonly used inheritance mode is combination inheritance. This mode uses the prototype chain to inherit shared attributes and methods, and inherits instance attributes by borrowing constructors.

  • The original type inheritance can implement inheritance without the need to pre-define the constructor. Its essence is to execute a shortest copy of a given object. The copied copy can be further transformed.
  • Parasitic inheritance is very similar to the original type inheritance. It also creates an object based on an object or some information, enhances the object, and finally returns the object. This mode can be used together with the combination inheritance to solve the problem of inefficiency caused by multiple calls to the super-Type constructor in the combination inheritance mode.
  • Parasitic combined inheritance combines the advantages of parasitic inheritance and combination inheritance, and is the most effective way to implement type-based inheritance.

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.