Сегодня наткнулся довольно занятный gist на github'е.
Вот его код:
Так же, приводится пример использования:
Не похоже на javascript'овый синтаксис, верно?
Немного о порядке выполнения:
Попробуйте выполнить этот код.
Сначала, выполнится функция b, а потом считается значение(через функцию valueOf) a.
Таким образом, когда вы пишите:
Сначала вызовется функция a, созданная в первой строке, с аргументами {b:1}. В это время, в deferred запишется класс, которым нужно дополнить, и набор аттрибутов/методов дополняемого класса.
Затем выполнится def('b').valueOf, возьмется класс и «плагины» из deferred, создастся класс на основе a, и ему запишутся атрибуты/методы.
Все довольно просто и лаконично!
Спасибо jdalton за ссылку на этот гист!
P.S.
Переведенный и дополненный вариант
Вот его код:
/*
* 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.
Переведенный и дополненный вариант