Эксперты JavaScript: почему `with` сводит на нет оптимизацию компилятора, связанную с областью видимости

1

Чтение Кайл Симпсона Вы не знаете JS: Scopes & Closures, он утверждает, что вы должны держаться подальше от обоих eval() функции, и with ключевым словом, потому что всякий раз, когда компилятор видит эти два (я перефразирую), это не выполнить некоторые оптимизации, связанные с лексической областью, и сохранить расположение идентификаторов, потому что эти ключевые слова могут потенциально изменить лексическую область, что делает оптимизацию компилятора неправильной (я предполагаю, что оптимизация - это что-то вроде компилятора, хранящего местоположение каждого идентификатора, так что он может предоставить значение идентификатора без его поиска, когда он запрашивается во время выполнения).

Теперь я понимаю, почему это произойдет, когда вы используете ключевое слово eval(): ваш eval может оценивать ввод пользователя, а этот пользовательский ввод может быть объявлением новой переменной, которая затеняет другую переменную, к которой вы обращаетесь позже. выполняемая функция, если компилятор сохранил статическое местоположение, доступ вернет значение неправильного идентификатора (поскольку доступ должен был вернуть значение идентификатора, объявленного eval(), но оно вернуло значение переменная, которая была сохранена компилятором для оптимизации поиска). Поэтому я просто предполагаю, что именно поэтому компилятор не выполняет зависящие от масштаба объекты, когда он видит код eval() в вашем коде.

Но почему компилятор делать то же самое для with ключевым словом? В книге говорится, что он делает это потому, что with создает новую лексическую область во время выполнения, и он использует свойство объекта, переданный в качестве аргумента with объявить новые идентификаторы. Я в буквальном смысле понятия не имею, что это значит, и мне очень трудно пытаться визуализировать все это, потому что все связанные с компилятором вещи в этой книге - это вся теория.

Я знаю, что я могу ошибиться, в этом случае, пожалуйста, любезно исправьте все мои недоразумения :)

  • 0
    @Bergi Я не спрашиваю , почему это вредно, я спрашиваю «почему компилятор не выполняет объемы работ , связанные с оптимизациями , если есть with присутствовать в коде». На какой из этих вопросов ответили в этой статье?
  • 0
    Причина не использовать with в 2017 году не в оптимизации, а в том, что мы пишем код строгого режима или ES6, в котором это даже не разрешено законом.
Показать ещё 1 комментарий
Теги:
v8
lexical-scope
spidermonkey

2 ответа

4
Лучший ответ

Приведенная здесь оптимизация основана на этом факте: переменные, объявленные внутри функции, всегда могут быть определены посредством простого статического анализа кода (т.е. var поиска объявлений var/let и function) и набора объявленных переменных в пределах функция никогда не изменяется.

eval нарушает это предположение, введя способность мутировать локальную привязку (путем ввода новых переменных в область функций во время выполнения). with нарушением этого предположения, введя новое нелексическое связывание внутри функции, свойства которой вычисляются во время выполнения. Статический анализ кода не всегда может определить, от свойств with объектом, так что анализатор не может определить, какие переменные существуют в пределах with блоком. Важно отметить, что объект, поставляемый with может меняться между выполнением функции, что означает, что набор переменных внутри этого лексического раздела функции никогда не может быть гарантированно согласован.

Рассмотрим простую функцию:

function foo() {
    var a, b;
    function c() { ... }
    ...
}

Все точки в foo имеют три переменные локальной области видимости: a, b и c. Оптимизатор может присоединить к функции, которая говорит: "Эта функция имеет три переменные: a, b и c. Это никогда не изменится".

Теперь рассмотрим:

function bar(egg) {
    var a, b;
    function c() { ... }

    with(egg) {
        ...
    }
}

В блоке " with неизвестно, какие переменные будут или не будут существовать. Если есть, a b или c в with, мы не знаем, до времени выполнения, если это относится к переменному bar или которую создают with(egg) лексической областью.

Чтобы показать полу-практический пример того, как это проблема, в конце рассмотрим:

function baz(egg) {
    with(egg) {
        return function() { return whereami; }
    }
}

Когда выполняется внутренняя функция (например, bar({...})()), механизм выполнения будет искать цепочку областей для поиска whereami. Если оптимизатору было разрешено прикреплять постоянную заметку к baz, тогда механизм выполнения сразу же узнает, что функция baz whereami для значения whereami, потому что это будет гарантировано стать домом для whereami (любой аналогично - именованная переменная вверх по цепочке областей видимости будет затенена ближайшим). Тем не менее, он не знает, если whereami существует в baz или нет, потому что это может быть условно создано содержимое egg на конкретном пробеге bar, создавшего, что внутренняя функция. Поэтому он должен проверять, и оптимизация не используется.

  • 0
    добавление нескольких примеров кода добавило бы ценность ответа :)
  • 0
    « мы не знаем до времени выполнения » - мы даже не всегда знаем во время выполнения, когда вводится оператор with . Нам нужно проверять объект каждый раз, когда к переменной обращаются. Также это, конечно, предотвращает оптимизацию компилятора, которая переупорядочивает, дублирует или избегает доступа к переменным.
Показать ещё 11 комментариев
0

Возьмем следующий пример:

{
 let a = 1; //stored at 123
 {
   let b = 2; //stored at 124
   console.log(a/*123*/,b/*124*/);
 }
}

И теперь это:

{
 let a = 1;//stored at 123
 with({a:3}){
   console.log(a /*123 ??*/);
 }
}
  • 0
    Не могли бы вы быть более понятным / добавить некоторые описания?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню