Разъяснение Javascript Контекст выполнения - PullRequest
0 голосов
/ 16 марта 2020

Я пытался укрепить мое понимание контекста выполнения JS, и у меня возникли проблемы с получением объяснения, почему код, приведенный ниже, не выводит «hello world».

var foo = "foo";

function test1() {
    console.log(foo)
    var bar = "hello world";
    test2();
}

function test2() {
    console.log(bar);
}

test1();

По моему (очень сомнительному) пониманию, test2(), будучи выполненным внутри test1(), имеет доступ к контексту выполнения test1() и должен иметь возможность разрешать имя переменной bar путем перемещения вверх по цепочке областей действия в контекст выполнения test1(), где определено bar. Вместо этого я получаю ошибку ссылки при попытке напечатать bar.

. Я могу понять, как работает приведенный ниже код, из-за лексической области видимости JS, но я был бы признателен за объяснение того, как JS интерпретирует каждый по-разному с точки зрения контекста исполнения и цепочек контекста.

function test1() {
    console.log(foo)
    var bar = "hello world";
    function test2() {
        console.log(bar);
    }
    test2();
}

test1();

До сих пор моя лучшая попытка найти объяснение для себя заключалась в изменении первого блока кода следующим образом:

var foo = "foo";
var bar = "not hello world :("

function test1() {
    console.log(foo)
    var bar = "hello world";
    test2();
}

function test2() {
    console.log(bar);
}

test1();

Здесь вызов test2() выводит "not hello world :(", определенный в глобальной области видимости. Сначала я подумал, что test2() поднимается по цепочке областей видимости в контекст выполнения test1, в глобальную область. контекст выполнения, но это не кажется правильным, поскольку он нашел бы определение для bar внутри test1() до достижения глобального определения. Таким образом, мое второе предположение состоит в том, что определение test2() создает " закрытие "-подобный захват глобального контекста выполнения, когда он был определен, и вызов его в пределах test1() приводит к значению для bar значения null / undefined, поскольку это было его значение при определении функции (вообще не имеет декларации для подъема). Таким образом, он не перемещается в контекст выполнения test1() для поиска идентификатора.

Любые объяснения / ресурсы были бы чрезвычайно полезны. Я, очевидно, очень плохо знаком с языком, поэтому извиняюсь, если мой словарный запас / терминология не совсем верны. Заранее спасибо за помощь.

1 Ответ

1 голос
/ 16 марта 2020

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

test2() не может получить доступ к bar, поскольку в этой области нет переменной с именем bar, когда функция объявляется. Там нет никакого способа манипулировать этой локальной областью после факта. Он установлен в камне.

Это означает, что функция может получить доступ к переменной в локальной области видимости или в любой области видимости, которая содержит объявление этой функции. Это означает следование парам фигурных скобок {}, которые содержат объявление этой функции, вплоть до root файла. Думайте об этом как о дереве: ваша функция будет иметь доступ к любой переменной между этой функцией и root дерева. не будет иметь доступ к другим ветвям этого дерева.


И это действительно хорошая вещь. Это обеспечивает хорошую инкапсуляцию. Вы хотите, чтобы ваши функции были черными ящиками с точки зрения звонящего. Вы хотите, чтобы локальные переменные в вашей функции были действительно локальными. И вы хотите знать, к каким переменным имеет доступ функция, когда вы пишете функцию, а не удивляться тому, какие значения появляются, когда вы запускаете функцию.

...