Почему переменные моей функции не доступны в обратном вызове моего обещания? [Дубликат]

Что бы я делал, это игнорировать формат и проверять числовое содержимое:

var originalPhoneNumber = "415-555-1212";

function isValid(p) {
  var phoneRe = /^[2-9]\d{2}[2-9]\d{2}\d{4}$/;
  var digits = p.replace(/\D/g, "");
  return phoneRe.test(digits);
}
113
задан Gabe Kopley 9 February 2015 в 23:19
поделиться

5 ответов

Я нашел отчет о выпуске v8 , который именно о том, что вы просите.

Теперь, чтобы суммировать то, что сказано в этом выпуске ... v8 может хранить переменные, которые являются локальными для функции в стеке или в объекте «context», который живет в куче. Он будет выделять локальные переменные в стеке, пока функция не содержит никакой внутренней функции, которая относится к ним. Это оптимизация. Если любая внутренняя функция ссылается на локальную переменную, эта переменная будет помещена в объект контекста (т. Е. В куче, а не в стеке). Случай eval является особенным: если он вообще вызван внутренней функцией, все локальные переменные помещаются в объект контекста.

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

Отладчик не может проверить те переменные, которые находятся в стеке. Что касается проблемы, возникающей при отладке, один из участников проекта говорит, что :

Единственное решение, о котором я мог думать, это то, что всякий раз, когда devtools включен, мы уничтожаем весь код и перекомпилируем с принудительным контекстным распределением. Это резко изменило бы производительность при использовании devtools.

Вот пример «если какая-либо внутренняя функция относится к переменной, поместите ее в объект контекста». Если вы запустите это, вы сможете получить доступ к x в инструкции debugger, хотя x используется только в функции foo, , которая никогда не называется !

function baz() {
  var x = "x value";
  var z = "z value";

  function foo () {
    console.log(x);
  }

  function bar() {
    debugger;
  };

  bar();
}
baz();
111
ответ дан Louis 16 August 2018 в 11:11
поделиться
  • 1
    Вы поняли способ удаления кода? Мне нравится использовать отладчик как REPL и код там, а затем передать код в свои собственные файлы. Но часто это невозможно, поскольку переменные, которые должны быть там, недоступны. Простой eval этого не сделает. Я слышу бесконечный цикл. – Ray Foss 2 March 2016 в 18:29
  • 2
    Я на самом деле не сталкивался с этой проблемой во время отладки, поэтому я не искал способы удаления кода. – Louis 3 March 2016 в 12:33
  • 3
    Последний комментарий из этой проблемы гласит: Включение V8 в режим, где все принудительно выделено контекстом, возможно, но я не уверен, как / когда запускать это через DevTools UI . Для отладки, Иногда я хотел бы это сделать. Как я могу заставить такой режим? – Suma 30 January 2017 в 11:40
  • 4
    @Louis: для дальнейшего использования этот вопрос является дубликатом. – user208769 17 February 2017 в 10:11
  • 5
    @ user208769 При закрытии в качестве дубликата мы выступаем за вопрос, который является самым полезным для будущих читателей. Есть несколько факторов, которые помогают определить, какой вопрос наиболее полезен: ваш вопрос получил ровно 0 ответов, в то время как у этого был множественный ответный ответ. Поэтому этот вопрос является наиболее полезным из двух. Даты становятся определяющим фактором, только если полезность в основном равна. – Louis 17 February 2017 в 12:20

Я также заметил это в nodejs. Я полагаю (и я допускаю, что это только предположение), что при компиляции кода, если x не появляется внутри bar, он не делает x доступным в области bar. Это, вероятно, делает его несколько более эффективным; проблема заключается в том, что кто-то забыл (или не заботился), что даже если в bar нет x, вы можете решить запустить отладчик и, следовательно, по-прежнему необходимо получить доступ к x изнутри bar.

