1. 程式人生 > >js各種繼承方式匯總

js各種繼承方式匯總

使用 bit 拷貝 prot urn str 返回 共享 ceo

js中的各種繼承實現匯總

首先定義一個父類:

function Animal(name) {
  this.name = name || '動物'
  this.sleep = function () {
    console.log(this.name + '正在睡覺!')
  }
}
Animal.prototype.eat = function (food) {
  console.log(this.name + '正在吃:' + food)
}

原型鏈繼承

特點:
1、子類的原型指向父類的實例
缺點:
1、無法多繼承
2、無法向父類的構造傳參

3、來自原型對象的引用屬性是所有實例共享的

function Cat() { }
Cat.prototype = new Animal()
Cat.prototype.name = '貓'

// Test code
const cat = new Cat()
console.log(cat.name)   // 貓
cat.eat('魚')       // 貓正在吃:魚
cat.sleep()       // 貓正在睡覺!
console.log(cat instanceof Cat)   // true
console.log(cat instanceof Animal)    // true

構造繼承(使用call、apply方式)

特點:
1、子類的構造中進行父類構造的調用
優點:
1、實現了多繼承,想繼承哪個直接在子類構造裏面call或者apply哪個就行
2、避免所有子類實例共享父類引用屬性問題
3、創建子類實例時,可以向父類傳遞參數
缺點:
1、沒用到原型,只是單純繼承了父類的實例屬性及方法
2、沒繼承原型上的屬性及方法
3、每個子類都有父類方法屬性的副本,影響性能,沒有實現父類函數復用

function Dog(name) {
  Animal.call(this)
  this.name = name || '狗'
}
// Test code
const
dog = new Dog() console.log(dog.name) // 狗 dog.sleep() // 狗正在睡覺! // dog.eat('粑粑') 不能繼承原型上的eat console.log(dog instanceof Dog) // true console.log(dog instanceof Animal) // false,等於是復制父類的實例屬性給子類,沒用到原型

實例繼承

特點:
1、子類的構造中返回父類的實例
優點:
1、可以繼承原型上的屬性或方法
缺點:
1、實例為父類實例,而非子類實例
2、不能實現多繼承

function Pig(name) {
  const instance = new Animal()
  instance.name = name || '豬'
  return instance
}
// Test code
const pig = new Pig()
console.log(pig.name)   // 豬
pig.sleep()   // 豬正在睡覺!
pig.eat('菠菜葉子')   // 豬正在吃:菠菜葉子
console.log(pig instanceof Pig)   // false
console.log(pig instanceof Animal)   // true

復制繼承或拷貝繼承(暴力繼承)

特點:
1、子類的構造中強制拷貝父類原型上的屬性或方法
優點:
1、可以多重繼承
缺點:
1、效率較低,內存占用高
2、不能繼承父類不可枚舉的屬性(不能用for in遍歷的)

function Rabbit(name) {
  const animal = new Animal()   // 多重繼承直接new多個遍歷
  for (let i in animal) {
    Rabbit.prototype[i] = animal[i]
  }
  Rabbit.prototype.name = name || '兔子'
}
// Test code
const rabbit = new Rabbit('傻兔子')
console.log(rabbit.name)    // 傻兔子
rabbit.sleep()   // 傻兔子正在睡覺!
rabbit.eat('胡蘿蔔')   // 傻兔子正在吃:胡蘿蔔
console.log(rabbit instanceof Rabbit)   // true
console.log(rabbit instanceof Animal)   // false

對象冒充繼承(類似於構造繼承)

同構造繼承

function Mouse(name) {
  this.method = Animal
  this.method(name)
  delete this.method
}
// Test code
const mouse = new Mouse('老鼠')
console.log(mouse.name)    // 老鼠
mouse.sleep()   // 老鼠正在睡覺!
// mouse.eat('大米')   // 繼承不到原型上的屬性
console.log(mouse instanceof Mouse)   // true
console.log(mouse instanceof Animal)   // false

組合繼承(構造繼承+原型鏈繼承)

特點:
1、組合構造繼承和原型鏈繼承
優點:
1、可以繼承實例屬性/方法,也可以繼承原型屬性/方法
2、既是子類的實例,也是父類的實例
3、不存在引用屬性共享問題
4、可傳參
5、函數可復用
缺點:
1、調用了兩次父類構造函數

function Duck(name) {
  Animal.call(this, name)
}
Duck.prototype = new Animal()
Duck.prototype.say = function () {   // 新增的say方法
  console.log(this.name + '正在說話!')
}
// Test code
const duck = new Duck('鴨子')
console.log(duck.name)    // 鴨子
duck.sleep()   // 鴨子正在睡覺!
duck.eat('蟲子')   // 鴨子正在吃:蟲子
console.log(duck instanceof Duck)   // true
console.log(duck instanceof Animal)   // true

寄生組合繼承

特點:
1、使用中間函數對象避免父類構造被兩次調用的問題
優點:
1、完美
缺點:
1、寫起來費勁

function Snake(name) {
  Animal.call(this, name)
}
const Super = function () { }
Super.prototype = Animal.prototype
Snake.prototype = new Super()
// Test code
const snake = new Snake('蛇')
console.log(snake.name)    // 蛇
snake.sleep()   // 蛇正在睡覺!
snake.eat('小鳥')   // 蛇正在吃:小鳥
console.log(snake instanceof Snake)   // true
console.log(snake instanceof Animal)   // true

ES6的class繼承

class Point {
  constructor(x, y) {? //constructor 構造方法
    this.x = x
    this.y = y
  }
  toString() {
    return this.x + ', ' + this.y
  }
  static hello() {
    console.log('hello world!')
  }
}
class ColorPoint extends Point {
  constructor(x, y, color){
    super(x, y)   // 必須先調用super,否則子類的this不可用
    this.color = color
  }
  toString() {
    return this.color + ',' + super.toString()
  }
}
// Test code
const cp = new ColorPoint(25, 8, 'green')
console.log(cp instanceof ColorPoint) // true
console.log(cp instanceof Point) // true
ColorPoint.hello()    // hello world!

js各種繼承方式匯總