Pull to refresh

Chainvas: изящный и миниатюрный «костыль», добавляющий средства цепного вызова (method chaining) к любому API

Reading time 3 min
Views 2.7K
Благодаря библиотеке jQuery примерно с 2006 года (то есть лет пять как) никому не надо объяснять, что такое method chaining: это та самая техника программирования, в которой методы объекта могут быть вызваны друг за другом по цепочке, как в jQuery.

Главнейшим достоинством этой техники является заметная экономия усилий программиста. С нею программисту не приходится заново, неоднократно записывать имя объекта вот в такой манере:
obj.шмяк();
obj.тыдыжжь();
obj.ынц();

Вместо этого программист может вызвать все методы цепóчкою — в одну строку:
obj.шмяк().тыдыжжь().ынц();

Если же ему покажется, что такой вид записи хуже читается человеком, чем предыдущий (особенно когда у методов появляются параметры, иногда довольно обширные), то тогда программист может записывать имена методов с новой строки (JavaScript это позволяет), но всё равно экономить на имени объекта:
obj
   .шмяк(параметр1, параметр2, …)
   .тыдыжжь(параметр1, параметр2, …)
   .ынц(параметр1, параметр2, …);

На практике возможность такой техники обеспечивается тем, что ни один метод объекта не возвращает значение undefined. Вместо этого, если метод является командою, а не запросом (то есть выполняет некоторое действие, а не возвращает некоторое значение), то в конце его автор библиотеки пишет «return this» — этим-то и обеспечивается возможность записи вызова нескольких команд подряд в форме цепочки.

Насколько я знаю, устоявшегося русского эквивалента англоязычному словосочетанию «method chaining» пока что не существует. Наверное, можно говорить о «цепочечной» или, для простоты, о «цепной» форме вызова методов.

Удобство цепного вызова вызывает привыкание. Ну правда же: достаточно пару-тройку-другую недель попрограммировать на jQuery — и обыкновенные API начинают раздражать, даже бесить, своею допотопною невозможностью цепного вызова. Также недостаёт возможности задания их свойств в виде объекта, передаваемого методу, подобному .css({color: 'red', 'line-height': 1}) в jQuery.

Вообразите себе, например, как необыкновенно было бы удобно, кабы по холсту (<canvas>) можно было рисовать цепными вызовами в такой манере:
ctx.beginPath()
   .prop({
      lineWidth: 2,
      strokeStyle: '#333'
   }).moveTo(0,0)
   .bezierCurveTo(50,50, 80,80, 100,100)
   .stroke().closePath();

И средство для именно таких цепных вызовов появилось — благодаря Lea Verou. Вот оно:

[Chainvas]

Библиотека Chainvas весит всего-навсего ≈1⅓ килобайта после обработки минификатором, а между тем её методами можно обеспечить обёртку вокруг всех (или только некоторых) методов любого объекта, обеспечивая цепной вызов их. К ней также приложена пара готовых дополнительных модулей, один из которых (объёмом 348 байтов) задаёт обёртку вокруг API DOM, а другой (объёмом 406 байтов) задаёт обёртку холстов (<canvas>).

Обёртывание DOM позволяет совершать цепные вызовы наподобие нижеследующих:
// цепной вызов DOM (объектной модели документа):
document.body.appendChild(
   document.createElement('a')
      .prop({
         'href': 'http://leaverou.me',
         'innerHTML': 'Lea Verou',
         'title': 'Visit this awesome blog!',
         'onclick': function(evt){
            alert('gotcha!');
         }
      })
      .setAttribute('data-unicorns', '42')
      .addEventListener('mouseover', function(){
         alert('don’t do this');
      }, false)
);

// цепной вызов CSSOM (объектной модели стилей):
var css = document.body.style.prop({
   color: '#245',
   fontFamily: 'Georgia, serif',
   textDecoration: 'underline'
}).removeProperty('text-decoration').cssText;

// цепной вызов методов classList:
element.classList
   .add('foo')
   .add('bar')
   .toggle('baz');

Выглядит неплохо — но, понятно, при наличии jQuery всё это никому не нужно. Я бы нипочём не стал возёхаться с document.createElement('a') вместо простого $('<a />'), например.

А вот обёртка для холстов (<canvas>) это совсем другое дело. Она не просто обеспечивает цепной вызов методов холста (пример которого я привёл перед тем, как упомянул Chainvas), которого нет в jQuery, но и определяет два полезных вспомогательных метода: circle(x, y, radius) для отрисовки кругов и roundRect(x, y, width, height, radius) для отрисовки закруглённых прямоугольников. (Здесь «отрисовкою» я называю определение начертаний контура, после которого всё же потребуется дополнительный вызов stroke() или fill() для фактического отображения.)

Сладкий, сладкий синтаксический сахар.

Не удивительно поэтому, что и саму библиотеку её автор назвала «Chainvas».
Tags:
Hubs:
+26
Comments 10
Comments Comments 10

Articles