澳门太阳集团登录网址 1

javaScript继承方式,六种继承方式

JavaScript 各类持续格局

2017/06/20 · JavaScript
· 继承

初藳出处: Xuthus
Blog   

继续是面向对象编制程序中又一不行重要的概念,JavaScript帮衬落到实处接二连三,不辅助接口世袭,实现持续首要依赖原型链来达成的。

原型链世袭基本思想便是让二个原型对象指向另一个体系的实例

function SuperType() {
this.property = true
}
SuperType.prototype.getSuperValue = function () {
return this.property
}
function SubType() {
this.subproperty = false
}
SubType.prototype = new SuperType()
SubType.prototype.getSubValue = function () {
return this.subproperty
}
var instance = new SubType()
console.log(instance.getSuperValue()) // true

代码定义了多少个门类SuperType和SubType,每种门类分别有一个脾性和一个主意,SubType世襲了SuperType,而接二连三是因此创立SuperType的实例,并将该实例赋给SubType.prototype达成的。

兑现的本质是重写原型对象,代之以二个新品类的实例,那么存在SuperType的实例中的全体属性和方式,将来也存在于SubType.prototype中了。

大家精通,在开创三个实例的时候,实例对象中会有三当中间指针指向创制它的原型,进行关联起来,在这里间代码SubType.prototype
= new
SuperType(),也会在SubType.prototype制造一个里边指针,将SubType.prototype与SuperType关联起来。

故此instance指向SubType的原型,SubType的原型又指向SuperType的原型,进而在instance在调用getSuperValue()方法的时候,会顺着这条链一向往上找。

增加情势

在给SubType原型增多方法的时候,假设,父类上也会有平等的名字,SubType将会覆盖那些方法,达到重新的目标。
不过其大器晚成法子依然存在于父类中。

切记不可能以字面量的花样丰盛,因为,上边说过通超过实际例世襲本质上正是重写,再使用字面量情势,又是贰遍重写了,但这一次重写未有跟父类有任何关系,所以就能够形成原型链截断。

function SuperType() {
this.property = true
}
SuperType.prototype.getSuperValue = function () {
return this.property
}
function SubType() {
this.subproperty = false
}
SubType.prototype = new SuperType()
SubType.prototype = {
getSubValue:function () {
return this.subproperty
}
}
var instance = new SubType()
console.log(instance.getSuperValue()) // error

问题

唯有的接收原型链世袭,主要难点来自包括引用类型值的原型。

function SuperType() {
this.colors = [澳门太阳集团登录网址,’red’, ‘blue’, ‘green’]
}
function SubType() {
}
SubType.prototype = new SuperType()
var instance1 = new SubType()
var instance2 = new SubType()
instance1.colors.push(‘black’)
console.log(instance1.colors) // [“red”, “blue”, “green”, “black”]
console.log(instance2.colors) // [“red”, “blue”, “green”, “black”]

在SuperType构造函数定义了贰个colors属性,当SubType通过原型链世袭后,那些天性就能够产出SubType.prototype中,就跟特意创制了SubType.prototype.colors相像,所以会变成SubType的兼具实例都会分享这几个天性,所以instance1校勘colors这几个援引类型值,也会反映到instance第22中学。

原型链

率先得要清楚哪些是原型链,在风流罗曼蒂克篇小说看懂proto和prototype的关系及界别中讲得老大详细

原型链世襲基本思维便是让三个原型对象指向另三个连串的实例

function SuperType() { this.property = true }
SuperType.prototype.getSuperValue = function () { return this.property }
function SubType() { this.subproperty = false } SubType.prototype = new
SuperType() SubType.prototype.getSubValue = function () { return
this.subproperty } var instance = new SubType()
console.log(instance.getSuperValue()) // true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function SuperType() {
  this.property = true
}
SuperType.prototype.getSuperValue = function () {
  return this.property
}
function SubType() {
  this.subproperty = false
}
SubType.prototype = new SuperType()
SubType.prototype.getSubValue = function () {
  return this.subproperty
}
var instance = new SubType()
console.log(instance.getSuperValue()) // true

代码定义了三个门类SuperType和SubType,每个种类分别有六特性情和三个措施,SubType世袭了SuperType,而三回九转是透过创办SuperType的实例,并将该实例赋给SubType.prototype实现的。

兑现的精气神是重写原型对象,代之以三个新品类的实例,那么存在SuperType的实例中的全数属性和情势,未来也存在于SubType.prototype中了。

