ES5规范中JS的构造函数与继承

42 阅读2分钟

我们对于知识的理解尊崇 案例从简 的方式,无需讲解很多种,提取几个经典实现即可。

构造函数

// 声明一个构造函数
function Person (name) {
  this.name = name || 'Person'
  this.sleep = function () {
    console.log(`${this.name}--正在睡觉`)
  }
}
// 原型上添加<eat>方法
Person.prototype.eat = function (food) {
  console.log(`${this.name}--在吃--${food}`)
}
let p01 = new Person()


// 打印属性和方法
console.log(p01.name) // Person
p01.sleep() // Person--正在睡觉
p01.eat('食物') // Person--在吃--食物

继承

    1. 原型链继承
  • 特点:基于原型链,既是父类的实例,也是子类的实例
  • 缺点:无法实现多继承
function ZhangSan () {}
ZhangSan.prototype = new Person('张三')
let zs01 = new ZhangSan()


// 打印属性和方法
console.log(zs01.name) // 张三
zs01.sleep() // 张三--正在睡觉
zs01.eat('饼干') // 张三--在吃--饼干
    1. 构造函数继承
  • 特点:可以实现多继承
  • 缺点:只能继承父类实例的属性和方法,不能继承原型上的属性和方法
function LiSi (name) {
  Person.call(this)
  this.name = name || 'LiSi'
}
let ls01 = new LiSi('李四')


// 打印属性和方法
console.log(ls01.name) // 李四
ls01.sleep() // 李四--正在睡觉
ls01.eat('面包') // Error: ls01.eat is not a function
    1. 组合继承
  • 特点:可以继承实例属性/方法,也可以继承原型属性/方法
  • 缺点:调用了两次父类构造函数,生成了两份实例
function WangWu (name) {
  Person.call(this)
  this.name = name || 'WangWu'
}
WangWu.prototype = new Person()
let ww01 = new WangWu('王五')


// 打印属性和方法
console.log(ww01.name) // 王五
ww01.sleep() // 王五--正在睡觉
ww01.eat('米饭') // 王五--在吃--米饭
    1. 寄生组合继承
  • 特点:可以继承实例属性/方法,也可以继承原型属性/方法
  • @des: 通过寄生方式,砍掉父类的实例属性;这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性
  • @tip: 【 最佳方案 】
function ZhaoLiu (name) {
  Person.call(this)
  this.name = name || 'ZhaoLiu'
}
(function () {
  // 创建一个没有实例方法的类
  let Super = function () {}
  Super.prototype = Person.prototype
  ZhaoLiu.prototype = new Super()
})()
let zl01 = new ZhaoLiu('赵六')


// 打印属性和方法
console.log(zl01.name) // 赵六
zl01.sleep() // 赵六--正在睡觉
zl01.eat('汉堡') // 赵六--在吃--汉堡