Взаимодействие с цепочкой областей JavaScript
-
06-07-2019 - |
Вопрос
Учитывая следующий фрагмент javascript в области видимости:
var x = 10;
function sayx() {
alert(x);
}
sayx();
Конечно, вы ожидаете, что в окне сообщения будет напечатано «10», вы можете выполнить несколько вложенных функций, чтобы взаимодействовать с тем, как определяется «x», потому что при определении того, что такое среда, происходит цепочка областей действия.
Вы даже можете выполнить «перекомпиляцию» с помощью eval, чтобы добавить новые области во время выполнения .. например:
var x = 10;
function sayx() {
alert(x);
}
function wrap(f) {
return eval('(function() { var x = 20;(' + f + ')(); })');
}
wrap(sayx)();
Это работает, потому что у функции будет вызываться функция toString, которая будет возвращать «исходный» источник .. таким образом, мы по существу создаем упакованную версию функции, которая имеет новую область видимости, которая переопределяет x .. результатом будет предупреждение поле с надписью «20», а не «10».
Однако на первый взгляд это может работать, но цепочка областей действия не работает, следующий элемент в цепочке уже не тот, потому что функция 'f' теперь определена в другом месте ... еще хуже то, что унаследованная цепочка областей действия может содержать множество ссылок, к которым у вызывающей функции не должно быть доступа.
Итак, есть ли более поддерживаемый и работоспособный способ внедрения элемента области? что-то вроде:
function withScope(f, scope) { ??? }
---
var x = 10, y = 10;
function dothemath() {
alert(x + y);
}
var haxthemath = withScope(dothemath, { x: 9000 });
haxthemath(); // 9010 not 20
Я предполагаю, что ответ «нет», некоторые могут утверждать, что есть проблемы «безопасности» с такой инъекцией области, но, учитывая, что вы все равно можете добиться цели (хотя и сильно сломанной), я не думаю, что это .. р>
Преимущества этого состоят в том, что вы можете подделать свои псевдопеременные.
Заранее спасибо.
<Ч>Отредактируйте, просто поясните немного, представьте, что я хотел 'withScope' функцию, которая имела следующую цепочку областей видимости:
Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }
Я хотел бы иметь возможность вернуть функцию, которая фактически имела бы ту же цепочку + область, которую я предоставляю .. т.е.:
withScope(somefunc, { foo: 'bar' })
дал бы мне
Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }
Ext scope - { foo = 'bar' }
Все предыдущие постоянные переменные будут найдены, потому что моя расширенная область ничего о них не говорит.
Решение
Если вы ссылаетесь на область видимости локальных переменных в функции и / или замыкании, я думаю, что ответ - нет.
Вы можете изменить область действия ключевого слова this
, используя functionName.call (scope, arg1, ...) или functionName.apply (scope, [arg1, ...]); Это можно использовать вместе с прототипами для создания похожих цепочек, как вы описываете - если что-то не найдено в собственных свойствах объекта, это ищется в его прототипе. Если свойство отсутствует, используется следующий прототип в цепочке и т. Д.
Другие советы
ответ, который, я думаю, вы ищете, - это встроенная функция " утверждение.
Однако я бы не рекомендовал использовать его, поскольку он устарел и, скорее всего, не будет существовать в ecmascript 6
Думаю, вы могли бы сделать это еще одним способом - изнутри самого хост-приложения, манипулируя средой javascript извне. Или, если вы используете Rhino, вы можете сделать это изнутри javascript, потому что связь между Java apis и Javascript в Rhino просто такая. Когда Стив Йегге впервые указал, что это взорвало мой разум. Манипулируйте javascript снаружи javascript, но изнутри javascript! Это гений!
Если вы застряли в среде браузера, возможно, вы можете использовать интерпретатор javascript, написанный на javascript, например, narcissus.
Может быть, использовать встроенный в javascript метод toString
для функций?
function withScope(f, scope) {
var toExec = "";
for (var prop in scope) {
toExec += "var " + prop + " = scope['" + prop + "'];"
}
toExec += "f = (" + f.toString() + ")";
eval(toExec);
return f;
}
var x = 10;
var f = function() {
console.log(x);
};
withScope(f, {x: 20})();
Это кажется плохой идеей ...
Если вы хотите поиграть с областью действия, вам может понравиться оператор let
, представленный в Javascript 1.7. Последние версии Firefox поддерживают let
. р>