6
ответ дан David Knipe 16 August 2018 в 11:11
поделиться
  • 1
    Благодарю. В принципе, я хочу объяснить это начинающим javascript лучше, чем «Отладчик». & Quot; – Gabe Kopley 9 February 2015 в 23:22
  • 2
    @GabeKopley: Технически отладчик не лжет. Если переменная не указана, то она не заключена в техническом отношении. Таким образом, интерпретатору не нужно создавать закрытие. – slebetman 21 April 2017 в 15:55
  • 3
    Не в этом дело. При использовании отладчика я часто бывал в ситуации, когда мне хотелось знать значение переменной во внешней области, но не могло из-за этого. И на более философской ноте я бы сказал, что отладчик лжет. Независимо от того, существует ли переменная во внутренней области, она не должна зависеть от того, действительно ли она используется или существует ли не связанная команда eval. Если переменная объявлена, она должна быть доступна. – David Knipe 22 April 2017 в 11:30

Ничего себе, действительно интересно!

Как уже упоминалось, это, по-видимому, связано с scope, но более конкретно, связано с debugger scope. Когда внедренный скрипт оценивается в инструментах разработчика, он, как представляется, определяет ScopeChain, что приводит к некоторой причудливости (поскольку оно связано с областью инспектора / отладчика). Вариант того, что вы разместили, это:

(EDIT - на самом деле, вы упомянули об этом в своем исходном вопросе, yikes, мой плохой! )

function foo() {
  var x = "bat";
  var y = "man";

  function bar() {
    console.log(x); // logs "bat"

    debugger; // Attempting to access "y" throws the following
              // Uncaught ReferenceError: y is not defined
              // However, x is available in the scopeChain. Weird!
  }
  bar();
}
foo();

Для амбициозного и / или любопытного масштаба (heh) из источника, чтобы узнать, что происходит:

https://github.com/WebKit/webkit/tree/master/Source / JavaScriptCore / inspector https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/debugger

2
ответ дан Jack 16 August 2018 в 11:11
поделиться

Я подозреваю, что это связано с перестановкой переменных и функций. JavaScript приносит все объявления переменных и функций в начало функции, в которой они определены. Дополнительная информация здесь: http://jamesallardice.com/explaining-function-and-variable-hoisting-in-javascript/

Бьюсь об заклад, что Chrome вызывает точку прерывания с переменной, недоступной для области видимости, потому что в функции больше ничего нет. Это работает:

function baz() {
  var x = "foo";

  function bar() {
    console.log(x); 
    debugger;
  };
  bar();
}

Как это делает:

function baz() {
  var x = "foo";

  function bar() {
    debugger;
    console.log(x);     
  };
  bar();
}

Надеюсь, что и / или ссылка выше помогает. Это мой любимый вид вопросов SO, BTW:)

0
ответ дан markle976 16 August 2018 в 11:11
поделиться
  • 1
    Благодаря! :) Мне интересно, что делает FF по-другому. С моей точки зрения, как разработчик, опыт FF объективно лучше ... – Gabe Kopley 9 February 2015 в 19:34
  • 2
    «вызов точки прерывания в лекс-время» Я сомневаюсь в этом. Это не то, что нужно для контрольных точек. И я не понимаю, почему имеет значение отсутствие других функций в функции. Сказав это, если это что-то вроде nodejs, то точки останова могут быть очень ошибочными. – David Knipe 9 February 2015 в 23:11

Как @Louis сказал, что это вызвано оптимизациями v8. Вы можете перемещать стек вызовов в кадр, где эта переменная видна:

Или заменить debugger на

eval('debugger');

eval отключит текущий кусок

14
ответ дан OwnageIsMagic 16 August 2018 в 11:11
поделиться
  • 1
    Почти здорово! Он приостанавливается в модуле VM (желтый) с содержимым debugger, и контекст действительно доступен. Если вы повышаете стек на один уровень до кода, который вы пытаетесь отлаживать, вы снова не имеете доступа к контексту. Так что это просто немного неуклюже, не имея возможности смотреть на код, который вы отлаживаете, при доступе к скрытым переменным закрытия. Тем не менее, я буду поддерживать, поскольку это избавляет меня от необходимости добавлять код, который явно не предназначен для отладки, и он дает мне доступ ко всему контексту без деоптимизации всего приложения. – Sigfried 27 July 2017 в 11:12
  • 2
    О ... это даже clunkier, чем использовать желтое окно eval ed source, чтобы получить доступ к контексту: вы не можете пройти через код (если вы не поместите eval('debugger') между всеми строками, которые вы хотите пройти). – Sigfried 27 July 2017 в 12:46
Другие вопросы по тегам:

Похожие вопросы: