JavaScript 继承

ECMAScript只支持实现继承。

原型链

  ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。简单回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。这就是所谓原型链的基本概念。

  通过借用构造函数的方法,在子类型的内部调用超类构造函数。call 或者 apply。

  组合继承

  将原型链和借用构造函数的技术组合到一块,发挥二者的长处。其思路是借助原型链实现对原型方法和属性的继承,借助构造函数实现对实例属性的继承。这样在函数定义上实现了函数的复用,又能保证实例都有自己的属性。

  

//继承
    function Student(name,age,job,banji){
        //继承属性
        PersonByConstructorAndPrototype.call(this,name,age,job);
        this.banji=banji;//特有的属性
    }
    //继承方法
    Student.prototype=new PersonByConstructorAndPrototype();
    Student.prototype.sayBanji=function(){
        console.log(this.banji);
    }

    var Jim=new Student("Jim",12,"","三年级二班");
    // for( var prop in Jim)
    //     console.log(prop);
    Jim.sayName();
    Jim.sayBanji();
View Code

  

  组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点,成为 Java Script 中最常用的继承模式。而且,instanceof 和 is Prototype Of()也能够用于识别基于组合继承创建的对象。

  子类型有时候需要重写超类型中的某个方法,或者需要添加超类型中不存在的某个方法。但不管怎样,给原型添加方法的代码一定要放在替换原型的语句之后。

  在通过原型链实现继承时,不能使用对象字面量创建原型方法。因为这样做就会重写原型链。

原型式继承

  

//原型式继承
    var teacher={
        name:"Nicholas",
        friends:["Jim","Court"]
    };
    function object(o){
        function F(){}
        F.prototype=o;
        return new F();
    }

    var teacherMan=object(teacher);
    teacherMan.name="Mick";
    teacherMan.friends.push("Nicholas");
    console.log(teacherMan.friends);
View Code

ECMAScript通过新增Object.create()方法规范了原型式的继承。这个方法接收两个参数:一个作为新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。

var teacherMan= Object.create(teacher,{
    name:{
    value:"Mick"
    },
    sex:{
        value:"Man"
    },
    girlFriend:{
        value:"Merry"
    }
    }); //object(teacher);
    //teacherMan.name="Mick";
    teacherMan.friends.push("Nicholas");
    console.log(teacherMan.friends);
    console.log(teacherMan.sex);
    console.log(teacherMan.girlFriend);
View Code

在没有必要兴师动众地创建构造函数,而只想让一个对象与另一个对象保持类似的情况下,原型式继承是完全可以胜任的。不过别忘了,包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样。

寄生组合式继承

  组合模式最大的是在任何时候都会调用两次超类的构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

  所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

  

//寄生组合式继承
    function inheritPrototype(subType,superType){
        var prototype=Object.create(superType.prototype); //object(superType.prototype);
        prototype.constructor=subType;        //增强对象
        subType.prototype=prototype;        //指定对象
    }

    
    function teacher1(name){
            this.name=name;
            this.friends=[];
        };

    function teacherWoman(name,sex,boyFriend){
            teacher1.call(this,name);
            this.sex=sex;
            this.boyFriend=boyFriend;
    }
    console.log("********");
    inheritPrototype(teacherWoman,teacher1);
    var Merry=new teacherWoman("Merry","Woman","Mick");
    console.log(Merry.friends);
    Merry.friends.push("Hello Kitty");
    // teacherWoman.friends.push("Jim");
    console.log(Merry.friends);
    console.log(Merry.sex);
    console.log(Merry.boyFriend);
View Code

 

 

 

 

 

 

  

 

 

  

posted @ 2016-01-06 16:18  止水的水  阅读(213)  评论(0编辑  收藏  举报