Взаимодействие с цепочкой областей JavaScript

StackOverflow https://stackoverflow.com/questions/1810931

  •  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 .

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top