Этот синтаксис JavaScript, который я до сих пор не видел, что он действительно делает?
Сегодня я видел синтаксис JavaScript (при вызове функции), который мне незнакомец. Это было похоже:
def('Person') ({
init: function(name) {this.name=name;}
,speak: function(text) {alert(text || 'Hi, my name is ' + this.name);}
});
и
def('Ninja') << Person ({
kick: function() {this.speak('I kick u!');}
});
1: Что происходит с объектом в круглых скобках в первом примере? Он каким-то образом обрабатывается функцией def
, но я не понимаю, что здесь происходит (см. Функцию def
ниже). Куда идет объект?
2: Примерно так же, но использование оператора <<
, которого я никогда не видел (я думаю!). Что это значит?
Код из http://gist.github.com/474994, где Джо Далтон сделал небольшую вещь для наследования JavaScript-OO (это, по-видимому, вилка кто-то другой работает, но довольно тщательно переписан, как кажется). Может быть, вы захотите проверить это там, на что ссылается функция def
, которую я вам даю:
function def(klassName, context) {
context || (context = global);
// Create class on given context (defaults to global object)
var Klass =
context[klassName] = function Klass() {
// Called as a constructor
if (this != context) {
// Allow the init method to return a different class/object
return this.init && this.init.apply(this, arguments);
}
// 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 is called to set up
// inheritance from a superclass
deferred.valueOf = function() {
var Superclass = deferred._super;
if (!Superclass)
return Klass;
Subclass.prototype = Superclass.prototype;
Klass.prototype = new Subclass;
Klass.superclass = Superclass;
Klass.prototype.constructor = Klass;
return Klass.addPlugins(deferred._plugins);
};
return deferred;
}
Ответы
Ответ 1
1: вызов def('Person')
возвращает функцию, вызываемую с параметром object. Это тот же принцип, что и:
function x() {
return function(y) { alert(y); }
}
x()('Hello world!');
2: Оператор <<
- это оператор сдвига влево. Он сдвигает целочисленное значение на определенное количество бит влево. Я не нашел ссылок на какое-либо другое использование для него, и в Javascript нет перегрузки оператора, поэтому я не могу понять, как использовать его для функции. Пока это выглядит опечаткой для меня.
Edit:
Как пояснил Тим, оператор сдвига просто используется, чтобы вызвать вызов метода valueOf
. Он работает как перегрузка всех операторов, принимая первоначальную цель и делая что-то совершенно другое.
Ответ 2
Ничего себе, это было достаточно сложным для понимания моего крошечного мозга, но я чувствую себя намного лучше, зная, как это работает:) Благодаря @Tim для указания трюка valueOf()
.
Общий случай создания "class"
с использованием:
def ("ClassName") ({
init: function() { .. },
foo: function() { .. }
});
является тривиальным, так как первый вызов def
возвращает функцию, которая принимает объект и копирует свойства переданного объекта, прототипу ClassName
.
Более интересный случай использования <<
для подкласса зависит от порядка оценки выражения, а также от попыток принудительного принуждения любого объекта к значению с помощью неявного вызова valueOf()
. Основной трюк - это в основном общая переменная, которая записывает суперкласс и свойства, которые будут применяться к нему. Выражение
def("ClassName") << ParentClass({ .. })
будет оцениваться следующим образом:
-
def("ClassName")
вызывается и создает глобальный объект ClassName
и возвращает свою конструкторскую функцию. Позвольте называть этот возвращенный объект - initializeMeLater
.
Вызывается -
ParentClass(..)
, где хранится ссылка на ParentClass
, и передается в объекте/свойствах в общей переменной.
Вызывается -
initializeMeLater.valueOf()
, который получает ссылку на родительский класс и свойства этой общей переменной и устанавливает прототипы.
-
valueOf
вызывается на возвращаемое значение с шага 2, которое бесполезно и не имеет никакого эффекта, поскольку мы уже установили отношение суперкласса на шаге 3.
Код пытается эмулировать синтаксис Ruby для создания подклассов, который выглядит следующим образом:
class Child < Parent
def someMethod
...
end
end