为了账号安全,请及时绑定邮箱和手机立即绑定

前端面试中-es5原型链实现类与继承的几种方法

题目:使用js模拟类与类的继承


 


 


github代码地址:https://github.com/jgchenu/Es5-prototype-chain-implementation-class-and-inheritance


1.借助构造函数实现继承

/**
* 借助构造函数实现继承
*/
function Parent1 () {
this.name = 'parent1';
}
Parent1.prototype.say = function () {
//Parent1 原型链上的方法并没有被 Child1 所继承
};
function Child1 () {
Parent1.call(this);//apply;改变函数运行的上下文(将父级的构造函数this指向子构造函数的实例上)
this.type = 'child1';
}
console.log(new Child1(), new Child1().say());//Uncaught TypeError: (intermediate value).say is not a function
//缺点就是父类原型链上的方法没有被child1继承了,因为只是调用了父类的构造函数,将属性赋值给子类的实例

2.借助原型链实现继承

           /**
           * 借助原型链实现继承
           */
            function Parent2() {
                this.name = 'parent2';
                this.play = [1, 2, 3];
            }
            function Child2() {
                this.type = 'child2';
            }
            Child2.prototype = new Parent2();//new Child2().__proto__===Child2.prototype
            var s1 = new Child2();
            var s2 = new Child2();
            console.log(s1.play, s2.play);//(3) [1, 2, 3] (3) [1, 2, 3]
            s1.play.push(4);
            console.log(s1.play, s2.play);//(4) [1, 2, 3, 4] (4) [1, 2, 3, 4]
            //缺点,虽然父类的实例成为了子类的原型对象,子类实例都能使用到父类的方法跟数据,但是每次实例化子类,都共用同一个父类实例
            //改变原型对象会改变父类实例的数据,从而导致两边的原型对象数据都改变

3.组合

function Parent3() {
            this.name = 'parent3';
            this.play = [1, 2, 3];
        }
        function Child3() {
            Parent3.call(this); //在子构造函数中执行父级构造函数
            this.type = 'child3';
        }
        Child3.prototype = new Parent3();
        var s3 = new Child3();
        var s4 = new Child3();
        s3.play.push(4);
        console.log(s3.play, s4.play); //(4) [1, 2, 3, 4] (3) [1, 2, 3]
        // 缺点:在实例化1个子类的时候,父类的构造函数执行了2次),同时,子类实例有了父类实例的数据,
        // 子类的原型对象同时也是父类的示例,也有了一份一样的父类实例数据

4.组合优化一

function Parent4() {
                this.name = 'parent4';
                this.play = [1, 2, 3];
            }
            function Child4() {
                Parent4.call(this);
                this.type = 'child4';
            }
            Child4.prototype = Parent4.prototype;//实例化1个子类的时候,父类的构造函数执行了1次
            var s5 = new Child4();
            var s6 = new Child4();
            console.log(s5, s6);//Child4 {name: "parent4", play: Array(3), type: "child4"} Child4 {name: "parent4", play: Array(3), type: "child4"}
            console.log(s5 instanceof Child4, s5 instanceof Parent4);//true true
            console.log(s5.constructor);
            //缺点:直接把父类的原型对象复制给子类的原型对象,
            //那么打印出来的s5的constructor是父类的构造函数。是由父类构造的。
            //直接使用s5 instanceof Parent4或者Child5出来的结果都是是true。
            //因为无论instanceof的原理是判断实例化对象的_proto_是不是等于构造函数的prototype对象
            //但是在这里CHild4.prototype跟Parent4.prototype指向的是同一块内存地址,所以肯定都是为true

5.组合优化二

 /**
         * 组合继承的优化2
         */
        function Parent5() {
            this.name = 'parent5';
            this.play = [1, 2, 3];
        }
        function Child5() {
            Parent5.call(this);
            this.type = 'child5';
        }
        Child5.prototype = Object.create(Parent5.prototype);
        Child5.prototype.constructor = Child5;
        var s7 = new Child5();
        console.log(s7 instanceof Child5, s7 instanceof Parent5); //true true
        s7.constructor
        //通过 Object.create()创建一个中间对象{},这个中间对象原型指向Parent.prototype
        //再讲这个中间对象{}赋值给子类的prototpye,最后再修改子类的prototype的constructor为CHild5构造函数
        //这种写法,设置s7的构造函数是Child而不是parent,虽然s7 instanceof child跟parent都未true
        //但是s7.constructor=Child5了,而不是parent5
        //证明s7是从child实例化的。


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
38
获赞与收藏
153

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消