<script type="text/javascript">

            function People(name){

                    this.name = name;

                    this.job = "程序员";

            }

            //这里是和构造函数模式继承的区别所在,因为把方法定义在了原型对象上。所以可解决函数复用的问题。把可复用的定义在原型对象上,所有实例都可以共享

            //把引用类型的数据定义在构造函数中,就不会共享(每次创建都会分配新的内存空间)

            People.prototype.sayname = function(){

                console.log(this.name);

            }

            function Person(name,age){

                //person继承people方法的属性

                People.call(this,name);

                this.age = age;

            }

            //每次new一个新的上下文,导致引用类型的数据不会共享

            Person.prototype = new People();

            Person.prototype.constructor = Person;

            Person.prototype.sayage = function(){

                console.log(this.age);

            }

            var stu = new Person("prj",21);

            stu.job = "ceo";

            console.log(stu.job);

            stu.sayname();

            stu.sayage();    

            var stu1 = new Person("wxj",20);

            console.log(stu1.job);

            stu1.sayname();

            stu1.sayage();

        </script>

 

  这种方法的名称叫做:组合继承方式。所谓组合是,原型继承和构造函数继承方法的组合。

  单独使用这两种中的任何一个都会有比较明显的问题:原型链继承,会导致超类构造函数中的引用类型数据共享。构造函数模式继承:这种方式,使得函数的可复用性完全丧失,如果一个函数可以重复使用的话,每次都会为这个函数分配空间,如果这样的函数很多的话,就会造成内存空间的浪费。

  组合继承方式集合了他们的优点:原型链方式的函数可复用和构造函数模式的内容封闭,引用类型不会共享。

  唯一有点遗憾的地方是:组合继承最大的 问题就是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是 在子类型构造函数内部。这样的后果是:第一次调用时,会使name属性和job属性出现在实例上,第二次调用会使name属性和job属性出现在原型上。就像这样:

虽然这并不影响我们想要的所有功能,但是精益求精的coder,还是想出了解决办法,就是我们要说的第二种方式:

  寄生组合式继承:

  这种继承方式解决了上面那种方式带来的缺点:上面的缺点在于,让实例出现在了不该出现的地方,归根接底,是在new 构造函数的时候出的问题,因为job属性和name属性,已经出现在了该出现的位置,我们这次只想继承超类的原型。ok,那么我们需要将超类的prototype拷贝一份,送给子类就可以了。

  

     <script type="text/javascript">
            function People(name){
                    this.name = name;
                    this.job = "程序员";
            }
            //这里是和构造函数模式继承的区别所在,因为把方法定义在了原型对象上。所以可解决函数复用的问题。把可复用的定义在原型对象上,所有实例都可以共享
            //把引用类型的数据定义在构造函数中,就不会共享
            People.prototype.sayname = function(){
                console.log(this.name);
            }
            function Person(name,age){
                //person继承people方法的属性
                People.call(this,name);
                this.age = age;
            }
            //每次new一个新的上下文,导致引用类型的数据不会共享
//            Person.prototype = new People();
//            Person.prototype.constructor = Person;

            (function(sub,sup){
                var prototype = sup.prototype;
                prototype.constructor = sub;
                sub.prototype = prototype;
            })(Person,People)
            Person.prototype.sayage = function(){
                console.log(this.age);
            }
            
            var stu = new Person("prj",21);
            stu.job = "ceo";
            console.log(stu.job);
            stu.sayname();
            stu.sayage();
            console.log(stu);
            
            var stu1 = new Person("wxj",20);
            console.log(stu1.job);
            stu1.sayname();
            stu1.sayage();
        </script>

唯一改变的地方在于红色代码部分:使用寄生的方式,将父类的prototype赋值给了子类的prototype;

 

可以发现子类的原型中,没有了name和job属性

 

原创学习博客,欢迎交流,转载说明噢~~~

posted on 2017-12-08 17:36  101-28  阅读(244)  评论(0编辑  收藏  举报