Created
July 14, 2010 07:08
-
-
Save indutny/475129 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* def.js: Простое наследование в стиле Ruby для Javascript | |
* | |
* Copyright (c) 2010 Tobias Schneider | |
* This script is freely distributable under the terms of the MIT license. | |
*/ | |
(function(global) { | |
// Используется, чтобы сохранить суперкласс и "плагины" ля | |
// дальнейшего использования | |
// used to defer setup of superclass and plugins | |
var deferred; | |
// Добавляет родителю "плагины" | |
function addPlugins(plugins) { | |
augment(this, this.prototype, plugins); | |
return this; | |
} | |
// Копирует аттрибуты и методы объекта "source" в объект "destination" | |
// И в его прототип | |
// TODO: Ensure we fix IE to iterate over shadowed properties | |
// of those further up the prototype chain. There is also a | |
// bug in Safari 2 that will match the shadowed property and | |
// the one further up the prototype chain. | |
function augment(destination, destinationPrototype, source) { | |
for (var key in source) { | |
destinationPrototype[key] = destination[key] = source[key]; | |
} | |
} | |
// Пустой класс, необходим для наследования | |
// dummy subclass | |
function Subclass() { } | |
function def(klassName, context) { | |
context || (context = global); | |
// Создаем класс в указаном контексте (по умолчанию global) | |
// create class on given context (defaults to global object) | |
var Klass = | |
context[klassName] = function Klass() { | |
// Если вызывается как конструктор | |
// called as a constructor | |
if (this != context) { | |
// Если в классе есть "init" метод, то он может вернуть | |
// другой класс/объект | |
// allow the init method to return a different class/object | |
return this.init && this.init.apply(this, arguments); | |
} | |
// Вызывается как функция | |
// defer setup of superclass and plugins | |
// Сохраним в "deferred" класс и "плагины", которые могли быть | |
// переданы первым аргументом | |
// called as a method | |
// defer setup of superclass and plugins | |
deferred._super = Klass; | |
deferred._plugins = arguments[0] || { }; | |
}; | |
// Добавляем метод, чтобы запускать его в контексте | |
// add static helper method | |
Klass.addPlugins = addPlugins; | |
// Будет вызываться эта функция, | |
// если класс создается без наследования | |
// called as function when not | |
// inheriting from a superclass | |
deferred = function(plugins) { | |
return Klass.addPlugins(plugins); | |
}; | |
// Благодаря функции valueOf | |
// будет осуществляться наследование | |
// valueOf is called to setup | |
// inheritance from a superclass | |
deferred.valueOf = function() { | |
// Возьмем класс, который мы сохранили в "deferred" | |
var Superclass = deferred._super; | |
// Если класса нет - значит мы должны | |
// вернуть сам класс, чтобы вести себя | |
// как нормальная valueOf функция | |
if (!Superclass) return Klass.valueOf();; | |
// Создаем клон супер класса с пустым конструктором | |
Subclass.prototype = Superclass.prototype; | |
// Создаем объект | |
Klass.prototype = new Subclass; | |
// Добавляем superclass классу | |
Klass.superclass = Superclass; | |
Klass.prototype.constructor = Klass; | |
// Добавляем "плагины", сохраненые в deferred | |
Klass.addPlugins(deferred._plugins); | |
// Возвращаем нормальное valueOf | |
// the result of the inheritance experession | |
// isn't normally captured so this is really edge | |
// case stuff here and of little practical use | |
return Klass.valueOf() | |
}; | |
// Возвращаем deferred - | |
// функцию, принимающую атрибуты и методы, а затем создающую класс | |
return deferred; | |
} | |
// Выносим def из замыкания | |
// expose | |
global.def = def; | |
})(this); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example | |
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(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment