理解JavaScript继承(一)

理解JavaScript继承(一)

我们都知道,面向对象的编程语言非常强大,之所以强大,就是其支持继承。在JavaScript中,也支持继承,而且有多种方法实现继承,比如原型链继承,借用构造函数继承,或者把原型链和借用构造函数函数组合在一起的组合继承,还有直接原型式继承,深浅拷贝继承。下面我就一一来说一说这些继承方法。

1.原型链

首先我们得清楚构造函数(constructor),原型对象(prototype)和实例的三者关系。

每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

function SuperType(){
    this.property = true;
}
        
SuperType.prototype.getSuperValue = function(){
    return this.property;
};
        
function SubType(){
    this.subproperty = false;
}
        
//inherit from SuperType
SubType.prototype = new SuperType();//重写原型对象,赋值为一个实例对象,获得实例对象的所有属性和方法
        
SubType.prototype.getSubValue = function (){
    return this.subproperty;
};

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

原型链的详细请看深入理解原型链一文

2.借用构造函数

function SuperType(){
    this.colors = ["red", "blue", "green"];
}

function SubType(){  
    //inherit from SuperType
    SuperType.call(this);
}

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);    //"red,blue,green,black"
        
var instance2 = new SubType();
alert(instance2.colors);    //"red,blue,green"

通过借用构造函数的方法,会实现对实例属性的继承,每个实例都有它自己的属性,这些属性都是部署在自己身上的,每一个实例对象都有自己的一个副本。改变属性不会对其它实例对象的该属性造成影响。

3.组合继承

组合继承,有时候也叫伪经典继承,指的是将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式。其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。

function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
        
SuperType.prototype.sayName = function(){
    alert(this.name);
};

function SubType(name, age){  
    SuperType.call(this, name);//借用构造函数实现对实例属性的继承,每个实例对象都会创建一个该属性的副本
            
    this.age = age;
}

SubType.prototype = new SuperType();//原型链实现对原型属性和方法的继承,这样它的实例实例对象都会继承原型属性方法,都相当于是指针引用,除非自己重写了一个相同的属性或者方法实现覆盖,否则修改熟悉就会出现原型链中德问题
        
SubType.prototype.sayAge = function(){
    alert(this.age);
};
        
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors);  //"red,blue,green,black"
instance1.sayName();      //"Nicholas";
instance1.sayAge();       //29
        
       
var instance2 = new SubType("Greg", 27);
alert(instance2.colors);  //"red,blue,green"
instance2.sayName();      //"Greg";
instance2.sayAge();       //27`

4.原型式继承

原型式继承并没有使用严格意义上的构造函数,而是借助原型可以基于已有的对象创建新对象,同时还不必创建自定义类型。

function object(o) {
    function F() {}    
    F.prototype = o;  
    return new F();
}

在object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例。本质上,是对传入其中的对象做了一次浅拷贝。

实例

function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}
        
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
        
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
        
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
        
alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"

原型式继承要求你必须有一个对象作为另一个对象的基础,通过把一个对象传递给object()函数,然后再根据具体需求对得到的对象加以修改(修改原来的,或者添加新的属性方法)即可。

在ECMAScript5中,新增了一个Object.create()方法规范了原型式继承,这个方法接受两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的情况下,Object.create()与object()方法的行为相同。

实例

var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
        
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
        
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"

posted @ 2017-01-25 08:53  叶子陪你玩  阅读(284)  评论(0编辑  收藏  举报