Js原型链之---继承

1、继承

在其他面向对象的语言,不如JAVAC++中都有继承的概念。那么什么是继承呢?用简单的例子来解释一下:你父亲给你留了很多的钱,则你就继承了你父亲的钱。这就是简单的继承。
javascript中没函数没有签名,所有无法实现接口继承。但在ECMAScript中却是支持实现继承的。怎么实现?

1.1、原型链继承

javascript中将原型链作为实现继承的主要方法。如果对原型链不理解的,可以阅读我之前的文章https://blog.csdn.net/weixin_42714574/article/details/105642837
基本思想:利用原型让一个引用类型继承另一个引用类型的属性和方法。
让我们简单的回顾构造函数、原型和实例的关系:每个构造函数都有一个原型对象prototype,原型对象都包含一个指向构造函数的指针prototype.constructor,而实例都包含一个指向原型对象的内部指针__proto__
那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?

//父级
function Super() {
  this.Supername = 'super'
}
//父类型原型方法
Super.prototype.getSuperName = function () {
  return false
}
// 子类型
function Sub() {
  this.Subname = 'sub'
}
// 将父类型的实例指向了子类型的原型
Sub.prototype = new Super()  //==> var superInstance = new Super()
// 子类型的原型方法
Sub.prototype.getSubName = function () {
  return true
}
//创建子类型实例 
var subInstance = new Sub()
console.log(subInstance.getSuperName())  //false

这就是实现了简单继承,创建父类型的实例,那么父类型的实例就拥有了__proto__指向了父类型的prototype原型,那么将这个实例的指向赋给了子类型的原型,则子类型原型的指向就变为了父类型的原型。下面进行简单验证:

console.log(Sub.prototype.__proto__)  //Super { getSuperName: [Function] }
console.log(superinstance.__proto__)  //Super { getSuperName: [Function] }

实现的本质:是重写原型对象,在Sub构造函数创建的一开始就产生了一个prototype原型。在继承以后,构造函数的原型不在指向一开始的那一个了,代之一个新类型的实例。
这样我们就可以使用Super.prototype上的全部方法和属性,在我们给子类型添加了新方法后,则父类型并不能共享,这是子类型独有的。
此外还是要主要构造器的指向,要注意subInstance.constructor现在的指向是Super,这是因为原型被重写的原因

console.log(subInstance.constructor)  //[Function: Super]

要习惯性的将构造器指向指回原来的构造器

Sub.prototype = new Super()
Sub.prototype.construtor = Sub
console.log(subInstance.constructor) //[Function: Sub]
1.2、同名方法的问题

在此前的例子上Super的原型上有一个getSuperName的方法,那么子类型定义一个同名方法会怎么样?

Sub.prototype.getSuperName = function(){
	return true
}
var subInstance = new Sub()
var superInstance = new Super()
console.log(subInstance.getSuperName())  // true
console.log(subInstance.getSuperName())  // false

在子类型上定义了一个与父类型同名的方法,那么子类型的方法就会把父类型的同名方法覆盖掉。
那么后定义的getSuperName方法实际上只是子类型的方法,并不会影响父类型的方法。

1.3、组合继承方法

在之前的文章有写过原型对象和构造函数方法单独使用产生的问题。在这里简单的提一下。
原型链产生的问题:引用类型的原型属性会被所有的实例共享,当一个实例修改了原型属性的值,则所有实例上的值都会改变,这与实际不符。
构造函数模式:** 避免了原型链遇到的问题,但定义的方法很难被复用**
采用两种模式的组合,就很好的解决了上述问题:
一般来说:原型链实现共享的属性和方法的定义,构造函数实现对实例属性的继承

function Super(name) {
  this.name = name
  this.colors = ['red', 'blue', 'black']
}
Super.prototype.sayName = function () {
  console.log(this.name)
}
function Sub(name, age) {
	//借调了Super的构造函数,类似于java当中的 super(this)
  Super.call(this, name)
  this.age = age
}
Sub.prototype = new Super()
Sub.prototype.constructor = Sub
Sub.prototype.sayAge = function () {
  console.log(this.age)
}

var instance1 = new Sub('Nicholas', 29)
instance1.colors.push('yellow')  
console.log(instance1.colors)  //[ 'red', 'blue', 'black', 'yellow' ]
instance1.sayName()  //Nicholas
instance1.sayAge()  //29

var instance2 = new Sub('Grey', 18)  
console.log(instance2.colors)  //[ 'red', 'blue', 'black' ]
instance2.sayAge() //18
instance2.sayName() //Grey

通过这种组合继承的方法,很好的解决了冲突问题。创建的两个实例的属性和方法互不影响。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值