javascript几种继承总结

199 阅读2分钟

我目前所用过的常用的js继承有7种,分别为,原型继承,构造继承,拷贝继承,实例继承,组合继承,寄生组合继承,class继承.下面将逐一分析各种继承的优缺点。

先写一个父类以便继承。

   function Parent(name) {
            this.name = name || 'parent';
            this.sleep = function () {
                console.log(this.name + '跟淼在一起睡觉');
            }
        }

1、原型继承

就是把son的原型改为parent的new实例,来实现继承。

      function Son() { }
        Son.prototype = new Parent();
        //测试
        var son = new Son();
        console.log(son.name);//parent 

        son.sleep();//调用父类的方法 //parent跟淼在一起睡觉
        console.log(son instanceof Parent); //true 与父同类型
        console.log(son instanceof Son); //true  

这种方式继承的缺点是:上面使用原型链来继承,没办法使属性私有化。属性都是共享的。一改全改。

2、借用构造继承

在son里面,把parent的this指向变成son的this指向,来实现继承

 function Son(name) {
            Parent.call(this);
            this.name = name || 'Parent';
        }
        var son = new Son('fxq');
        console.log(son.name); //fxq
        son.sleep(); //fxq跟淼在一起睡觉
        console.log(son instanceof Parent); //false
        console.log(son instanceof Son); //true

这种方式继承的缺点是:只能继承属性,父类的方法不能共享,就是每个子类调用方法,但方法都不同,会造成内存泄露。

3、实例继承

   function Son() {
            var instance = new Parent();
            return instance;
        }
        var son = new Son()
        console.log(son.name) //传不了参  parent 
        son.sleep(); //parent跟淼在一起睡觉
        console.log(son instanceof Parent); //true
        console.log(son instanceof Son); //false

4、组合继承

是将原型继承和构造继承组合起来实现继承。即将parent的指向改到son上,也将son原型改为parent实例。

function Son(name) {
            Parent.call(this);
            this.name = name || 'Parent';
        }
        Son.prototype = new Parent();
        console.log(Son.prototype.constructor);
        Son.prototype.constructor = Son;//重新将构造函数指向改回Son函数,没改之前指向Parent
        console.log(Son.prototype.constructor);
        var son = new Son('fxq');
        console.log(son.name); //fxq
        son.sleep(); //fxq跟淼在一起睡觉
        console.log(son instanceof Parent);  //true
        console.log(son instanceof Son); //true

这种继承方法解决了上面的问题,但缺点是父类原型对象被调用了两次,浪费了内存。

浏览器显示结果

ƒ Parent(name) {
            this.name = name || 'parent';
            this.sleep = function () {
                console.log(this.name + '跟淼在一起睡觉');
            }
        }
Untitled-1.html:59 ƒ Son(name) {
            Parent.call(this);
            this.name = name || 'Parent';
        }
Untitled-1.html:61 fxq
Untitled-1.html:13 fxq跟淼在一起睡觉
Untitled-1.html:63 true
Untitled-1.html:64 true

5、寄生组合继承

//寄生组合继承
        function Son(name) {
            Parent.call(this,name);
            this.name = name || 'Parent';
        }
        //抱在iief里面
        (function () {
            var Super = function () { };
            Super.prototype = Parent.prototype;
            Son.prototype = new Super(); //这是找个中间量吧
        })();
        var son = new Son('fxq');
        console.log(son.name);
        son.sleep()
        console.log(son instanceof Parent); // true
        console.log(son instanceof Son); //true

这种方法继承几乎没有缺点,很完美,但是就是实现复杂。

6、ES6 class继承

    class Son extends Parent {
            constructor(name) {
                super(name);
                //super(name) 就是parent.call(this,name);
                this.name = name || 'Parent';
            }

        }

        var son = new Son('fxq');
        console.log(son.name);
        son.sleep()
        console.log(son instanceof Parent); // true
        console.log(son instanceof Son); //true

这种继承是使用ES6class语法糖,将寄生组合继承简化。

super(name) 就是parent.call(this,name);

7、拷贝继承

拷贝继承就是利用递归实现深拷贝,这里不多做赘述。

总结:寄生组合继承是目前最好的继承方法,就是太复杂,ES6新出的class继承方法感觉像是模仿了Java的class方法来哦继承,后面可能成为主流继承方法。