Как стать автором
Обновить

Простое наследование в стиле Ruby для Javascript

Время на прочтение 3 мин
Количество просмотров 1K
Автор оригинала: John-David Dalton
Сегодня наткнулся довольно занятный gist на github'е.

Вот его код:
/*
*  def.js: Простое наследование в стиле Ruby для Javascript
*
*  Copyright (c) 2010 Tobias Schneider
*  This script is freely distributable under the terms of the MIT license.
*/
(function(global) {

 // Используется, чтобы сохранить суперкласс и "плагины" для
 // дальнейшего использования
 var deferred;

 // Добавляет родителю "плагины"
 function addPlugins(plugins) {
  augment(this.prototype, plugins);
  return this;
 }

 // Копирует аттрибуты и методы объекта "source" в объект "destination"
 function augment(destination, source) {
  for (var key in source) {
   destination[key] = source[key];
  }
 }

 // Пустой класс, необходим для наследования
 function Subclass() { }

 function def(klassName, context) {
  context || (context = global);
  
  // Создаем класс в указаном контексте (по умолчанию global)
  var Klass =
  context[klassName] = function Klass() {
   // Если вызывается как конструктор
   if (this != context) {    
    // Если в классе есть "init" метод, то он может вернуть
    // другой класс/объект
    return this.init && this.init.apply(this, arguments);
   }
   // Вызывается как функция
   // defer setup of superclass and plugins
   // Сохраним в "deferred" класс и "плагины", которые могли быть
   // переданы первым аргументом
   deferred._super = Klass;
   deferred._plugins = arguments[0] || { };
  };

  // Добавляем метод, чтобы запускать его в контексте
  Klass.addPlugins = addPlugins;

  // Будет вызываться эта функция,
  // если класс создается без наследования
  deferred = function(plugins) {
   return Klass.addPlugins(plugins);
  };

  // Благодаря функции valueOf
  // будет осуществляться наследование
  deferred.valueOf = function() {
   // Возьмем класс, который мы сохранили в "deferred"
   var Superclass = deferred._super;
   
   // Если класса нет - значит мы должны
   // вернуть сам класс, чтобы вести себя
   // как нормальная valueOf функция
   if (!Superclass) return Klass;

   // Создаем клон супер класса с пустым конструктором
   Subclass.prototype = Superclass.prototype;
   // Создаем объект
   Klass.prototype = new Subclass;

   // Добавляем superclass классу
   Klass.superclass = Superclass;
   Klass.prototype.constructor = Klass;
   
   // Добавляем "плагины", сохраненые в deferred
   return Klass.addPlugins(deferred._plugins);
  };
  
  // Возвращаем deferred -
  // функцию, принимающую атрибуты и методы, а затем создающую класс
  return deferred;
 }

 // Выносим def из замыкания
 global.def = def;
})(this);




Так же, приводится пример использования:
// Пример

def ('Person') ({
 'init': function(name) {
  this.name = name;
 },
 'speak': function(text) {
  alert(text || 'Здравствуй, меня зовут ' + this.name);
 }
});

def ('Ninja') << Person ({
 'ask': function() {
  this.speak('Ты веришь, что здесь моя скорость и сила зависят от моих мускулов?');
 }
});

var ninjy = new Ninja('Морфеус');
ninjy.speak();
ninjy.ask();



Не похоже на javascript'овый синтаксис, верно?

Как же это работает:


Немного о порядке выполнения:
var a = {valueOf: function(){alert(2)}}
var b = function(){alert(1);}
a << b();


Попробуйте выполнить этот код.
Сначала, выполнится функция b, а потом считается значение(через функцию valueOf) a.

Таким образом, когда вы пишите:
def('a') ({a:1});
def('b') << a ({b:1});

.

Сначала вызовется функция a, созданная в первой строке, с аргументами {b:1}. В это время, в deferred запишется класс, которым нужно дополнить, и набор аттрибутов/методов дополняемого класса.
Затем выполнится def('b').valueOf, возьмется класс и «плагины» из deferred, создастся класс на основе a, и ему запишутся атрибуты/методы.

Все довольно просто и лаконично!
Спасибо jdalton за ссылку на этот гист!

P.S.
Переведенный и дополненный вариант
Теги:
Хабы:
+31
Комментарии 23
Комментарии Комментарии 23

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн