Шаблоны проектирования моделей JavaScript, пользовательские события и многое другое - PullRequest
0 голосов
/ 13 июня 2019

С учетом следующего API:

var person = new Model({name: 'John'});
person.get('name'); //=> 'John'
person.set('name', 'Johny');
person.on('change', function(oldModel, newModel){
    console.log(oldModel, newModel);
    //=> {name: 'John'}, {name: 'Johny'}
});

Напишите класс модели.

Технические характеристики:

  1. Класс моделиимеет 3 метода: get, set и on.
  2. Можно зарегистрировать несколько обратных вызовов «change»
  3. Все зарегистрированные обратные вызовы необходимо вызывать, когда происходит изменение
  4. Изменениесобытие происходит всякий раз, когда новые атрибуты добавляются или изменяются с помощью метода set.

Для этого вопроса о конструкции.Я реализовал тремя различными способами ниже.Все они работают.

Мой вопрос: какой из них лучше?или почему один над другим?Или, если у вас есть лучшее решение, пожалуйста, помогите мне лучше понять концепцию вопроса.

IIFE

/** method 1: IIFE */
const IIFEModel = (function() {
  function ourModel(obj) {
    this.oldModel = Object.assign({}, obj);
    this.newModel = obj;
  }

  ourModel.prototype.set = function(key, value) {
    this.oldModel = Object.assign({}, this.newModel);
    this.newModel[key] = value;
    this.on("change");
  };

  ourModel.prototype.get = function(key) {
    console.log(this.newModel[key]);
    return this.newModel[key];
  };

  ourModel.prototype.on = function(eventName, handler = () => {}) {
    switch (eventName) {
      case "change":
        return handler(this.oldModel, this.newModel);
      default:
        return handler();
    }
  };

  return ourModel;
})();

Выявление образца прототипа

/** method 2: Revealing Prototype Pattern */
const PrototypeModel = function(obj) {
  this.oldModel = Object.assign({}, obj);
  this.newModel = obj;
};

PrototypeModel.prototype = (function() {
  const set = function(key, value) {
    this.oldModel = Object.assign({}, this.newModel);
    this.newModel[key] = value;
    this.on("change");
  };

  const get = function(key) {
    console.log(this.newModel[key]);
    return this.newModel[key];
  };

  const on = function(eventName, handler = () => {}) {
    switch (eventName) {
      case "change":
        return handler(this.oldModel, this.newModel);
      default:
        return handler();
    }
  };

  return {
    get: get,
    set: set,
    on: on
  };
})();

***** ОБНОВЛЕНИЕ КОДА после предложения @obfish ******

/** method 3: ES6 */
class ECMAModel {
  constructor(obj) {
    this.oldModel = Object.assign({}, obj);
    this.newModel = obj;
    this.events = new Map();
  }
  set(key, value) {
    this.oldModel = Object.assign({}, this.newModel);
    this.newModel[key] = value;
    this.fire("change", this.oldModel, this.newModel);
  }
  get(key) {
    console.log(this.newModel[key]);
    return this.newModel[key];
  }
  on(eventName, handler) {
    if (this.events.has(eventName))
      this.events.set(eventName, this.events.get(eventName).concat(handler));
    else this.events.set(eventName, [handler]);
  }
  off(eventName, handler) {
    if (!this.events.has(eventName)) return;
    let index = this.events.get(eventName).indexOf(handler);
    if (index != -1) this.events.get(eventName).splice(index, 1);
  }
  fire(eventName, ...args) {
    if (!this.events.has(eventName)) return;
    if (!args || !args.length) args = [];

    var es = this.events.get(eventName),
      l = es.length;
    for (var i = 0; i < l; i++) {
      es[i].apply(null, args);
    }
  }
}
/** test case */
let person = new PrototypeModel({ name: "john" });
person.get("name");
person.set("name", "johny");
person.get("name");
person.on("change", function(oldModel, newModel) {
  console.log(oldModel, newModel);
});

И я замечаю, что способ создания пользовательского события немного недостижим.Поскольку я предполагаю, что функция обратного вызова из теста имеет два элемента, которые могут иметь проблемы при рассмотрении масштабируемости.Есть ли другой способ добиться этого?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...