六种继承方式

图片 1

六种继承方式

JavaScript 多种持续情势

2017/06/20 · JavaScript
· 继承

原稿出处: Xuthus
Blog   

一而再三番五次是面向对象编制程序中又黄金年代那二个关键的概念,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(卡塔尔(英语:State of Qatar)方法的时候,会顺着这条链一贯往上找。

丰盛措施

在给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(卡塔尔(英语:State of Qatar)方法来改换指标的实行上下文

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卡塔尔(英语:State of Qatar) } function SubType(name, job卡塔尔(قطر‎ { // 世袭属性
SuperType.call(this, name卡塔尔国 this.job = job } // 世袭方法
SubType.prototype = new SuperType(卡塔尔 SubType.prototype.constructor =
SuperType SubType.prototype.sayJob = function(卡塔尔(英语:State of Qatar) { 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’卡塔尔(英语:State of Qatar)} return clone // 再次回到那些指标 } var person = { name: ‘Jiang’ } var
anotherPeson = createAnother(person卡塔尔(英语:State of Qatar) anotherPeson.sayHi(卡塔尔(英语:State of Qatar)

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卡塔尔(英语:State of Qatar)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(卡塔尔(英语:State of Qatar)

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 (卡塔尔(英语:State of Qatar) {
console.log(this.name卡塔尔 } function SubType(name, job卡塔尔(قطر‎ { // 世襲属性
SuperType.call(this, name卡塔尔(英语:State of Qatar) this.job = job } // 世襲 SubType.prototype =
Object.create(SuperType.prototype卡塔尔(英语:State of Qatar) // 修复constructor
SubType.prototype.constructor = SubType var instance = new
SubType(‘Jiang’, ‘student’卡塔尔(英语:State of Qatar) 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

admin

网站地图xml地图