JavaScript 中的继承

原文
不像其它语言,js 没有类的概念。它使用原型和原型链来实现继承。如果你不知道什么是原型,请先看这篇文章

原型链

原型链指的是一个对象的 __proto__ 指向另一个对象,而不是指向构造函数。如果这另一个对象的 proto 又继续指向另一个对象,这就会产生一个链式关系,这就是原型链。

这里写图片描述

下面实现一个原型链


//SuperType constructor function
function SuperType(){
    this.name = "Virat"
}

//SuperType prototype
SuperType.prototype.getSuperName = function(){
    return this.name
}

//SubType prototype function
function SubType(){
    this.age = 26
}

//Inherit the properties from SuperType
SubType.prototype = new SuperType();

//Add new property to SubType prototype
SubType.prototype.getSubAge = function(){
    return this.age;
}

//Create a SubType object
var subTypeObj = new SubType();
console.log(subTypeObj.name); //Output: Virat
console.log(subTypeObj.age); //Output: 26
console.log(subTypeObj.getSuperName()); //Output: Virat
console.log(subTypeObj.getSubAge()); //Output: 26

这里写图片描述

上面的代码定义了两个构造函数,SuperTypeSubType 。默认情况下,SubType.prototype 有一个指向构造函数本身的属性 construtor ,一个继承 object 的属性 __proto__

//继承 SuperType 的属性
SubType.prototype = new SuperType();

这行代码覆盖了 SubType 构造函数的默认 prototype 属性,并使得 SubType.prototype 指向了 SuperType 的一个对象。

这意味着, SubType.prototype 拥有了 SuperType 对象的所有属性和方法。

//往 SubType 原型中添加属性
SubType.prototype.getSubAge = function(){
    return this.age;
}

在 SubType 的默认 prototype 被覆盖之后,通过上面这段代码,我们在从 SuperType 继承的基础上往原型对象中增加了一个方法 getSubAge()

注意: 在继承之后,新的方法必须被增加到 SubType 中,因为继承覆盖了 SubType 原有的原型对象。

控制台输出

这里写图片描述

这里写图片描述

这里写图片描述

注意: getSuperName() 方法保留在 SuperType.prototype 对象中,但 name 属性在 SubType.prototype 中。这是因为 getSuperName() 是一个原型对象的方法。SubType.prototype 现在是一个 SuperType 的实例,所以属性被存储在这里。也要注意 SubType.prototype.constructor 指向了 SuperType,因为SubType.prototype 中的 constructor 属性被覆盖了。

原型链的问题

因为所有父类原型的属性都被子类共享,所以如果一个子类对象修改了父类原型的属性,其它的子类对象也会受影响。这个问题经常被抱怨。

要解决这个问题,我们在构造函数中继承实例属性,用原型链继承公共的属性和方法。


//SuperType constructor function
function SuperType(firstName, lastName){
    this.firstName = "Virat",
    this.lastName = "Kohli",
    this.friends = ["Ashwin", "Jadeja"]
}

//SuperType prototype
SuperType.prototype.getSuperName = function(){
    return this.firstName + " " + this.lastName;
}

//SubType prototype function
function SubType(firstName, lastName, age){
    //Inherit instance properties
    SuperType.call(this, firstname, lastName);
    this.age = age;
}

//Inherit methods and shared properties
SubType.prototype = new SuperType();

//Add new property to SubType prototype
SubType.prototype.getSubAge = function(){
    return this.age;
}

//Create SubType objects
var subTypeObj1= new SubType("Virat", "Kohli", 26);
var subTypeObj2 = new SubType("Sachin", "Tendulkar", 39);

//Modify the friends property using the subTypeObj1
subTypeObj1.friends.push("Amit");

console.log(subTypeObj1.friends);//["Ahswin", "Jadega", "Amit"]
console.log(subTypeObj2.friends);//["Ashwin", "Jadega"]

//subTypeObj1
console.log(subTypeObj1.firstName); //Output: Virat
console.log(subTypeObj1.age); //Output: 26
console.log(subTypeObj1.getSuperName()); //Output: Virat Kohli
console.log(subTypeObj1.getSubAge()); //Output: 26

//subTypeObj2
console.log(subTypeObj2.firstName); //Output: Sachin
console.log(subTypeObj2.age); //Output: 39
console.log(subTypeObj2.getSuperName()); //Output: Sachin Tendulkar
console.log(subTypeObj2.getSubAge()); //Output: 39

现在来分析一下上面的代码。首先,我们定义了 SuperType 构造函数,它有三个属性 firstName, lastNamefriends,这三个属性是实例属性,然后我们在 SuperType 的原型上定义了 getSuperName 方法。

现在,让我们来看一下如何定义 SubType 构造函数

//SubType prototype function
function SubType(firstName, lastName, age){
    //Inherit instance properties
    SuperType.call(this, firstname, lastName);
    this.age = age;
}

这里我们定义了 SubType 构造函数,在构造函数里面,我们使用 call 调用了 SuperType 构造函数。通过执行 call 的调用,我们在这个被创建的 SubType 实例对象的上下文中执行了 SuperType 的构造函数。在继承 SuperType 的实例属性之后,我们增加了一个 age 属性到 SubType 的构造函数中。

//继承公共方法和属性
SubType.prototype = new SuperType();

到此为止我们仅仅继承了 SuperType 的实例属性,但是公共的属性和方法没有继承,我们通过上面这行代码继承它们。

一旦执行了上面的代码,我们继承了 SuperType 构造函数的所有属性。

//增加新属性到原型中
SubType.prototype.getSubAge = function(){
    return this.age;
}

通过上面这行代码我们增加了在从 SuperType 中继承的属性中又增加了一个新的属性。

下面我们通过创建一个 SubType 实例来理解这个过程。

var subTypeObj1= new SubType("Virat", "Kohli", 26);

执行上面这行代码之后,三个参数 (”Virat”, “Kohli”, 26)被传递到 SubType 构造函数中。SubType 构造函数通过 SuperType.call(this, firstname, lastName) 调用了 SuperType 构造函数,SuperType 构造函数在 subTypeObj1 的上下文中执行,随之增加 firstName, lastName, friends 属性到 subTypeObj1 对象中。在 SuperType.call(this, firstname, lastName) 之后,SubType 构造函数增加了 age 属性到 subTypeObj1 对象中。

因此目前 subTypeObj1 对象拥有 firstName,lastName ,friends 和 age 属性。此时 SubType 构造函数有如下公共的属性和方法:

  1. getSuperName
  2. getSubAge

subTypeObj1 从 SubType 构造函数中继承上面所有属性。

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值