菜单

JavaScript 六栽持续方式

2018年11月16日 - JavaScript

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这个引用类型值,也会见体现到instance2中。

假构造函数

这个方法为解决原型中含引用类型值所带的问题。

这种艺术的思想就是当子类构造函数的里调用父类构造函数,可以借助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’

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

相关文章

发表评论

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

网站地图xml地图