原型链以及继承的几种方式 - Go语言中文社区

原型链以及继承的几种方式


学习原型链前需要了解

使用构造函数模式创建的对象实例,都有一个constructor(构造函数) 属性,该属性指向构造函数。

function Person (name, age, job) {

  this.name = name;

  this.age = age;

  this.job = job;

  this.sayName = function () {

    alert(this.name)

  }

}

var person1 = new Person(“Nicholas”, 29, “Sofware Engineer”)

var person2 = new Person(“Greg”, 27, “Doctor”)

alert(person1.constructor == Person) // true

alert(person2.constructor == Person) // true

//创建出来的所有对象即使Object的实例,同时也是Person的实例

只要创建一个新函数,就会根据特定的规则为该函数创建一个 prototype 属性,这个属性是一个指针,指向一个对象。这个对象的用途是包含可以由特定类型的 所有实例 共享的属性和方法,这个对象就是通过调用构造函数创建的对象实例的原型对象。

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

原型链
如果让一个原型对象等于另一个类型的实例,层层递进,构成实例与原型的链条,这就是原型链

创建了自定义的构造函数,其原型对象默认只会取得 constructor 属性;其他方法都是从Object 继承来的
当调用构造函数创建一个实例之后,该实例内部会包含一个指针(属性),指向构造函数的原型,我们可以称这个指针为 [[Prototype]]

Function(Object)包含 prototype(原型对象指针)
prototype(原型对象指针)包含constructor(构造函数)属性
constructor(构造函数)属性包含指向原型对象所在函数的指针

继承的几种方式

js主要是通过原型链实现继承,原型链的构建是通过将一个类型的实例赋值给另外一个构造函数的原型实现的

原型链继承

基本代码

function SuperType () {
  this.property = true
}
SuperType.prototype.getSuperValue = function () {
  return this.property
}
function SubType () {
  this.subproperty = false
}
// 继承了SuperType //
SubType.prototype = new SuperType()
SubType.protype.getSubValue = function () {
  return this.subproperty
}
var instance = new SubType()

实现的本质:重写原型对象,用一个新的类型的实例去替代

SubType Prototype === SuperType构造函数的实例
注意:
1.默认的原型
所有的引用类型都默认继承Object,这个继承也是通过原型链实现的

2.原型链的问题
a.对象实例共享所有继承的属性和方法
b.创建子类型的实例的时候,不能传递参数

借用构造函数继承

基本代码

function SuperType () {
  this.colors = ["red", "blue", "green"]
}
function SubType () {
  // 继承了SuperType
  SuperType.call(this)
  // 只能继承构造函数上的属性
}

实现的本质:在子类构造函数的内部调用超类型构造函数,使用aapply()和call() 方法
注意:
1.函数复用性不高
2.只能继承实例上的属性,原型上的方法不可见

组合继承(伪经典继承)

基本代码

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) // 第二次调用SuperType()
  this.age = age
}
//继承方法
SubType.prototype = new SuperType() // 第一次调用 SuperType()
Subtype.prototype.sayAge = function () {
  alert(this.age)
}

实现思路:使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承
注意:
组合继承避免了原型链和借用构造函数的缺陷,融合了他们的优点,成为js中最常用的继承方式。

原型式继承

基本代码

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

实现本质:object()函数对传入其中的对象执行了一次浅复制
注意:
可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅复制,而复制的副本还可以得到进一步的改造
问题还是包含引用类型的属性都会被共享

寄生式继承

基本代码

function createAnother (original) {
  var clone = object(original) // 通过调用函数创建一个新对象
  clone.sayHi = function () { // 以某种方式来增强这个对象
    alert("hi")
  }
  return clone // 返回这个对象
}

实现本质和寄生构造函数还有工厂模式类似
注意:
基于某个对象或者某些信息创建一个对象,然后增强对象,最后返回对象,为了解决组合继承模式由于多次调用超类型构造函数而导致的低效率问题,可以将这个模式与组合继承一起使用

寄生组合式继承

基本代码

function inheritPrototype (subType, superType) {
  var prototype = object(superType.prototype) // 创建对象
  prototype.constructor = subType // 增强对象
  subType.prototype = prototype // 指定对象
}

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
}
inheritPrototype(SubType, SuperType)

 

实现本质:借用构造函数来继承属性,通过原型链的混成形式来继承方法
注意:
高效率只调用了一次构造函数,集寄生式继承和组合继承的优点于一身,是实现基于类型继承的最有效方式

小结:
JavaScript主要通过原型链实现继承。原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的。
使用最多的继承模式是组合继承,这种模式使用原型链继承共享的属性和方法,通过借用构造函数继承实例属性

注:博客新手,文章有误请大家指出,不胜感激

说实话,博客园的编辑器是有点难用

csdn链接:https://blog.csdn.net/weixin_43882226/article/details/88197382 

版权声明:本文来源博客园,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://www.cnblogs.com/8609lql/p/10572518.html
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2019-11-17 15:07:23
  • 阅读 ( 1121 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