动态

详情 返回 返回

【js】實現繼承的幾種方式 - 动态 详情

js繼承

  1. 原型鏈
  2. 構造函數
  3. 組合繼承(原型鏈 + 構造函數)
  4. 原型式繼承
  5. 寄生式繼承
  6. 寄生組合繼承

1.原型鏈繼承

將父類的實例作為子類的原型

//父類
function School(name) {
    //實例屬性
    this.name = name || "父類"
    this.arr = [1]
}
//父類原型方法
School.prototype = {
    constructor: School,
    showName() {
        console.log(this.name);
    },
}
//子類
function Student(gender) {
    this.gender = gender
}
Student.prototype = new School("子類")
Student.prototype.constructor = Student
//子類的實例
let std1 = new Student()
let std2 = new Student()

關鍵

Student.prototype = new School()
  • 將父類的實例作為子類的原型
  • new School()得到一個實例對象o,它的構造函數是School,o上沒有constructor屬性,但會繼承School的prototype上的constructor
  • 給o追加一個屬性constructor指向Student
  • 相當於通過o的繼承實現的間接的繼承,也就是原型鏈繼承

優點

  • 共享了父類原型上的方法

    std1.showName() //子類
    std1.showName === std2.showName //true

缺點

  • 不能向父類傳參 - 在實例化子類時想讓std1帶上name不能實現,只能手動追加
  • 子類實例共享了父類構造函數的引用屬性

    std1.arr.push(2)
    console.log(std2.arr);//[1,2]

2.構造函數

將父類的構造函數在子類的構造函數中執行,改變this指向

function School(name) {
    this.name = name || "父類"
    this.arr = [1]
    this.showName = function () {
        console.log(this.name);
    }
}

function Student(name,gender) {
    School.call(this,name)
    this.gender = gender
}

let std1 = new Student("張三")
let std2 = new Student("李四")

關鍵

School.call(this,name)
  • 將School中的this改為Student中的this,將name參數傳入School返回
  • 相當於拷貝了父類構造函數中的屬性與方法
  • 在實例化子類時都會這樣拷貝一次

優點

  • 可以向父類構造函數傳參 - 通過call
  • 不共享父類的引用屬性

    std1.arr.push(2)
    console.log(std2.arr);//[1]

缺點

  • 方法不能複用

    std1.showName === std2.showName //false
  • 不能繼承父類原型上的方法 - 只是對父類構造函數內屬性與方法的拷貝

3.組合繼承

結合原型鏈和構造函數

function School(name) {
    this.name = name || "父類"
    this.arr = [1]
    
}
School.prototype = {
    constructor:School,
    showName() {
        console.log(this.name);
    }

}
function Student(name, gender) {
    School.call(this, name)
    this.gender = gender
}
Student.prototype = new School()
Student.prototype.constructor = Student

let std1 = new Student("張三")
let std2 = new Student("李四")
  • 包含了1和2的關鍵語句

優點

  • 可以向父類傳參數
  • 共享複用父類原型上的方法
  • 不共享父類構造函數上的引用屬性

缺點

  • 兩個關鍵語句調用了兩次父類構造函數,生成兩個實例副本,影響性能

優化1

Student.prototype = new School()
替換為
Student.prototype = School.prototype
  • 這種優化解決了兩次調用,但是在修改constructor時,父類的也會改變

優化2(完美)

Student.prototype = new School()
替換為
Student.prototype = Object.create(School.prototype)
  • Object.create(proto),創建一個以proto為原型的對象,未調用父類構造函數並且得到一個能繼承父類原型的對象

    Student.prototype.__proto__ === School.prototype//true
  • 修改子類的constructor不會影響到父類,類似與1中提到了o對象,對其追加constructor即可
let std1 = new Student("張三")
let sch1 = new School("理工")
std1.constructor === Student //true
sch1.constructor === School  //true

4.原型式繼承

2006年 Douglas Crockford介紹的一種不涉及嚴格意義上構造函數的繼承方法
不自定義類型也可以通過原型實現對象之間的信息共享

let School = {
    name: "理工",
    arr: [1],
    showName() {
        console.log(this.name);
    }
}
function creat(o) {
    function F() { }
    F.prototype = o
    return new F()
}
let sch1 = creat(School)
sch1.name = "工業"
sch1.showName() //工業
sch1.arr.push(2)
let sch2 = creat(School)
console.log(sch2.arr);//[1,2]
sch1.showName === sch2.showName //true
  • 3中提到的Object.create()的原理和create函數一樣
  • 這種方式的優缺點與原型鏈繼承方式類似

5.寄生式繼承

let School = {
    name: "理工",
    arr: [1],
    showName() {
        console.log(this.name);
    }
}
function create(o) {
    function F() { }
    F.prototype = o
    return new F()
}
function enhance(obj) {
    let clone = create(obj)
    clone.showAge = function () {
        console.log(this.age);
    }
    return clone
}
let sch1 = enhance(School)
let sch2 = enhance(School)

sch1.showName === sch2.showName;//true
sch1.showAge === sch2.showAge;//false
  • 調用函數創建對象,再增強新對象,最後返回新對象
  • 但是方法不能複用

6.寄生組合式繼承

增強的方式與寄生式不同

function enhance(Student,School) {
    let clone = create(School.prtotype)
    clone.costructor = Student
    Student.prototye = clone
}
  • 其實這種方式就是3中的優化2,create就相當於Object.create()
ES6中class的繼承方式在這裏不再介紹,後續在介紹class時作為其中的一部分分析
user avatar toopoo 头像 dingtongya 头像 yinzhixiaxue 头像 front_yue 头像 cicadasmile 头像 zourongle 头像 yqyx36 头像 zzd41 头像 DolphinScheduler 头像 b_a_r_a_n 头像 sy_records 头像 hsr2022 头像
点赞 50 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.