咱俩知道,在创制叁个实例的时候,实例对象中会有二个里边指针指向创制它的原型,进行关联起来,在那代码SubType.prototype = new SuperType(),也会在SubType.prototype创设一个里面指针,将SubType.prototype与SuperType关联起来。

为此instance指向SubType的原型,SubType的原型又指向SuperType的原型,进而在instance在调用getSuperValue()方法的时候,会顺着这条链一向往上找。

增添形式

在给SubType原型增添方法的时候,假若,父类上也可以有同豆蔻年华的名字,SubType将会覆盖那几个主意,达到重新的目标。
不过其生龙活虎措施还是留存于父类中。

纪事不可能以字面量的情势丰裕,因为,上边说过通超过实际例世袭本质上正是重写,再选择字面量方式,又是一回重写了,但这一次重写未有跟父类有任何涉及,所以就可以诱致原型链截断。

function SuperType() { this.property = true }
SuperType.prototype.getSuperValue = function () { return this.property }
function SubType() { this.subproperty = false } SubType.prototype = new
SuperType() SubType.prototype = { getSubValue:function () { return
this.subproperty } } var instance = new SubType()
console.log(instance.getSuperValue()) // error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function SuperType() {
  this.property = true
}
SuperType.prototype.getSuperValue = function () {
  return this.property
}
function SubType() {
  this.subproperty = false
}
SubType.prototype = new SuperType()
SubType.prototype = {
  getSubValue:function () {
   return this.subproperty
  }
}
var instance = new SubType()
console.log(instance.getSuperValue())  // error

问题

独有的应用原型链世袭,首要难题根源包罗征引类型值的原型。

function SuperType() { this.colors = [‘red’, ‘blue’, ‘green’] }
function SubType() { } SubType.prototype = new SuperType() var instance1
= new SubType() var instance2 = new SubType()
instance1.colors.push(‘black’) console.log(instance1.colors) // [“red”,
“blue”, “green”, “black”] console.log(instance2.colors) // [“red”,
“blue”, “green”, “black”]

1
2
3
4
5
6
7
8
9
10
11
function SuperType() {
  this.colors = [‘red’, ‘blue’, ‘green’]
}
function SubType() {
}
SubType.prototype = new SuperType()
var instance1 = new SubType()
var instance2 = new SubType()
instance1.colors.push(‘black’)
console.log(instance1.colors)  // ["red", "blue", "green", "black"]
console.log(instance2.colors) // ["red", "blue", "green", "black"]

在SuperType构造函数定义了二个colors属性,当SubType通过原型链世袭后,那几个脾性就能够并发SubType.prototype中,就跟专门创造了SubType.prototype.colors同样,所以会以致SubType的富有实例都会分享那天本性,所以instance1改革colors这么些引用类型值,也会展现到instance第22中学。

借用构造函数

此办法为了减轻原型中含有引用类型值所带给的主题材料。

这种办法的构思就是在子类构造函数的内部调用父类构造函数,能够依靠apply()和call()方法来改变指标的执行上下文

function SuperType() {
this.colors = [‘red’, ‘blue’, ‘green’]
}
function SubType() {
// 继承SuperType
SuperType.call(this)
}
var instance1 = new SubType()
var instance2 = new SubType()
instance1.colors.push(‘black’)
console.log(instance1.colors) // [“red”, “blue”, “green”, “black”]
console.log(instance2.colors) // [“red”, “blue”, “green”]

在新建SubType实例是调用了SuperType构造函数,那样来说,就能够在新SubType目的上实行SuperType函数中定义的全体目的早先化代码。

结果,SubType的种种实例就能够具有友好的colors属性的别本了。

传送参数

依靠于构造函数还恐怕有三个优势正是能够传递参数

function SuperType(name) {
this.name = name
}
function SubType() {
// 继承SuperType
SuperType.call(this, ‘Jiang’)
this.job = ‘student’
}
var instance = new SubType()
console.log(instance.name) // Jiang
console.log(instance.job) // student

问题

固然唯有依附构造函数,方法都在构造函数中定义,由此函数不能达到复用

借用构造函数

此办法为了解决原型中带有援引类型值所带动的标题。

这种措施的思索正是在子类构造函数的里边调用父类构造函数,能够依赖apply()和call()方法来改换目的的实践上下文

