99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

JavaScript六種繼承方式

發(fā)布時(shí)間:2017-06-13 18:27  回復(fù):0  查看:1782   最后回復(fù):2017-06-13 18:27  

本文和大家分享的主要是javascript中繼承相關(guān)內(nèi)容,一起來看看吧,希望對大家學(xué)習(xí)javascript有所幫助。

  繼承是面向?qū)ο缶幊讨杏忠环浅V匾母拍睿?/span>JavaScript支持實(shí)現(xiàn)繼承,不支持接口繼承,實(shí)現(xiàn)繼承主要依靠原型鏈來實(shí)現(xiàn)的

  原型鏈

  原型鏈繼承基本思想就是讓一個(gè)原型對象指向另一個(gè)類型的實(shí)例

  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

  代碼定義了兩個(gè)類型SuperTypeSubType,每個(gè)類型分別有一個(gè)屬性和一個(gè)方法,SubType繼承了SuperType,而繼承是通過創(chuàng)建SuperType的實(shí)例,并將該實(shí)例賦給SubType.prototype實(shí)現(xiàn)的

  實(shí)現(xiàn)的本質(zhì)是重寫原型對象,代之以一個(gè)新類型的實(shí)例,那么存在SuperType的實(shí)例中的所有屬性和方法,現(xiàn)在也存在于SubType.prototype中了

  我們知道,在創(chuàng)建一個(gè)實(shí)例的時(shí)候,實(shí)例對象中會(huì)有一個(gè)內(nèi)部指針指向創(chuàng)建它的原型,進(jìn)行關(guān)聯(lián)起來,在這里代碼 SubType.prototype = new SuperType() ,也會(huì)在SubType.prototype創(chuàng)建一個(gè)內(nèi)部指針,將SubType.prototypeSuperType關(guān)聯(lián)起來

  所以instance指向SubType的原型,SubType的原型又指向SuperType的原型,繼而在instance在調(diào)用getSuperValue()方法的時(shí)候,會(huì)順著這條鏈一直往上找

  添加方法

  在給SubType原型添加方法的時(shí)候,如果,父類上也有同樣的名字,SubType將會(huì)覆蓋這個(gè)方法,達(dá)到重新的目的。 但是這個(gè)方法依然存在于父類中

  記住不能以字面量的形式添加,因?yàn)?,上面說過通過實(shí)例繼承本質(zhì)上就是重寫,再使用字面量形式,又是一次重寫了,但這次重寫沒有跟父類有任何關(guān)聯(lián),所以就會(huì)導(dǎo)致原型鏈截?cái)?/span>

  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構(gòu)造函數(shù)定義了一個(gè)colors屬性,當(dāng)SubType通過原型鏈繼承后,這個(gè)屬性就會(huì)出現(xiàn)SubType.prototype中,就跟專門創(chuàng)建了SubType.prototype.colors一樣,所以會(huì)導(dǎo)致SubType的所有實(shí)例都會(huì)共享這個(gè)屬性,所以instance1修改colors這個(gè)引用類型值,也會(huì)反映到instance2

  借用構(gòu)造函數(shù)

  此方法為了解決原型中包含引用類型值所帶來的問題

  這種方法的思想就是在子類構(gòu)造函數(shù)的內(nèi)部調(diào)用父類構(gòu)造函數(shù),可以借助apply()call()方法來改變對象的執(zhí)行上下文

  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實(shí)例是調(diào)用了SuperType構(gòu)造函數(shù),這樣以來,就會(huì)在新SubType對象上執(zhí)行SuperType函數(shù)中定義的所有對象初始化代碼

  結(jié)果,SubType的每個(gè)實(shí)例就會(huì)具有自己的colors屬性的副本了

  傳遞參數(shù)

  借助構(gòu)造函數(shù)還有一個(gè)優(yōu)勢就是可以傳遞參數(shù)

  function SuperType(name){

  this.name = name

  }

  function SubType(){

  // 繼承SuperType

  SuperType.call(this, 'Jiang')

  this.job = 'student'

  }

  var instance = new SubType()console.log(instance.name)  // Jiangconsole.log(instance.job)   // student

  問題

  如果僅僅借助構(gòu)造函數(shù),方法都在構(gòu)造函數(shù)中定義,因此函數(shù)無法達(dá)到復(fù)用

  組合繼承(原型鏈+構(gòu)造函數(shù))

  組合繼承是將原型鏈繼承和構(gòu)造函數(shù)結(jié)合起來,從而發(fā)揮二者之長的一種模式

  思路就是使用原型鏈實(shí)現(xiàn)對原型屬性和方法的繼承,而通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對實(shí)例屬性的繼承

  這樣,既通過在原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用,又能夠保證每個(gè)實(shí)例都有它自己的屬性

  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'

  這種模式避免了原型鏈和構(gòu)造函數(shù)繼承的缺陷,融合了他們的優(yōu)點(diǎn),是最常用的一種繼承模式

  原型式繼承

  借助原型可以基于已有的對象創(chuàng)建新對象,同時(shí)還不必因此創(chuàng)建自定義類型

  function object(o){

  function F(){}

  F.prototype = o

  return new F()

  }

  在object函數(shù)內(nèi)部,先創(chuàng)建一個(gè)臨時(shí)性的構(gòu)造函數(shù),然后將傳入的對象作為這個(gè)構(gòu)造函數(shù)的原型,最后返回這個(gè)臨時(shí)類型的一個(gè)新實(shí)例

  本質(zhì)上來說,object對傳入其中的對象執(zhí)行了一次淺復(fù)制

  var person = {

  name: 'Jiang',

  friends: ['Shelby', 'Court']

  }

  var anotherPerson = object(person)

  console.log(anotherPerson.friends)  // ['Shelby', 'Court']

  這種模式要去你必須有一個(gè)對象作為另一個(gè)對象的基礎(chǔ)

  在這個(gè)例子中,person作為另一個(gè)對象的基礎(chǔ),把person傳入object中,該函數(shù)就會(huì)返回一個(gè)新的對象

  這個(gè)新對象將person作為原型,所以它的原型中就包含一個(gè)基本類型和一個(gè)引用類型

  所以意味著如果還有另外一個(gè)對象關(guān)聯(lián)了person,anotherPerson修改數(shù)組friends的時(shí)候,也會(huì)體現(xiàn)在這個(gè)對象中

  Object.create()方法

  ES5通過Object.create()方法規(guī)范了原型式繼承,可以接受兩個(gè)參數(shù),一個(gè)是用作新對象原型的對象和一個(gè)可選的為新對象定義額外屬性的對象,行為相同,基本用法和上面的object一樣,除了object不能接受第二個(gè)參數(shù)以外

  var person = {

  name: 'Jiang',

  friends: ['Shelby', 'Court']

  }

  var anotherPerson = Object.create(person)console.log(anotherPerson.friends)  // ['Shelby', 'Court']

  寄生式繼承

  寄生式繼承的思路與寄生構(gòu)造函數(shù)和工廠模式類似,即創(chuàng)建一個(gè)僅用于封裝繼承過程的函數(shù)

  function createAnother(o){

  var clone = Object.create(o) // 創(chuàng)建一個(gè)新對象

  clone.sayHi = function(){ // 添加方法

  console.log('hi')

  }

  return clone  // 返回這個(gè)對象

  }

  var person = {

  name: 'Jiang'

  }

  var anotherPeson = createAnother(person)

  anotherPeson.sayHi()

  基于person返回了一個(gè)新對象anotherPeson,新對象不僅擁有了person的屬性和方法,還有自己的sayHi方法

  在主要考慮對象而不是自定義類型和構(gòu)造函數(shù)的情況下,這是一個(gè)有用的模式

  寄生組合式繼承

  在前面說的組合模式(原型鏈+構(gòu)造函數(shù))中,繼承的時(shí)候需要調(diào)用兩次父類構(gòu)造函數(shù)

  父類

  function SuperType(name){

  this.name = name

  this.colors = ['red', 'blue', 'green']

  }

  第一次在子類構(gòu)造函數(shù)中

  function SubType(name, job){

  // 繼承屬性

  SuperType.call(this, name)

  this.job = job

  }

  第二次將子類的原型指向父類的實(shí)例

  // 繼承方法SubType.prototype = new SuperType()

  當(dāng)使用 var instance = new SubType() 的時(shí)候,會(huì)產(chǎn)生兩組namecolor屬性,一組在SubType實(shí)例上,一組在SubType原型上,只不過實(shí)例上的屏蔽了原型上的

  使用寄生式組合模式,可以規(guī)避這個(gè)問題

  這種模式通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法

  基本思路:不必為了指定子類型的原型而調(diào)用父類的構(gòu)造函數(shù),我們需要的無非就是父類原型的一個(gè)副本

  本質(zhì)上就是使用寄生式繼承來繼承父類的原型,在將結(jié)果指定給子類型的原型

  function inheritPrototype(subType, superType){

  var prototype = Object.create(superType.prototype)

  prototype.constructor = subType

  subType.prototype = prototype

  }

  該函數(shù)實(shí)現(xiàn)了寄生組合繼承的最簡單形式

  這個(gè)函數(shù)接受兩個(gè)參數(shù),一個(gè)子類,一個(gè)父類

  第一步創(chuàng)建父類原型的副本,第二步將創(chuàng)建的副本添加constructor屬性,第三部將子類的原型指向這個(gè)副本

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

  補(bǔ)充:直接使用Object.create來實(shí)現(xiàn),其實(shí)就是將上面封裝的函數(shù)拆開,這樣演示可以更容易理解

  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)

  // 修復(fù)constructor

  SubType.prototype.constructor = SubType

  var instance = new SubType('Jiang', 'student')

  instance.sayName()

  ES6新增了一個(gè)方法, Object.setPrototypeOf ,可以直接創(chuàng)建關(guān)聯(lián),而且不用手動(dòng)添加constructor屬性

  // 繼承Object.setPrototypeOf(SubType.prototype, SuperType.prototype)

  console.log(SubType.prototype.constructor === SubType) // true

 

來源: Xu?thus Blog

您還未登錄,請先登錄

熱門帖子

最新帖子

?