FE-DSHUI / DSHUI

前端王者小分队读书会
4 stars 1 forks source link

《你不知道的JavaScript(上卷)》-类继承模式和对象委托模式的区别-2021-03-05 #60

Open AwakenedSomeone opened 3 years ago

AwakenedSomeone commented 3 years ago

结合之前说的对象委托,以及另一篇《重学ES6:继承的几种方式》里寄生组合继承的方式来说明。 1.首先,如果是寄生组合继承,涉及到需要调用父类(相当于Class里的supper构造函数调用),然后再通过Object.create(),让子类继承到父类。这样的方式,允许我们在子类中重写父类的方法,营造出了一种伪多态的现象。我们在构造这样的设计模式时,允许我们在原型链上有同名方法。 以编写一个控件生成对象为例:

// 类 控件
// 父类
function Widget (w, h) {
  this.width = w || 50
  this.height = h || 50
  this.$elem = null
}
Widget.prototype.render = function ($where) {
  if (this.$elem) {
    this.$elem.css({
      width: this.width + 'px',
      height: this.height + 'px'
    }).appendTo($where)
  }
}

// 子类
function Button (w, h, label) {
  // 类似调用“supper”构造函数   实现寄生组合继承的关键
  Widget.call(this, w, h)
  this.label = label || 'Default'
  this.$elem = $("<button>").text(this.label)
}
// 让Button继承Widget  实现寄生组合继承的关键
Button.prototype = Object.create(Widget.prototype)

// 重写render 
Button.prototype.render = function ($where) {
  // supper 调用
  Widget.prototype.render.call(this, $where)
  this.$elem.click(this.onClick.bind(this))
}
Button.prototype.onClick = function (evt) {
  console.log("Botton" + this.label + "clicked")
}

// 实际生成的地方
$(document).read(function () {
  var $body = $(document.body)
  var btn1 = new Button(125, 30, "Hello")
  var btn2 = new Button(150, 40, "World")

  btn1.render($body)
  btn2.render($body)
})
  1. 而对于对象委托模式,则是希望我们尽量不要再原型链上使用相同的方法名,避免重写,如果需要改写原型链上的方法,最好是重新写一个语义明显的方法,在这个方法中再调用原型链上的方法,这样做也达到了我们既想复用原型链上的方法,又不改变原方法的目的。 同样的控件对象,用对象委托设计模式如下: // 委托控件对象
    var Widget = {
    init: function (width, height) {
    this.width = width || 50;
    this.height = height || 50;
    this.$elem = null;
    },
    insert: function ($where) {
    if (this.$elem) {
      this.$elem.css({ width: this.width + "px", height: this.height + "px" }).appendTo($where);
    }
    }
    };
    var Button = Object.create(Widget);
    // 另写了一个setup来调用原型链上的init函数
    Button.setup = function (width, height, label) { // 委托调用
    this.init(width, height);
    this.label = label || "Default";
    this.$elem = $("<button>").text(this.label);
    };
    Button.build = function ($where) {
    // 委托调用
    this.insert($where);
    this.$elem.click(this.onClick.bind(this));
    };
    Button.onClick = function (evt) {
    console.log("Button '" + this.label + "' clicked!");
    };
    $(document).ready(function () {
    var $body = $(document.body);
    var btn1 = Object.create(Button);
    btn1.setup(125, 30, "Hello");
    var btn2 = Object.create(Button);
    btn2.setup(150, 40, "World");
    btn1.build($body);
    btn2.build($body);
    });

在这本书中,作者更推崇这样的设计模式,这样语义更清楚,也不会像模仿类的方式那样复杂。我个人也更喜欢对象委托模式,这样的模式跟vue里的写法类似,更符合平常的使用风格。