菜单

JavaScript承袭格局(4)

2019年10月13日 - Ajax

JavaScript 多种持续形式

2017/06/20 · JavaScript
· 继承

原稿出处: Xuthus
Blog
   

承接是面向对象编制程序中又一可怜首要的定义,JavaScript帮忙促成持续,不帮助接口承接,落成持续首要信任原型链来落成的。

4,承袭工具函数四

原型链

先是得要知道怎么是原型链,在一篇小说看懂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中学。

view sourceprint?01 /** 

借用构造函数

此情势为了消除原型中饱含引用类型值所拉动的难题。

这种办法的思辨正是在子类构造函数的在那之中调用父类构造函数,能够依据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

问题

比如唯有注重构造函数,方法都在构造函数中定义,由此函数无法达到复用

02  * @param {String} className 

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

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

思路就是使用原型链达成对原型属性和办法的接轨,而通过借用构造函数来促成对实例属性的存在延续。

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

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’

这种形式幸免了原型链和构造函数承袭的劣势,融入了她们的优点,是最常用的一种持续格局。

03  * @param {String/Function} superClass 

原型式承继

依赖原型能够依照已有的对象成立新目的,同时还不用因而创造自定义类型。

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’]

04  * @param {Function} classImp 

寄生式承继

寄生式传承的思绪与寄生构造函数和工厂形式类似,即开立三个仅用于封装承继进程的函数。

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

在重大思量对象实际不是自定义类型和构造函数的动静下,那是三个立见成效的方式。

05  */

寄生组合式承接

在前面说的重组格局(原型链+构造函数)中,承接的时候要求调用一遍父类构造函数。

父类

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

06 function $class(className, superClass, classImp){ 

07     if(superClass === “”) superClass = Object; 

08     var clazz = function(){ 

09         return function(){ 

10             if(typeof this.init == “function”){ 

11                 this.init.apply(this, arguments); 

12             } 

13         }; 

14     }(); 

15     var p = clazz.prototype = new superClass(); 

16     var _super = superClass.prototype; 

17     window[className] = clazz; 

18     classImp.apply(p, [_super]); 

19 }

概念父类Person

view sourceprint?01 /** 

02  * 父类 Person 

03  */

04 $class(Person,,function(){ 

05     this.init = function(name){ 

06         this.name = name; 

07     }; 

08     this.getName = function(){ 

09         return this.name; 

10     }; 

11     this.setName = function(name){ 

12         this.name = name; 

13     } 

14 });

子类Man

view sourceprint?01 /** 

02  * 子类 Man 

03  */

04 $class(Man, Person, function(supr){ 

05     this.init = function(name, age){ 

06         supr.init.apply(this,[name]); // 该句非常重要 

07         this.age = age; 

08     }; 

09     this.getAge = function(){ 

10         return this.age; 

11     }; 

12     this.setAge = function(age){ 

13         this.age = age; 

14     }; 

15 }); 

16 var m = new Man(Jack,25); 

17 console.log(m.name); // Jack 

18 console.log(m.age); // 25

从输出看能够看看子类Man的确承继了父类的属性和办法

http://www.bkjia.com/Javascript/508051.htmlwww.bkjia.comtruehttp://www.bkjia.com/Javascript/508051.htmlTechArticle4,继承工具函数四 view sourceprint?01 /** 02 *
@param {String} className 03 * @param {String/Function} superClass 04
* @param {Function} classImp 05 */ 06 function $class(c…

相关文章

发表评论

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

网站地图xml地图