码迷,mamicode.com
首页 > Web开发 > 详细

JS 中的 继承

时间:2016-06-22 00:26:58      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:

许多 OO 语言(面向对象语言)都支持两种继承方式:接口继承和实现继承。接口继承只继承方法名,而实现继承则继承实际的方法。

JS只支持实现继承,主要是依靠原型链来实现的。

1、原型链

每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么,我们让原型对象等于另一个类型的实例,
此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针,如此层层递进,就构成了实例与原型的链条。

一种基本的模式:

function SuperType(){
        this.prototype = true;
    }
    SuperType.prototype.getSuperValue = function(){
        return this.prototype;
    }
    function SubType(){
        this.subprototype = false;
    }
    SubType.prototype = new SuperType();
    SubType.prototype.getSubValue = function(){
        return this.subprototype;
    }

    var instance = new SubType();
    alert(instance.getSuperValue());  //true

继承是通过创建 SuperType 的实例,并将该实例赋给SubType.prototype 实现的。实现的本质是重写原型对象,代之以一个新类型的实例。
原来存在于 SuperType 的实例中的所有属性和方法,现在也存在于 SubType.prototype 中了,关系图 如下:
技术分享上面的例子来说,调用
instance.getSuperValue()会经历三个搜索步骤: 1)搜索实例; 2)搜索 SubType.prototype;
3)搜索 SuperType.prototype,最后一步才会找到该方法。在找不到属性或方法的情况下,搜索过程总是要一环一环地前行到原型链末端才会停下来。


默认原型都会包含一个内部指针,指向 Object.prototype。这也正是所有自定义类型都会继承 toString()、valueOf()等默认方法的根本原因。
这是一个完整的原型路径:
技术分享

 

原型和实例的关系

使用 instanceof 操作符,只要用这个操作符来测试实例与原型链中出现过的构造函数,结果就会返回 true。

alert(instance  instanceof  Object)   //true
alert(instance instanceof SuperType); //true
alert(instance instanceof SubType) //true

可以说 instance 是 Object、 SuperType 或 SubType 中任何一个类型的实例。

使用 isPrototypeOf()方法。同样,只要是原型链中出现过的原型,都可以说是该原型链所派生的实例的原型,

alert(Object.prototype.isPrototypeOf(instance)); //true
alert(SuperType.prototype.isPrototypeOf(instance)); //true
alert(SubType.prototype.isPrototypeOf(instance)); //true

谨慎的定义方法

给原型添加方法的代码一定要放在替换原型的语句之后,因为这个是对原型的重写,如果顺序放错了,就出问题了

 

4. 原型链的问题

原型链虽然很强大,可以用它来实现继承,最主要的问题来自包含引用类型值的原型。

function SuperType(){
        this.colors = ["red", "blue", "green"];
    }
    function SubType(){
    }
    //继承了 SuperType
    SubType.prototype = new SuperType();

    var instance1 = new SubType();
    var instance2 = new SubType();

    instance1.colors.push("black");
    alert(instance1.colors); //"red,blue,green,black"
    alert(instance2.colors); //"red,blue,green,black"
当intance1做修改时,就影响了instance2

另一个问题:在创建子类型的实例时,不能向超类型的构造函数中传递参数。

2、借用构造函数实现继承

   function Person(name,age){
        this.color = ["red","yellow","blue"];
        this.name = name;
        this.age = age;
    }
    function Student(name,age){
    //继承了Person Person.apply(
this,arguments); Person.call(this,name,age); } var s1 = new Student("Linda",25); var s2 = new Student("John",32); s1.color.push("black"); alert(s1.color+s1.name); //"red","yellow","blue","black" alert(s2.color+s2.name); //"red","yellow","blue"

借用构造函数有一个很大的优势:  即可以在子类型构造函数中向超类型构造函数传递参数。
借用构造函数的问题: 方法都在构造函数中定义,因此函数复用就无从谈起了。

组合继承

指的是将原型链和借用构造函数的技术组合到一块,使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

function Person(name){
        this.name = name;    
        this.firends = ["A","B","C"];
    }
    Person.prototype.sayName = function(){
        alert(this.name);
    }
    function Student(name,age){
         Person.apply(this,[name]);
    }
    Student.prototype = new Person();
    Student.prototype.constructor = Student;
    Student.prototype.sayAge = function(){
        alert(this.age);
    }
    var s1 = new Student("Linda",25);
    var s2 = new Student("John",32);
    
    s1.sayName();    //"Linda"
    s1.firends.push("D");
    alert(s1.firends);        //"A","B","C","D"
    alert(s2.firends);        //"A","B","C"

组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点,成为 JavaScript 中最常用的继承模式。

原型式继承

 



 

JS 中的 继承

标签:

原文地址:http://www.cnblogs.com/a-lonely-wolf/p/5605452.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!