• 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的两种集成的方式,最好使用的还是通过类的继承(上述第一种方案,解决存在问题的)。



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


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

  • 相关阅读:
    Max History CodeForces
    Buy a Ticket CodeForces
    AC日记——字符串的展开 openjudge 1.7 35
    AC日记——回文子串 openjudge 1.7 34
    AC日记——判断字符串是否为回文 openjudge 1.7 33
    AC日记——行程长度编码 openjudge 1.7 32
    AC日记——字符串P型编码 openjudge 1.7 31
    AC日记——字符环 openjudge 1.7 30
    AC日记——ISBN号码 openjudge 1.7 29
    AC日记——单词倒排 1.7 28
  • 原文地址:https://www.cnblogs.com/dingxiaoyue/p/4924942.html
Copyright © 2020-2023  润新知