Javascript 进阶 继承

本文深入探讨JavaScript中基于类的继承与基于原型链的继承两种方式,详细解析其实现原理及存在的问题,如引用类型变量共享导致的数据不一致性。并通过代码示例展示了如何解决这些问题。

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.youkuaiyun.com/jiangjunshow

                转载请标明出处: http://blog.youkuaiyun.com/lmj623565791/article/details/29194261
1、基于类的继承
下面看下面的代码:
 <script type="text/javascript">        function Person(name, age)        {            this.name = name;            this.age = age;        }        Person.prototype.say = function ()        {            console.log(this.name + " , " + this.age);        }        function Student(no)        {            this.no = no;        }<span style="white-space:pre"/**         * Student的prototype指向Person的对象         */</span>        Student.prototype = new Person();        var stu1 = new Student("0001");        stu1.name = '张三';        stu1.age = '11';        console.log(stu1.no);        stu1.say();    </script>

输出结果:

0001 张三 , 11 

可以看到Student成功集成了Person,并且拥有了Person的say方法,核心代码其实就是一句 Student.prototype = new Person();,下面通过图解来说明原理:


将Student.prototype指向new Person() , new Person的_proto_又指向Person Prototype;这样完成了整个继承。

但是这种方式存在问题:

问题1:当父类存在引用类型变量时,造成数据不一致,下面我们给Person添加一个hobbies属性,类型为数组。

 <script type="text/javascript">        /**         * 存在问题         * 1、无法在Student的构造方法中传递参数用于父类的构造方法         * 2、对于引用类型变量,造成数据不一致         */        function Person(name, age)        {            this.name = name;            this.age = age;            this.hobbies = [] ;        }        Person.prototype.say = function ()        {            console.log(this.name + " , " + this.age +" , " +this.hobbies);        }        function Student(no)        {            this.no = no;        }        Student.prototype = new Person();        var stu1 = new Student("0001");        stu1.name = '张三';        stu1.age = '11';        stu1.hobbies.push("soccer");        stu1.say();        var stu2 = new Student("0002");        stu2.name = '李四';        stu2.age = '12';        stu2.hobbies.push("girl");        stu2.say();    </script>

输出结果:
张三 , 11 , soccer 李四 , 12 , soccer,girl 
可以看出,李四的hobbies应该只有girl,但是上面的代码让所有对象共享了hobbies属性。

上述的继承方式还存在一个问题:

问题2:在Student的构造方法中,无法使用new Student("00001" , "张三" , 12) ;创建对象,并初始化name和age属性,必须stu.name, stu.age进行赋值


为了解决上述问题,对上述代码进行修改:

 <script type="text/javascript">        function Person(name, age)        {            this.name = name;            this.age = age;            this.hobbies = [];        }        Person.prototype.say = function ()        {            console.log(this.name + " , " + this.age +" , " + this.hobbies);        }        function Student(name, age, no)        {            /**             * 使用call方法,第一个参数为上下文;             * 有点类似Java中的super(name,age)的感觉             */            Person.call(this, name, age);            this.no = no;        }        Student.prototype = new Person();        var stu1 = new Student("0001","张三",11);        stu1.hobbies.push("soccer");        stu1.say();        var stu2 = new Student("0002","李四",12);        stu2.hobbies.push("cangjin");        stu2.hobbies.push("basketball");        stu2.say();    </script>

输出:

0001 , 张三 , soccer 0002 , 李四 , cangjin,basketball 

在Student的构造方法中使用了Person.call(this,name,age)感觉就像super(name,age)【call的第一个参数为上下文】;并且成功解决了对引用属性的共享问题,完美解决。

2、基于原型链的继承

    <script type="text/javascript">        /**         * 基于原型链的集成中都是对象         * 存在问题:         * 1、对于引用类型变量,造成数据不一致         */        var Person = {                    name: "人",                    age: 0,                    hobbies: [],                    say: function ()                    {                        console.log(this.name + " , " + this.age + " , " + this.hobbies);                    }                }                ;        var Student = clone(Person);        Student.no ="";        Student.sayHello = function()        {            console.log(this.name  +"hello ") ;        }        var stu1 = clone(Student);        stu1.name = "zhangsan";        stu1.age = 12;        stu1.hobbies.push("Java");        stu1.say();        var stu2 = clone(Student);        stu2.name = "lisi";        stu2.age = 13;        stu2.hobbies.push("Javascript");        stu2.say();        /**         * 返回一个prototype执行obj的一个对象         * @param obj         * @returns {F}         */        function clone(obj)        {            var F = function ()            {            };            F.prototype = obj;            return new F();        }    </script>

输出:

zhangsan , 12 , Java lisi , 13 , Java,Javascript 

可以看出同样存在引用属性不一致的问题,并且整个操作全部基于对象,给人的感觉不是很好,下面通过图解解释下原理:


对象间通过一个clone函数,不断的返回一个新的对象,且prototype执行传入的对象,整个继承过程其实就是_proto_不断的指向,形成一个链,所以叫做原型链。


好了,已经介绍完了,js的两种集成的方式,最好使用的还是通过类的继承(上述第一种方案,解决存在问题的)。



如果代码或者讲解存在任何问题,欢迎留言指出。




           

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.youkuaiyun.com/jiangjunshow

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值