элегантное письмо класса

внешний интерфейс GitHub JavaScript спецификация кода

предисловие

Хотя сейчас эпоха ES6, все же необходимо понимать, как написать класс в ES5. В этой статье подробно описывается метод написания классов в объектно-ориентированном программировании JavaScript и описывается, как шаг за шагом писать элегантные классы.

1. Примеры

Пример — компонент легкой подсказки.Toast. Функции, которые необходимо реализовать:

  • onметод, показывающий подсказки
  • offметод, скрыть подсказку
  • initметод, запрос на инициализацию
function Toast(option){
  this.prompt = '';
  this.elem = null;
  this.init(option);
}

Toast.prototype = {
  // 构造器
  constructor: Toast,
  // 初始化方法
  init: function(option){
    this.prompt = option.prompt || '';
    this.render();
    this.bindEvent();
  },
  // 显示
  show: function(){
    this.changeStyle(this.elem, 'display', 'block');
  },
  // 隐藏
  hide: function(){
    this.changeStyle(this.elem, 'display', 'none');
  },
  // 画出dom
  render: function(){
    var html = '';
    this.elem = document.createElement('div');
    this.changeStyle(this.elem, 'display', 'none');

    html += '<a class="J-close" href="javascript:;">x</a>'
    html += '<p>'+ this.prompt +'</p>';
    
    this.elem.innerHTML = html;

    return document.body.appendChild(this.elem);
  },
  // 绑定事件
  bindEvent: function(){
    var self = this;
    
    this.addEvent(this.elem, 'click', function(e){
      if(e.target.className.indexOf('J-close') != -1){
        console.log('close Toast!');
        self.hide();
      }
    });
  },
  // 添加事件方法
  addEvent: function(node, name, fn){
    var self = this;
    
    node.addEventListener(name, function(){
      fn.apply(self, Array.prototype.slice.call(arguments));
    }, false);
  },
  // 改变样式
  changeStyle: function(node, key, value){
      node.style[key] = value;
  }
};

var T = new Toast({prompt:'I\'m Toast!'});
T.show();

Во-вторых, состав класса.

Используемые классы JavaScript函数对象реализовать. Экземпляр класса выглядит следующим образом:

var T = new Toast();

Ключевым моментом является то, чтоFunctionписьма.

Класс делится на две части:constructor+prototype. это构造器+原型.

2.1 Конструкторы

Конструктор интуитивно понятен, то есть написан накод внутри функции. В примере Toast конструктор представляет собой следующую часть:

function Toast(option){
  this.prompt = '';
  this.elem = null;
  this.init(option);
}

здесьthis, указывает на созданный класс. каждый проходnew Toast()созданныйКонструктор будет выполнен один раз.

2.2 Прототип

Объявление методов и переменных в прототипе выполняется черезToast.prototype.*Путь. Тогда нормальная запись на прототипе выглядит следующим образом:

Toast.prototype.hide = function(){/*code*/}
Toast.prototype.myValue = 1;

Однако плохая часть этого метода записи заключается в том, что вы должны каждый раз писать первую половину.Toast.prorotype, немного громоздко. Он также не является дружественным с точки зрения оптимизации сжатия кода и не может обеспечить наилучшее сжатие. Путь улучшения следующий:

Toast.prorotype = {
  constructor: Toast,
  hide: function(){/*code*/},
  myValue: 1 
}

Оптимизация здесь заключается в том, чтобы указать прототипу новый пустой объект.{}. Преимущество в том, что вы можете использовать{key:value}способ написания методов и переменных на прототипе. Однако этот способ изменяет прототип в конструкторе.prototype.constructorуказывает на. Если явно не переобъявленоconstructorуказывает на,Toast.constructor.prototype.constructorбудет неявно указано наObject. Правильное направление должно бытьToast. Хотя черезnewСоздание экземпляра не вызывает исключения, но с точки зрения наследования классаconstructorУказывающее исключение приведет к неправильному результату решения о наследовании. Это то, чего мы не хотим видеть. Поэтому надо исправлятьconstructor.

2.3 Разница между конструктором и прототипом

Все методы и переменные в прототипе являются экземплярами объектов класса.общийиз. То есть только одна порция. Блок кода внутри конструктора — это каждый созданный объект.Единоличное владение. с или безthis.**Путь или путь частной переменной является эксклюзивным. Поэтому при написании класса необходимо учитывать, является ли новый атрибут общим или монопольным. Исходя из этого, решается, следует ли объявить конструктор или прототип.

3. Спецификация кода

  • Соглашение об именах классов, в отрасли есть неписаное правило, состоит в том, чтобы первая буква была заглавной.
  • Закрытые методы прототипов по умолчанию начинаются с подчеркивания. Это просто преимущество проверки кода с точки зрения командной работы, но на самом деле это открытый метод.

4. Сделайте инстанцирование независимым от нового

Создание экземпляра класса, обязательное поведение, требует использования оператора new. Если оператор new не используется, указатель this в конструкторе не будет текущим созданным объектом. Способ оптимизации заключается в использованииinstanceofСделайте слой защиты.

function Toast(option){
  if(!(this instanceof Toast)){
    return new Toast(option);
  }
  
  this.prompt = '';
  this.elem = null;
  this.init(option);
}

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

function Toast(option){
  if(!(this instanceof Toast)){
    throw new Error('Toast instantiation error');
  }
  
  this.prompt = '';
  this.elem = null;
  this.init(option);
}

Таким образом, не лучше ли было бы бросить горшок обратно 👽


Друзья, которым нравятся мои статьи, могут подписаться на меня следующими способами: