zoukankan      html  css  js  c++  java
  • Javascript 进阶 继承

    转载请标明出处:http://blog.csdn.net/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的两种集成的方式,最好使用的还是通过类的继承(上述第一种方案,解决存在问题的)。



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


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    二战后的一些战争启示(弱国无外交)
    为了生存人类必须去探索宇宙
    不同版本Eclipse对JDK版本要求
    string 转 java对象、转map的方式
    原生JS实现全选,反选
    oracle批量update
    HttpURLConnection 当作请求调用接口不带返回参数的工具类
    sun.misc.BASE64Encoder在Eclipse中不能直接使用的原因和解决方案
    javamail 发送邮件demo(文字与附件)
    Linux ping不通百度的解决方法
  • 原文地址:https://www.cnblogs.com/dingxiaoyue/p/4924942.html
Copyright © 2011-2022 走看看