设计模式什么的根本记不住啊 , 直接看各类原生JS继承吧!!!

2,263 阅读3分钟

原生JS继承详解

参考资料
不要讲什么设计模式 , 看得老子脑壳昏 , 智商欠费 , 还是简单点 , 方案 , 继承 , 就完事了

// 首先我们得有个父类
// 这个父类也很简单
function Human(name) {
    this.name = name || '肥宅' // 有参就取参 , 没参就叫肥宅
}
Human.prototype.drink = function(drinks) {
    console.log(this.name + '正在喝' + (drinks || '可乐'));
}

OK, 我们现在有了一个父类, 先来看一个最简单的继承

最简单的原型链继承

直接把父类的实例作为子类的原型

// 先写个空类
function Jianren(){}
Jianren.prototype = new Human()

// new个实例看看
var haidong = new Jianren();

console.log(haidong.name); //'肥宅'
console.log(haidong.drink()); //'haidong正在喝可乐'

对于这个继承, 概括为子类的原型链绑定父类的实例实现继承

缺陷

  1. 不能实现多类继承
  2. 为子类新增属性和方法,必须要在new Animal()这样的语句之后执行
  3. 无法控制子类能够访问父类属性的权限
  4. 创建子类的实例时也不能向父类构造函数传参

构造继承

复制父类属性

function Jianren(){
  Human.call(this);// 把父类写进子类构造函数内部, 调用call把子类的this传进去改变this的指向做到复制父类属性
  this.age = 22
}
  1. 构造继承其实就是复制了父类属性, new Jianren()出来的实例的construct和prototype都与Human无关, 指向Jianren()
  2. 可以不管new 父类前后顺序来新增子类的属性
  3. 创建子类实例时, 也可以向父类传递参数,
  4. 可以call多个父类实现多类继承
  5. 只能继承父类的实例属性和方法, 不能继承/访问到父类原型上的东西
  6. 难以复用, 影响性能

实例继承

在子类内部添加一个属性, 该属性为父类的实例

function Jianren(name){
  var ren = new Human();// 注意这里是不是this
  ren.name = name || 'haidong';
  return ren;
}
  1. 不会限制调用的方式, new 子类() 或者 子类()执行, 都返回ren
  2. new Jianren()的实例实际上是new Human(), constructor也是指向Human()
  3. 不支持多类继承

拷贝继承

function Jianren(name){
  var ren = new Human()
  for(var r in ren) {
      Cat.prototype[r] = ren[r] // 该处r是key, 应该用Object[key]的形式赋值和访问
  }
  Jianren.prototype.name = name || 'haidong'
}
  1. 支持多继承
  2. 效率低, 拷贝属性会占用内存
  3. 不可枚举父类

推荐的两种继承

组合继承和寄生组合继承

上面的继承主要是帮助理解, 或有时暴力快速解决小问题时使用 .

推荐一, 组合继承

子类的原型指向父类实例,该父类实例又可向上原型查找访问,修正后constructor指向子类自身

function Jianren(name) {
    Human.call(this) //第一步拷贝属性
    this.name = name || 'haidong'
}
Jianren.prototype = new Human() //第二步, 原型指向父类实例
Jianren.prototype.constructor = Jianren //第三步, 修正constructor指向
  1. 可以继承实例的属性/方法, 也可以继承原型的属性方法,
  2. 是子类的实例, 也相当于是父类的实例
  3. 子类的原型指向父类实例,该父类实例又可向上原型查找访问,修正后constructor指向子类自身
  4. 可传参,//call()可以传参,具体用法,自行百度谷歌
  5. 调用两次父类构造函数, 占内存, 第一步拷贝过一次, 第二步导致以后的Jianren的实例里和Jianren原型上重复的属性

推荐二, 寄生组合继承

// 有点复杂
function Jianren(name) {
    Human.call(this) //第一步拷贝属性
    this.name = name || 'haidong'
}
(function() { //来个匿名立即执行函数
    function J() {}// 创建一个中间类, 空, 什么都没有
    J.prototype = Human.prototype //第二步中间类原型指向父类原型
    Jianren.prototype = new J() //子类原型赋值为中间类的实例,往上查找,指向了父类的原型
})()
Jianren.prototype.constructor = Jianren //修正子类constructor指向

与上面的组合继承相比, 第一步拷贝 和 第二步中间类(空类)不会重复有Human的属性, 略微复杂, 可以忽略不计, 完美方式