#javascript #eval #decorator #hoisting
#javascript #оценка #декоратор #подъем
Вопрос:
Я играю с декораторами функций. Я хотел бы иметь способ легко украшать функции без необходимости делать это там, где объявлена функция.
var __slice = [].slice;
this.around = function(decoration) {
return function(base) {
return function() {
var argv, callback, __value__,
_this = this;
argv = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
__value__ = void 0;
callback = function() {
return __value__ = base.apply(_this, argv);
};
decoration.apply(this, [callback].concat(argv));
return __value__;
};
};
};
f("from outer");
function f(a){
console.log("f OUTER",a);
};
f("from outer");
(function g(){
f("from Inner (hoisted)");
function addDecorator(decoration, fn) {
var decorated = around(decoration)(fn);
eval(fn.name " = decorated");
decorated.unDecorate = function (){
eval(fn.name " = fn");
}
}
function myDecorator(cb){
console.log("before");
cb();
console.log("after");
}
function f(a){
console.log("f INNER",a);
}
f("from Inner (after declaration)");
addDecorator(myDecorator, f);
f("from Inner (Decorated)");
f.unDecorate();
f("from Inner (Undecorated)");
})();
f("from outer");
Я хочу иметь возможность вызывать addDecorator
где угодно внутри g
. т. е. вверху, где f
он поднят над его объявлением.
В консоли Chrome я получаю следующий вывод:
f OUTER from outer
f OUTER from outer
f INNER from Inner (hoisted)
f INNER from Inner (after declaration)
before
f INNER from Inner (Decorated)
after
f INNER from Inner (Undecorated)
f OUTER from outer
- Можно ли это сделать без eval?
- Можно ли переместить addDecorator за пределы g? (не так важно)
Комментарии:
1. Я не совсем понимаю, о чем вы спрашиваете, но если главный вопрос — могу ли я вызвать decorated
f
поверхg
до того, как к нему было применено оформлениеf
— мой ответ нет. Подъем выводит тела функций для использования выше в коде, чем те функции, которым они назначены, но оформление — это операция, а не объявление, поэтому это произойдет только в данный момент в последовательности выполнения.2. Нет, вопрос не в этом. Это очень интересный способ переопределения функций — и кажется, что ответы на оба вопроса на самом деле «нет». Тем не менее, я все еще исследую.)
3. @Brock, f поднимается до вершины g, в g добавляется украшение, затем объявляется f . Я не ожидал, что смогу вызвать decorated f перед вызовом функции декоратора.
4. Я приму ответы, которые изменяют
g
структуру или вызываются, еслиaddDecorator
можно узнать, где определена переданная функция, поэтому ей не нужно возвращать оформленную функцию, которая будет присвоена имени исходной функции. т. Е. Я не хочу иметь подобный кодf = addDecorator(d,f)
, поэтому я могу сделатьвариационная версия:addDecorationXxToAllOf(f1, f2, f3)
5. @SamHasler: ответ определенно «нет» на оба вопроса. В отличие от глобальной области видимости, JavaScript явно не дает вам способа доступа к области видимости функции каким-либо общим способом. Таким образом, вы можете либо вернуть новое значение функции, либо использовать объект для хранения функций. Обратите внимание, что
instrumentFunction
вышеописанное также работает только для глобальных функций, к которым можно получить доступ.
Ответ №1:
Вы можете как исключить eval
, так и переместить функцию за пределы g
, если хотите немного изменить свое соглашение.
Это будет иметь тот же эффект, но вызывается немного по-другому:
function addDecorator(decoration, fn) {
var decorated = around(decoration)(fn);
decorated.unDecorate = function () {
return fn;
}
return decorated;
}
f = addDecorator(myDecorator, f);
f = f.unDecorate();
Если вы не хотите менять способ ее вызова / использования, то, боюсь, ответ на оба ваших вопроса — нет.
Комментарии:
1. Я думаю, что я был бы более готов поместить все свои функции внутрь объекта, чтобы я мог выполнить передачу объекта в addDecorator, чтобы избежать необходимости выполнять назначение.
2. @SamHasler также выполнимо. Так или иначе, я полагаю, вам придется изменить свой подход, чтобы добиться удаления
eval
.