原型鏈以及繼承的幾種方式


學習原型鏈前需要了解

使用構造函數模式創建的對象實例,都有一個constructor(構造函數) 屬性,該屬性指向構造函數。

function Person (name, age, job) {

  this.name = name;

  this.age = age;

  this.job = job;

  this.sayName = function () {

    alert(this.name)

  }

}

var person1 = new Person(“Nicholas”, 29, “Sofware Engineer”)

var person2 = new Person(“Greg”, 27, “Doctor”)

alert(person1.constructor == Person) // true

alert(person2.constructor == Person) // true

//創建出來的所有對象即使Object的實例,同時也是Person的實例

只要創建一個新函數,就會根據特定的規則為該函數創建一個 prototype 屬性,這個屬性是一個指針,指向一個對象。這個對象的用途是包含可以由特定類型的 所有實例 共享的屬性和方法,這個對象就是通過調用構造函數創建的對象實例的原型對象。

原型鏈
構造函數,原型和實例的關系
每一個構造函數都有一個原型對象,原型對象包含一個指向構造函數的指針,而每個實例都包含一個指向構造函數的原型對象的內部指針

原型鏈
如果讓一個原型對象等於另一個類型的實例,層層遞進,構成實例與原型的鏈條,這就是原型鏈

創建了自定義的構造函數,其原型對象默認只會取得 constructor 屬性;其他方法都是從Object 繼承來的
當調用構造函數創建一個實例之后,該實例內部會包含一個指針(屬性),指向構造函數的原型,我們可以稱這個指針為 [[Prototype]]

Function(Object)包含 prototype(原型對象指針)
prototype(原型對象指針)包含constructor(構造函數)屬性
constructor(構造函數)屬性包含指向原型對象所在函數的指針

繼承的幾種方式

js主要是通過原型鏈實現繼承,原型鏈的構建是通過將一個類型的實例賦值給另外一個構造函數的原型實現的

原型鏈繼承

基本代碼

function SuperType () {
  this.property = true
}
SuperType.prototype.getSuperValue = function () {
  return this.property
}
function SubType () {
  this.subproperty = false
}
// 繼承了SuperType //
SubType.prototype = new SuperType()
SubType.protype.getSubValue = function () {
  return this.subproperty
}
var instance = new SubType()

實現的本質:重寫原型對象,用一個新的類型的實例去替代

SubType Prototype === SuperType構造函數的實例
注意:
1.默認的原型
所有的引用類型都默認繼承Object,這個繼承也是通過原型鏈實現的

2.原型鏈的問題
a.對象實例共享所有繼承的屬性和方法
b.創建子類型的實例的時候,不能傳遞參數

借用構造函數繼承

基本代碼

function SuperType () {
  this.colors = ["red", "blue", "green"]
}
function SubType () {
  // 繼承了SuperType
  SuperType.call(this)
  // 只能繼承構造函數上的屬性
}

實現的本質:在子類構造函數的內部調用超類型構造函數,使用aapply()和call() 方法
注意:
1.函數復用性不高
2.只能繼承實例上的屬性,原型上的方法不可見

組合繼承(偽經典繼承)

基本代碼

function SuperType (name) {
  this.name = name
  this.colors = ["red", "blue", "green"]
}
SuperType.prototype.sayName = function () {
  alert(this.name)
}
function SubType (name, age) {
  // 繼承屬性
  SuperType.call(this, name) // 第二次調用SuperType()
  this.age = age
}
//繼承方法
SubType.prototype = new SuperType() // 第一次調用 SuperType()
Subtype.prototype.sayAge = function () {
  alert(this.age)
}

實現思路:使用原型鏈實現對原型屬性和方法的繼承,通過借用構造函數來實現對實例屬性的繼承
注意:
組合繼承避免了原型鏈和借用構造函數的缺陷,融合了他們的優點,成為js中最常用的繼承方式。

原型式繼承

基本代碼

function object (o) {
  function F(){}
  F.prototype = o
  return new F()
}

實現本質:object()函數對傳入其中的對象執行了一次淺復制
注意:
可以在不必預先定義構造函數的情況下實現繼承,其本質是執行對給定對象的淺復制,而復制的副本還可以得到進一步的改造
問題還是包含引用類型的屬性都會被共享

寄生式繼承

基本代碼

function createAnother (original) {
  var clone = object(original) // 通過調用函數創建一個新對象
  clone.sayHi = function () { // 以某種方式來增強這個對象
    alert("hi")
  }
  return clone // 返回這個對象
}

實現本質和寄生構造函數還有工廠模式類似
注意:
基於某個對象或者某些信息創建一個對象,然后增強對象,最后返回對象,為了解決組合繼承模式由於多次調用超類型構造函數而導致的低效率問題,可以將這個模式與組合繼承一起使用

寄生組合式繼承

基本代碼

function inheritPrototype (subType, superType) {
  var prototype = object(superType.prototype) // 創建對象
  prototype.constructor = subType // 增強對象
  subType.prototype = prototype // 指定對象
}

function SuperType (name) {
  this.name = name
  this.colors = {"red", "blue", "green"}
}
SuperType.prototype.sayName = function () {
  alert(this.name)
}
function SubType (name, age) {
SuperType.call(this, name)
  this.age = age
}
inheritPrototype(SubType, SuperType)

 

實現本質:借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法
注意:
高效率只調用了一次構造函數,集寄生式繼承和組合繼承的優點於一身,是實現基於類型繼承的最有效方式

小結:
JavaScript主要通過原型鏈實現繼承。原型鏈的構建是通過將一個類型的實例賦值給另一個構造函數的原型實現的。
使用最多的繼承模式是組合繼承,這種模式使用原型鏈繼承共享的屬性和方法,通過借用構造函數繼承實例屬性

注:博客新手,文章有誤請大家指出,不勝感激

說實話,博客園的編輯器是有點難用

csdn鏈接:https://blog.csdn.net/weixin_43882226/article/details/88197382 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM