JavaScript Object-Oriented inheritance detailed

Source: Internet
Author: User

First, the preliminary study of inheritance

Most JavaScript implementations use __proto__ attributes to represent the prototype chain of an object.

We can simply think of prototype as a template, the newly created custom object is prototype a copy of the template () (actually not a copy but a link, but the link is not visible, the newly instantiated object has an invisible pointer inside, __proto__ pointing to the prototype object)

When a property is found for an object, JavaScript traverses the prototype chain up until it finds a property of the given name. The lookup method can be represented as:

function GetProperty (obj, prop) {    if (Obj.hasownproperty (prop)) {        return obj[prop];    }    else if (obj.__proto__!== null) {        return GetProperty (obj.__proto__, prop);    }    else {        return undefined;}    }

We use object-oriented in JS a lot of the time:

function Person (name,age) {    this.name = name;    This.age = age;} Person.prototype.printInfo = function () {    console.log (this.name + ': ' + this.age);}; var person = new Person (' Jack ', ' n ');p erson.printinfo ();  Jack:17

and change, you can see, this way is also possible

var person = {/    * declares the required item */    Name: ' Name ', age    : ' Age ',        printinfo:function () {        Console.log ( THIS.name + ': ' + this.age);    }}; var person = {    name: ' Jack ',    age:17,    __proto__: Person};p Erson.printinfo ();  Jack:17

In fact, this is done by pointing the __proto__ to the person to achieve the purpose of the prototype inheritance (which may also be the source of some successor approach)

The above two methods are equivalent, but we see more or new way to produce the instance object, in fact, the new way is also implemented through inheritance, that a new exactly what to do?

There are two versions, which one is more pertinent

1)

this 变量引用该对象,同时还继承了该函数的原型(即把__proto__属性设置为该对象的prototype。2、属性和方法被加入到 this 引用的对象中(使用apply传参调用)。
3、新创建的对象由 this 所引用,并且最后隐式的返回实例。

用代码实现应该就是这样的

/* New Constructor () */function new (f) {    var n = {' __proto__ ': F.prototype};/* Step 1 *    /return function () { C5/>f.apply (n, arguments);            /* Step 2 */        return n;                         /* Step 3 */    };}

2)

var obj = {};obj.__proto__ = Base.prototype; Base.call (obj);

However, when I implemented the code, there was a wireless call stack overflow in both cases, and perhaps the new operation was not so simple inside

Ii. Overview of the way of succession

Said so many new also disorderly, may as well direct cut into the topic, talks about JS popular several inheritance way

1) Object Impersonation

Object impersonation is also divided into several categories--adding temporary properties, apply/call, etc.

Add temporary properties

The disadvantage is that you can only inherit the indicated property, and the properties on the prototype are not

function Parent (name) {    this.name = name;    This.words = ' words ';    This.say = function () {        console.log (this.name + ': ' + this.words);}    ;} Parent.prototype.say1 = function () {        console.log (this.name + ': ' + this.words);}; function child (name) {    this.temp = Parent;    This.temp (name);    The temp delete this.temp can be destroyed by taking the parameter name and then obtaining the corresponding Name,words attribute    . var child = new Child (' child '); Child.say (); Child.say1 ();

Call/apply

Actually changes the direction of this in the parent, as in the previous method, but cannot get the properties of the prototype.

function Parent (name) {    this.name = name;    This.words = ' words ';    This.say = function () {        console.log (this.name + ': ' + this.words);}    ;} Parent.prototype.say1 = function () {        console.log (this.name + ': ' + this.words);}; function child (name) {    //parent.call (this,name);    Parent.apply (This,[name]);} var child = new Child (' child '); Child.say (); Child.say1 ();

One drawback of object impersonation is that it is prone to wasting memory.

Because every time the impersonation process needs to instantiate a parent object, and each time the instantiation process, this shows that the specified property will exist independently in each instance and will not be shared.

For example, say () This method, each call to child will be newly generated and. The Say1 () method on the prototype can be shared.

2) prototype chain inheritance

This inheritance may be the most common: assigning a new instance of a parent class to the constructor's prototype

function Parent (name) {    this.name = name;    This.words = ' words ';    This.say = function () {        console.log (this.name + ': ' + this.words);}    ;} Parent.prototype.say1 = function () {        console.log (this.name + ': ' + this.words);}; function child (name) {    this.name = name;} Child.prototype = new Parent ();
If this sentence is not added, the child's constructor will be covered by the parent and become ParentChild.prototype.constructor = child;
var child = new Child (' child '); Child.say (); Child.say1 ();

As can be seen, child can not only inherit to the parent of say () also can get Say1 (), the key point is the new Parent () This new operation

According to the new operation we talked about at the very beginning, we can know what it's doing.

Here is a variant, which is also OK, although you do not have to define this.name again in child, but again new child (), you cannot update the values we need.

So this should be a problem with the inheritance of the prototype chain.

function Parent (name) {    this.name = name;    This.words = ' words ';} Parent.prototype.say1 = function () {        console.log (this.name + ': ' + this.words);}; function Child () {}//writes directly in the argument childchild.prototype = new Parent (' child '); Child.prototype.constructor = child;//Such newChild is invalid var child = new Child (' NewChild '); Child.say1 (); var p = new Parent (); P.say1 (); Child:words
3) prototype chain + object impersonation (borrowing constructors)

Both the prototype chain method and the object impersonation method are all flawed, and the defects of both are the advantages of each other. A combination of the two, nature is a good way, it is called a combination of inheritance it.

The idea behind it is to use the prototype chain to implement inheritance of prototype properties and methods, and to implement inheritance of instance properties by borrowing constructors. This enables the reuse of functions both by defining methods on the prototype and ensuring that each instance has its own properties.