function SuperType() { this.colors = [‘red’, ‘blue’, ‘green’] }
function SubType() { // 继承SuperType SuperType.call(this) } var
instance1 = new SubType() var instance2 = new SubType()
instance1.colors.push(‘black’) console.log(instance1.colors) // [“red”,
“blue”, “green”, “black”] console.log(instance2.colors) // [“red”,
“blue”, “green”]

1
2
3
4
5
6
7
8
9
10
11
12
function SuperType() {
  this.colors = [‘red’, ‘blue’, ‘green’]
}
function SubType() {
  // 继承SuperType
  SuperType.call(this)
}
var instance1 = new SubType()
var instance2 = new SubType()
instance1.colors.push(‘black’)
console.log(instance1.colors)  // ["red", "blue", "green", "black"]
console.log(instance2.colors) // ["red", "blue", "green"]

在新建SubType实例是调用了SuperType构造函数,那样以来,就能够在新SubType目的上推行SuperType函数中定义的有着目的初步化代码。

结果,SubType的每种实例就集会场全部本人的colors属性的别本了。

传递参数

依靠构造函数还恐怕有三个优势便是能够传递参数

function SuperType(name) { this.name = name } function SubType() { //
继承SuperType SuperType.call(this, ‘Jiang’) this.job = ‘student’ } var
instance = new SubType() console.log(instance.name) // Jiang
console.log(instance.job) // student

1
2
3
4
5
6
7
8
9
10
11
12
function SuperType(name) {
  this.name = name
}
function SubType() {
  // 继承SuperType
  SuperType.call(this, ‘Jiang’)
 
  this.job = ‘student’
}
var instance = new SubType()
console.log(instance.name)  // Jiang
console.log(instance.job)   // student

问题

假设单纯信任构造函数,方法都在构造函数中定义,由此函数无法直达复用

构成世襲(原型链+构造函数)

整合世襲是将原型链世襲和构造函数结合起来,从而发挥两岸之长的生龙活虎种格局。

思路就是接纳原型链完结对原型属性和艺术的接轨,而透过借用构造函数来兑现对实例属性的存在延续。

如此,既通过在原型上定义方法完毕了函数复用,又能够保险种种实例都有它自身的性子。

function SuperType(name) {
this.name = name
this.colors = [‘red’, ‘blue’, ‘green’]
}
SuperType.prototype.sayName = function () {
console.log(this.name)
}
function SubType(name, job) {
// 世襲属性
SuperType.call(this, name)
this.job = job
}
// 世袭方法
SubType.prototype = new SuperType()
SubType.prototype.constructor = SuperType
SubType.prototype.sayJob = function() {
console.log(this.job)
}
var instance1 = new SubType(‘Jiang’, ‘student’)
instance1.colors.push(‘black’)
console.log(instance1.colors) //[“red”, “blue”, “green”, “black”]
instance1.sayName() // ‘Jiang’
instance1.sayJob() // ‘student’
var instance2 = new SubType(‘J’, ‘doctor’)
console.log(instance2.colors) // //[“red”, “blue”, “green”]
instance2.sayName() // ‘J’
instance2.sayJob() // ‘doctor’

这种方式防止了原型链和构造函数世襲的欠缺,融入了她们的优点,是最常用的大器晚成种持续方式。

组合世襲(原型链+构造函数)

结缘继承是将原型链世襲和构造函数结合起来,进而发挥两岸之长的生龙活虎种形式。

思路便是利用原型链达成对原型属性和办法的接轨,而透过借用构造函数来落到实处对实例属性的存在延续。

那样,既通过在原型上定义方法完结了函数复用,又能够保障每一个实例都有它和煦的性质。

