7种继承方式的比较(js)

前言

对于js这种面向过程的编程语言而言,oo不是它的强项,但有时也会在代码中OOP。
这里收集了七种继承方式,并测试做了比较。还有一些其他的实现形式暂未考虑,比如通过拷贝的形式实现继承;
由于技术原因,具体用到哪些场景不是很在行,所以这里就做一些简单的示范和介绍。

代码

		/**
         * https://www.cnblogs.com/qing-5/p/11365614.html
         * 父级构造函数中的属性在子级实例上有一份在原型上有一份(多余),浪费内存
         */
        /*
        function A(name) {
            this.name = name;
            this.propertys = {
                sex: "F"
            };
        }
        A.prototype.sayName = function() {
            console.log("A.prototype.sayName===", this.name);
        };
        A.prototype.sayName2 = function() {
            console.log("A.prototype.sayName===", this.name);
        };

        function B(age, name) {
            A.call(this, name); //
            this.age = age;
            this.propertys = {
                sex: "M"
            };
        }

        B.prototype = new A(); //
        B.prototype.constructor = B; //
        B.prototype.sayName = function() {
            console.log("B.prototype.sayName===", this.name);
        };
        B.prototype.sayAge = function() {
            console.log("B.prototype.sayAge===", this.age);
        };

        var a = new A("aaa");
        var b = new B(22, "bbb");
        a.sayName();
        b.sayName();
        b.sayAge();

        console.log("a===", a);
        console.log("b===", b);

        console.log("a.__proto__", a.__proto__);
        console.log("b.__proto__", b.__proto__);
        */

        


        /**
         * es6 class语法糖
         * 不继承构造器里面的属性
         * 代码易维护
         */
        /*
        class A {
            constructor(name) {
                this.name = name;
            }
            sayName() {
                console.log("A.prototype.sayName===", this.name);
            }
        }

        class B extends A {
            constructor(age, name) {
                super(name);
                this.name = name;
                this.age = age;
            }
            sayName(name) {
                console.log("B.prototype.sayName===", this.name);
            }
            sayAge() {
                console.log("B.prototype.sayAge===", this.age);
            }
        }

        var a = new A("aaa");
        var b = new B(22, "bbb");
        a.sayName();
        b.sayName();
        b.sayAge();

        console.log("a===", a);
        console.log("b===", b);

        console.log("a.__proto__", a.__proto__);
        console.log("b.__proto__", b.__proto__);

        */

        //

        /**
         * <<ES6标准入门 9.11>>
         * 实例之间的无构造函数的继承
         * 要产生多个对象需要克隆并一一改变它们的属性
         */

        /*
        var a = {
            name: "aaa",
            superName: "aaa_super",
            propertys: [{
                _a: "_a"
            }],
            sayName() {
                console.log("a.sayName:", this.name);
            }
        };
        var b = Object.create(a);
        // var b = Object.assign(
        //     Object.create(a), {
        //         name: 'bbb'
        //     }
        // );
        b.name = "bbb";
        b.age = 22;
        b.sayAge = function() {
            console.log("b.sayAge:", this.age);
        }


        a.sayName();
        b.sayName(); //能调用原型上的方法
        b.sayAge();

        b.propertys[0]._b = "_b"; //能改原型上的对象

        console.log("a===", a);
        console.log("b===", b);

        console.log("a.__proto__", a.__proto__); //Object.prototype
        console.log("b.__proto__", b.__proto__);
        */

        

        /** 
         * http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html
         * 构造函数绑定
         * 通过子类构造函数中,绑定父类this上的方法:A.call(this, name);
         * 只能访问父类构造函数内定义的属性和方法,不能访问父类原型上的
         * 子级实例上的属性拥有父级实例一样的属性,实际上消耗了内存换取了速度,因为在原型上查询是耗时的
         */
        /*
        function A(name) {
            this.name = name;
            this.propertys = {
                sex: "F"
            };
            this._a = "_a";
        }
        A.prototype.sayName = function() {
            console.log("A.prototype.sayName===", this.name);
        };
        A.prototype.say = function() {
            console.log("A.prototype.say===", this._a);
        };

        function B(age, name) {
            //继承属性    使用借用构造函数实现对实例属性的继承
            A.call(this, name);
            this.name = name; //覆盖属性
            this.age = age; //父级构造函数中的this上不会有age属性
            this.propertys = {
                sex: "M"
            };
        }
        B.prototype.sayName = function() { //覆盖方法
            console.log("B.prototype.sayName===", this.name);
        };
        B.prototype.sayAge = function() { //自定义方法
            console.log("B.prototype.sayAge===", this.age);
        };
        */

        /**
         * http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html
         * prototype模式
         * 通过子级构造函数的prototype设置为父级实例,并改变constructor指向
         * B.prototype = new A();  
         * B.prototype.constructor = B;
         * 子集对象的原型上有父级对象上的构造函数中的方法和属性,子级对象可以使用父级对象构造函数和原型上的方法属性
         * 子级原型上有一个父级构造函数中相同的副本,额外增加了内存消耗,也容易发生命名冲突
         */

        /*
        function A(name) {
            this.name = name;
            this.propertys = {
                sex: "F"
            };
            this._a = "_a";
        }
        A.prototype.sayName = function() {
            console.log("A.prototype.sayName===", this.name);
        };
        A.prototype.say = function() {
            console.log("A.prototype.say===", this._a);
        };

        function B(age, name) {
            this.name = name;
            this.age = age;
            this.propertys = {
                sex: "M"
            };
        }

        B.prototype = new A("aa");  
        B.prototype.constructor = B;

        B.prototype.sayName = function() { //覆盖方法
            console.log("B.prototype.sayName===", this.name);
        };
        B.prototype.sayAge = function() { //自定义方法
            console.log("B.prototype.sayAge===", this.age);
        };
        B.prototype.name = "B.prototype.name";
        */

        /**
         * http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html
         * 直接继承prototype(共享prototype)
         * 子级的构造函数的prototype上定义的东西会覆盖父级的,他们相互影响
         * 省内存
         */

        /*
        function A(name) {
            this.name = name;
            this.propertys = {
                sex: "F"
            };
            this._a = "_a";
        }
        A.prototype.sayName = function() {
            console.log("A.prototype.sayName===", this.name);
        };
        A.prototype.say = function() {
            console.log("A.prototype.say===", this._a);
        };

        function B(age, name) {
            this.name = name;
            this.age = age;
            this.propertys = {
                sex: "M"
            };
        }

        B.prototype = A.prototype;  
        B.prototype.constructor = B;

        B.prototype.sayName = function() { //覆盖方法
            console.log("B.prototype.sayName===", this.name);
        };
        B.prototype.sayAge = function() { //自定义方法
            console.log("B.prototype.sayAge===", this.age);
        };
        B.prototype.name = "B.prototype.name";
        */

        /**
         * http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html
         * 直接继承prototype(空函数中介)
         * 父子(实例/原型)上的属性和方法都泾渭分明
         * 调用父级原型上的方法this会错误,需显式改变this指向
         */


        /*
        function A(name) {
            this.name = name;
            this.propertys = {
                sex: "F"
            };
            this._a = "_a";
        }
        A.prototype.sayName = function() {
            console.log("A.prototype.sayName===", this.name);
        };
        A.prototype.say = function() {
            console.log("A.prototype.say===", this._a);
            console.log("A.prototype.say | this===", this);
        };

        function B(age, name) {
            this.name = name;
            this.age = age;
            this.propertys = {
                sex: "M"
            };
        }

        var F = function() {};
        F.prototype = A.prototype
        B.prototype = new F();  
        B.prototype.constructor = B;

        B.prototype.sayName = function(a) {
            console.log("B.prototype.sayName===", this.name);
        };
        B.prototype.sayAge = function() {
            console.log("B.prototype.sayAge===", this.age);
        };
        B.prototype.name = "B.prototype.name";
        */




        
        // var a = new A("aaa");
        // var b = new B(22, "bbb");
        // a.sayName();
        // b.sayName();
        // b.sayAge();


        // console.log("a===", a);
        // console.log("b===", b);

        // // console.log("A.name===", A.name);
        // // console.log("B.name===", B.name);

        // console.log("a.__proto__", a.__proto__);
        // console.log("b.__proto__", b.__proto__);

不足

1、没考虑混入(多继承)。
2、具体应用场景。
3、更多的继承方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值