JavaScript繼承看這篇就夠了!

基本上,ES6 的class能夠看做只是一個語法糖,它的絕大部分功能,ES5 均可以作到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。編程

藉助構造函數實現繼承

  • 缺點:沒法繼承原型鏈上的屬性和方法
function Person () {
  this.name = 'person1'
}
Person.prototype.sex = '10'
Person.prototype.sayName = function () {
  alert(this.name)
}
function Man () {
  Person.call(this)
  this.age = '24'
}
var m1 = new Man()
console.log(m1) // Man {name: "person1", age: "24"} (注意:實例自身不存在sex屬性和 
sayName方法)
// m1.sayName() // 報錯 (由於原型鏈上也不存在)
複製代碼

藉助原型鏈實現繼承

  • 缺點:子類共享父類的引用屬性
function Father () {
 this.Farr = [1, 2, 3]
}
function Child () { }
Child.prototype = new Father()
var c1 = new Child()
var c2 = new Child()
console.log(c1.Farr) // [1, 2, 3]
console.log(c2.Farr) // [1, 2, 3]
c1.Farr.push(4)
console.log(c1.Farr) // [1, 2, 3, 4]
console.log(c2.Farr) // [1, 2, 3, 4]
複製代碼

組合繼承

  • 優勢:子類不會共享父類中的屬性,缺點:Mother構造函數被執行兩次,沒法肯定實例直接父類了
function Mother () {
  console.log('init Mother...')
  this.Marr = ['a', 'b', 'c']
}
function Daughter () {
  Mother.call(this) // 執行一次Mother構造函數
}
Daughter.prototype = new Mother() // 再執行一次Mother構造函數
var d1 = new Daughter()
var d2 = new Daughter()
console.log(d1.Marr) //  ["a", "b", "c"]
console.log(d2.Marr) //  ["a", "b", "c"]
d1.Marr.push('d')
console.log(d1.Marr) // ["a", "b", "c", "d"]
console.log(d2.Marr) //  ["a", "b", "c"]
console.log(d2.__proto__.constructor === Mother) // true(指望值是false,由於Daughter纔是d2的直接父類)
複製代碼

組合繼承優化(一)

  • 優勢:防止調用兩次構造函數,缺點:依舊沒法肯定實例直接父類
function Animal () {
  console.log('init Animal...')
}
function Cat () {
  Animal.call(this) // 執行一次Animal構造函數
}
Cat.prototype = Animal.prototype
var cat = new Cat()
console.log(cat.__proto__.constructor === Animal) // true(指望值是false,由於Cat纔是cat的直接父類)
複製代碼

組合繼承優化(二)

  • 解決沒法肯定實例直接父類問題
function God () {
  console.log('init Final...')
  this.name = 'god'
}
God.prototype.todo = function () {
  alert('todo')
}
function Son () {
  God.call(this)
}
// Son.prototype = God.prototype
Son.prototype = Object.create(God.prototype) // Object.create()方法建立一個新對象,使用現有的對象來提供新建立的對象的__proto__
console.log(God.prototype)
console.log(Object.create(God.prototype))
Son.prototype.constructor = Son

var s = new Son // 無參數時,小括號能夠省略
console.log(s)
console.log(s.__proto__.constructor === Son) // true (與指望值一直,完美!)
console.log(s.__proto__.constructor) // true (與指望值一直,完美!)
複製代碼

爲何要用Object.create()方法

  • Object.create()方法建立一個新對象,使用現有的對象來提供新建立的對象的__proto__
  • 使用這個方法,傳入null能夠建立一個無任何屬性的對象(原型上也沒有)
  • 使用這個方法,會將現有對象放到__proto__屬性中,會隱藏現有對象原型上的默認屬性和方法,僅僅保留用戶本身定義的。
// 普通方法建立對象的對象
console.log({})
// 使用Object.create建立的對象
console.log(Object.create(null))

// 使用Object.create,會將現有對象放到__proto__屬性中
function God () {
  console.log('init Final...')
  this.name = 'god'
}
God.prototype.todo = function () {
  alert('todo')
}
function Son () {
  God.call(this)
}
// Son.prototype = God.prototype
Son.prototype = Object.create(God.prototype)
Son.prototype.constructor = Son

console.log(Son.prototype)
複製代碼
  • 普通方法建立對象的對象 函數

  • 使用Object.create建立的對象 優化

  • 使用Object.create()方法實現繼承 ui

  • 不使用Object.create()方法實現繼承 this

本篇完。spa

相關文章
相關標籤/搜索