function SuperType(name) { this.name = name this.colors = [‘red’,
‘blue’, ‘green’] } SuperType.prototype.sayName = function () {
console.log(this.name) } function SubType(name, job) { // 世襲属性
SuperType.call(this, name) this.job = job } // 继承方法
SubType.prototype = new SuperType() SubType.prototype.constructor =
SuperType SubType.prototype.sayJob = function() { console.log(this.job)
} var instance1 = new SubType(‘Jiang’, ‘student’)
instance1.colors.push(‘black’) console.log(instance1.colors) //[“red”,
“blue”, “green”, “black”] instance1.sayName() // ‘Jiang’
instance1.sayJob() // ‘student’ var instance2 = new SubType(‘J’,
‘doctor’) console.log(instance2.colors) // //[“red”, “blue”, “green”]
instance2.sayName() // ‘J’ instance2.sayJob() // ‘doctor’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function SuperType(name) {
  this.name = name
  this.colors = [‘red’, ‘blue’, ‘green’]
}
SuperType.prototype.sayName = function () {
  console.log(this.name)
}
function SubType(name, job) {
  // 继承属性
  SuperType.call(this, name)
 
  this.job = job
}
// 继承方法
SubType.prototype = new SuperType()
SubType.prototype.constructor = SuperType
SubType.prototype.sayJob = function() {
  console.log(this.job)
}
var instance1 = new SubType(‘Jiang’, ‘student’)
instance1.colors.push(‘black’)
console.log(instance1.colors) //["red", "blue", "green", "black"]
instance1.sayName() // ‘Jiang’
instance1.sayJob()  // ‘student’
var instance2 = new SubType(‘J’, ‘doctor’)
console.log(instance2.colors) // //["red", "blue", "green"]
instance2.sayName()  // ‘J’
instance2.sayJob()  // ‘doctor’

这种情势幸免了原型链和构造函数世襲的败笔,融合了她们的长处,是最常用的风华正茂种持续情势。

原型式世袭

依傍原型能够依照原来就有的对象创造新目的,同偶尔间还不用为此创制自定义类型。

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

1
2
3
4
5
function object(o) {
  function F() {}
  F.prototype = o
  return new F()
}

在object函数内部,先创建二个有的时候性的构造函数,然后将盛传的靶子作为那个构造函数的原型,最后回到那么些一时类型的二个新实例。

实为上来讲,object对传播此中的靶子施行了贰遍浅复制。

var person = { name: ‘Jiang’, friends: [‘Shelby’, ‘Court’] } var
anotherPerson = object(person) console.log(anotherPerson.friends) //
[‘Shelby’, ‘Court’]

1
2
3
4
5
6
var person = {
  name: ‘Jiang’,
  friends: [‘Shelby’, ‘Court’]
}
var anotherPerson = object(person)
console.log(anotherPerson.friends)  // [‘Shelby’, ‘Court’]

这种方式要去你必得有二个对象作为另二个目的的底子。

在这里个事例中,person作为另多少个指标的底工,把person传入object中,该函数就能够回去四个新的对象。

其风流罗曼蒂克新对象将person作为原型,所以它的原型中就包括一个主干项目和二个引用类型。

据此意味着生机勃勃旦还会有此外叁个对象关联了person,anotherPerson改正数组friends的时候,也会反映在此个目的中。

Object.create()方法

ES5因而Object.create()方法则范了原型式世袭,能够选取三个参数,三个是用作新对象原型的目的和二个可选的为新目的定义额外属性的靶子,行为等同,基本用法和方面的object相同,除了object无法选用第二个参数以外。

var person = { name: ‘Jiang’, friends: [‘Shelby’, ‘Court’] } var
anotherPerson = Object.create(person) console.log(anotherPerson.friends)
// [‘Shelby’, ‘Court’]

1
2
3
4
5
6
var person = {
  name: ‘Jiang’,
  friends: [‘Shelby’, ‘Court’]
}
var anotherPerson = Object.create(person)
console.log(anotherPerson.friends)  // [‘Shelby’, ‘Court’]

寄生式世袭

寄生式世襲的思绪与寄生构造函数和工厂形式雷同,即开立二个仅用于封装世袭进度的函数。

