JS的四种持续形式,各类承袭格局

JavaScript 种种持续格局

2017/06/20 · JavaScript
· 继承

原稿出处: Xuthus
Blog   

此伏彼起是面向对象编制程序中又一非常首要的概念,JavaScript帮忙促成延续,不帮衬接口承袭,完成两次三番主要信任原型链来完毕的。

承继是面向对象编制程序中又一丰盛主要的定义,JavaScript支持落到实处持续,不协理接口承接,达成持续首要借助原型链来实现的。

原型链

率先得要精晓哪些是原型链,在一篇小说看懂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”]

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

问题

假若单纯依据构造函数,方法都在构造函数中定义,由此函数无法达标复用

率先得要掌握哪些是原型链,在一篇文章看懂proto和prototype的关系及界别中讲得十分详尽

重组传承(原型链+构造函数)

构成袭继是将原型链传承和构造函数结合起来,进而发挥两岸之长的一种方式。

思路就是使用原型链达成对原型属性和章程的持续,而透过借用构造函数来兑现对实例属性的后续。

那样,既通过在原型上定义方法落成了函数复用,又能够确认保障每一个实例都有它和睦的性格。

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 SuperType() {

寄生式承继

寄生式继承的笔触与寄生构造函数和工厂格局类似,即创办二个仅用于封装承接进度的函数。

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方法。

在重大思考对象并不是自定义类型和构造函数的情事下,那是多个一蹴而就的格局。

  this.property = true

寄生组合式承袭

在后面说的咬合情势(原型链+构造函数)中,继承的时候要求调用两遍父类构造函数。

父类

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

}

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中学。

借用构造函数

此形式为了消除原型中饱含援用类型值所推动的难点。

这种艺术的构思正是在子类构造函数的个中调用父类构造函数,能够借助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

问题

倘使单纯依附构造函数,方法都在构造函数中定义,由此函数一点都不大概直达复用

构成承袭(原型链+构造函数)

结缘承袭是将原型链承继和构造函数结合起来,进而发挥双方之长的一种情势。

思路正是利用原型链完结对原型属性和方法的接续,而透过借用构造函数来完毕对实例属性的继承。

与此相类似,既通过在原型上定义方法完结了函数复用,又能够保证各样实例都有它和睦的习性。

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’

发表评论

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