function Parent (name) {    this.name = name;    This.words = ' words ';} Parent.prototype.say1 = function () {        console.log (this.name + ': ' + this.words);}; function child (name) {    //object impersonating    Parent.call (this,name);} The prototype chain inherits Child.prototype = new Parent (); Child.prototype.constructor = Child;var Child = new Child (' child '); Child.say1 (); Child:words

4) directly inherit the prototype of the parent class

We know that the inheritance of the prototype chain is

Child.prototype = new Parent ();

Could you skip the instantiation of the parent class and take the parent's prototype directly?

Child.prototype = Parent.prototype;

In fact, this is also possible, to see an example.

function Parent (name) {    this.name = name;    This.words = ' words ';} Parent.prototype.age = 30; Parent.prototype.sayAge = function () {    console.log (this.age);}; Parent.prototype.say = function () {        console.log (this.name + ': ' + this.words);}; function child (name) {    ///Parent.call (this,name);} Directly inherit the parent class Prototypechild.prototype = Parent.prototype; Child.prototype.constructor = Child;var Child = new Child (' child '); Child.say (); Undefined:undefinedchild.sayAge (); 30

As you can see, this method only gets the prototype property of the parent class, and the name and words properties on the instance are not available.

If you want to take it, then use Parent.call (this.name).

As a result, it should be quicker to use prototype directly, since it is not time consuming to instantiate an object as in the previous method. But there are shortcomings.

The disadvantage is that Child.prototype and Parent.prototype now point to the same object, so any changes to the Child.prototype will be reflected in the Parent.prototype.

function Parent (name) {    this.name = name;    This.words = ' words ';} Parent.prototype.age = 30; Parent.prototype.sayAge = function () {    console.log (this.age);}; Parent.prototype.say = function () {        console.log (this.name + ': ' + this.words);}; function child (name) {     parent.call (this,name);} Directly inherits the parent class Prototypechild.prototype = Parent.prototype;//child.prototype = new parent (); Child.prototype.constructor = Child;var Child = new Child (' child '); Child.say (); Child.sayage ();  Child.prototype.age = 40; Console.log (Parent.prototype.age); 40

You can see that the prototype of the parent has also been changed, but the way the prototype chain inherits is not.

But the wise man came up with a good idea: to use an empty object as an intermediary, and then to use the prototype of operations,

This prevents the instantiation of objects from producing too much time-consuming, but also avoids the case of parent-child prototype mixing.

function Parent (name) {    this.name = name;    This.words = ' words ';} Parent.prototype.age = 30; Parent.prototype.sayAge = function () {    console.log (this.age);}; Parent.prototype.say = function () {        console.log (this.name + ': ' + this.words);}; function child (name) {     parent.call (this,name);} Encapsulated into function functions extend (child,parent) {    ///Mediation Object    function F () {}    f.prototype = Parent.prototype;    Child.prototype = new F ();    Child.prototype.constructor = child;} Inherit extend (child,parent); var child = new Child (' child '); Child.say (); Child.sayage ();  Child.prototype.age = 40; Console.log (Parent.prototype.age); 30

5) prototype-Type inheritance

This inheritance uses prototypes and creates new objects based on existing objects, without having to create custom types in a way called原型式继承。

Can be encapsulated into a method, this method actually 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.

var parent = {    name: ' Parent ',    words: [' word1 ', ' Word2 '],    say:function () {        console.log (this.name + ': ' + this.words);    }};/ /encapsulated into Method object.create = function (Parent) {    function F () {}
The reason for not f.prototype = Parent.prototype here is
The parent object defined by the object literal does not have this direct prototype attribute (belonging to object)
If defined by the function Parent (), you can
F.prototype = Parent; return new F ();}; var child = Object.create (Parent); Child.say (); Child.name = ' child '; Child.words.push (' Word3 '); Child.say (); Parent.say ();

When child inherits the property method of the parent class, it can update the property value or redefine it, but there is a property sharing problem.

If it is a reference type of data, such as object, such as a child to words to add an item, the parent class will also be updated, causing some degree of problem.

The method of resolving reference type data sharing problems is generally not inheriting this property, or

6) Copy all the properties of the parent object to the child object

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.

var parent = {    name: ' Parent ',    words: [' word1 ', ' Word2 '],    say:function () {        console.log (this.name + ': ' + this.words);    }};/ /Object copy function Extendcopy (obj) {    var newObj = {};    For (var item in obj) {        Newobj[item] = Obj[item];    }    return NEWOBJ;} var child = extendcopy (Parent); Child.say (); Parent:word1,word2 child.name = ' child '; Child.words.push (' Word3 '); Child.say (); Child:word1,word2,word3 Parent.say ();//Parent:word1,word2,word3

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.

So the above child will also react to the parent when modified.

So you need to make a deep copy until you get the real value.

var parent = {    name: ' Parent ',    words: [' word1 ', ' Word2 '],    say:function () {        console.log (this.name + ': ' + this.words);    }};/ /reference type deep copy function Deepcopy (obj,newobj) {    newObj = NEWOBJ | | {};    For (var item in obj) {        if (typeof obj[item] = = = ' object ') {            Newobj[item] = (Object.prototype.toString.call (obj[ Item]) = = = ' [object Array] ')? [] : {};            Deepcopy (Obj[item],newobj[item]);        } else{            Newobj[item] = Obj[item]        }    }    return NEWOBJ; var child = deepcopy (Parent); Child.say (); Parent:word1,word2 child.name = ' child '; Child.words.push (' Word3 '); Child.say (); Child:word1,word2,word3 Parent.say ();//Parent:word1,word2

JavaScript Object-Oriented inheritance detailed

Related Article

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.