function createAnother(o) { var clone = Object.create(o) //
创制贰个新对象 clone.sayHi = function() { // 增多措施 console.log(‘hi’)
} return clone // 再次来到这几个指标 } var person = { name: ‘Jiang’ } var
anotherPeson = createAnother(person) anotherPeson.sayHi()

1
2
3
4
5
6
7
8
9
10
11
12
function createAnother(o) {
  var clone = Object.create(o) // 创建一个新对象
  clone.sayHi = function() { // 添加方法
    console.log(‘hi’)
  }
  return clone  // 返回这个对象
}
var person = {
  name: ‘Jiang’
}
var anotherPeson = createAnother(person)
anotherPeson.sayHi()

基于person重临了二个新目的anotherPeson,新目的不唯有抱有了person的脾气和方法,还大概有团结的sayHi方法。

在尤为重要思虑对象实际不是自定义类型和构造函数的状态下,那是贰个使得的情势。

寄生组合式世襲

在近日说的整合格局(原型链+构造函数)中,世襲的时候供给调用一次父类构造函数。

父类

function SuperType(name) { this.name = name this.colors = [‘red’,
‘blue’, ‘green’] }

1
2
3
4
function SuperType(name) {
  this.name = name
  this.colors = [‘red’, ‘blue’, ‘green’]
}

首先次在子类构造函数中

function SubType(name, job) { // 世袭属性 SuperType.call(this, name)
this.job = job }

1
2
3
4
5
6
function SubType(name, job) {
  // 继承属性
  SuperType.call(this, name)
 
  this.job = job
}

第二回将子类的原型指向父类的实例

// 世襲方法 SubType.prototype = new SuperType()

1
2
// 继承方法
SubType.prototype = new SuperType()

当使用var instance = new SubType()的时候,会发生两组name和color属性,后生可畏组在SubType实例上,风度翩翩组在SubType原型上,只不超过实际例上的屏蔽了原型上的。

利用寄生式组合形式,能够规避这些难题。

这种情势通过借用构造函数来继续属性,通过原型链的混成方式来一连方法。

基本思路:不必为了钦赐子类型的原型而调用父类的构造函数,大家须要的单纯正是父类原型的八个别本。

本质上便是应用寄生式世襲来三回九转父类的原型,在将结果钦命给子类型的原型。

function inheritPrototype(subType, superType) { var prototype =
Object.create(superType.prototype) prototype.constructor = subType
subType.prototype = prototype }

1
2
3
4
5
function inheritPrototype(subType, superType) {
  var prototype = Object.create(superType.prototype)
  prototype.constructor = subType
  subType.prototype = prototype
}

该函数达成了寄生组合世襲的最简便款式。

本条函数选拔四个参数,四个子类,三个父类。

先是步创建父类原型的别本,第二步将成立的别本增多constructor属性,第三部将子类的原型指向那么些别本。

function SuperType(name) { this.name = name this.colors = [‘red’,
‘blue’, ‘green’] } SuperType.prototype.sayName = function () {
console.log(this.name) } function SubType(name, job) { // 世袭属性
SuperType.call(this, name) this.job = job } // 世襲inheritPrototype(SubType, SuperType) var instance = new SubType(‘Jiang’,
‘student’) instance.sayName()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function SuperType(name) {
  this.name = name
  this.colors = [‘red’, ‘blue’, ‘green’]
}
SuperType.prototype.sayName = function () {
  console.log(this.name)
}
function SubType(name, job) {
  // 继承属性
  SuperType.call(this, name)
 
  this.job = job
}
// 继承
inheritPrototype(SubType, SuperType)
var instance = new SubType(‘Jiang’, ‘student’)
instance.sayName()

补偿:直接动用Object.create来促成,其实正是将方面封装的函数拆开,那样演示可以更便于精通。

function SuperType(name) { this.name = name this.colors = [‘red’,
‘blue’, ‘green’] } SuperType.prototype.sayName = function () {
console.log(this.name) } function SubType(name, job) { // 世袭属性
SuperType.call(this, name) this.job = job } // 世襲 SubType.prototype =
Object.create(SuperType.prototype) // 修复constructor
SubType.prototype.constructor = SubType var instance = new
SubType(‘Jiang’, ‘student’) instance.sayName()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function SuperType(name) {
  this.name = name
  this.colors = [‘red’, ‘blue’, ‘green’]
}
SuperType.prototype.sayName = function () {
  console.log(this.name)
}
function SubType(name, job) {
  // 继承属性
  SuperType.call(this, name)
 
  this.job = job
}
// 继承
SubType.prototype = Object.create(SuperType.prototype)
// 修复constructor
SubType.prototype.constructor = SubType
var instance = new SubType(‘Jiang’, ‘student’)
instance.sayName()

ES6新添了三个方法,Object.setPrototypeOf,能够一贯开立关联,并且不用手动增加constructor属性。

// 继承 Object.setPrototypeOf(SubType.prototype, SuperType.prototype)
console.log(SubType.prototype.constructor === SubType) // true

1
2
3
// 继承
Object.setPrototypeOf(SubType.prototype, SuperType.prototype)
console.log(SubType.prototype.constructor === SubType) // true

1 赞 2 收藏
评论

澳门太阳集团登录网址 1

发表评论

电子邮件地址不会被公开。 必填项已用*标注