Лексическая область действия / замыкания в javaScript

Я понимаю, что функции в 'js' имеют лексическую область видимости (т.е. функции создают свою среду (область видимости), когда они определены, а не когда они выполняются).

function f1() {
    var a = 1;
    f2();
}

function f2() {
    return a;
}
f1(); // a is not defined

Когда я запускаю просто 'f ()', он возвращает внутреннюю функцию. Что я получаю, это то, что делает "возврат"!

function f() {
    var b = "barb";
    return function() {
        return b;
    }
}
console.log(b); //ReferenceError: b is not defined

Почему вы получаете 'ReferenceError: b не определено?' Но разве вышеприведенная внутренняя функция не имеет доступа к своему пространству, пространству f () и т. Д. Учитывая, что 'b' возвращается в глобальное пространство, разве не будет работать console.log()?

Однако, когда я назначаю 'f ()' новой переменной и запускаю ее:

 var x = f(); 
 x();// "barb"
 console.log(b); //ReferenceError: b is not defined

Это возвращает "b", что означает "barb", но когда вы снова запустите console.log(), вы получите "ReferenceError:" b "не определено"; Разве "b" не находится в глобальной области видимости, так как он был возвращен? Так почему же "x()" также не вернул внутреннюю функцию, как "f ()"?

4 ответа

Решение

Вы, мой друг, полностью сбиты с толку. Ваше первое утверждение само по себе неверно:

функции создают свою среду (область видимости), когда они определены, а не когда они выполняются

На самом деле все наоборот. Определение функции не создает область видимости. Вызов функции создает область.

Что такое сфера?

Проще говоря, область действия - это продолжительность жизни переменной. Видите ли, каждая переменная рождается, живет и умирает. Начало области отмечает время, когда переменная рождается, а конец области отмечает время, когда она умирает.

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

Например, рассмотрим эту программу (это не JavaScript):

x = 10       // global variable x

{            // beginning of a scope
    x = 20   // local variable x
    print(x) // 20
}            // end of the scope

print(x)     // 10

Здесь мы создали глобальную переменную под названием x, Затем мы создали область видимости блока. Внутри этого блока мы создали локальную переменную x, Поскольку локальные переменные затеняют глобальные переменные, когда мы печатаем x мы получаем 20, Вернуться в глобальную сферу, когда мы печатаем x мы получаем 10 (местный x сейчас мертв).

Блок Области и Функциональные Области

В настоящее время в программировании существует два основных типа областей действия - области блоков и области функций.

Область в предыдущем примере была областью блока. Это просто блок кода. Отсюда и название. Области применения блоков выполняются немедленно.

Области функций, с другой стороны, являются шаблонами областей блоков. Как следует из названия, область действия функции принадлежит функции. Однако, точнее, это относится к вызову функции. Области действия функции не существуют, пока функция не будет вызвана. Например:

var x = 10

function inc(x) {
    print(x + 1);
}

inc(3);   // 4
print(x); // 10
inc(7);   // 8

Как вы можете видеть каждый раз, когда вызываете функцию, создается новая область. Вот почему вы получаете результаты 4, 10 а также 8,

JavaScript имеет только функциональные области. У него нет блочных областей. Следовательно, если вы хотите создать область видимости блока, вам нужно создать функцию и немедленно выполнить ее:

var x = 10;     // global variable x

(function () {  // beginning of a scope
    var x = 20; // local variable x
    print(x);   // 20
}());           // end of the scope

print(x);       // 10

Этот шаблон называется выражением функции, вызываемой немедленно (IIFE).

Лексические Области и Динамические Области

Области действия функций снова могут быть двух типов - лексическими и динамическими. Видите ли, в функции есть два типа переменных:

  1. Свободные переменные
  2. Связанные переменные

Переменные, объявленные внутри области видимости, привязаны к этой области. Переменные, не объявленные внутри области, являются свободными. Эти свободные переменные принадлежат какой-то другой области, но какой?

Лексическая сфера

В лексической области видимости переменные должны принадлежать родительской области видимости. Например:

function add(x) {         // template of a new scope, x is bound in this scope
    return function (y) { // template of a new scope, x is free, y is bound
        return x + y;     // x resolves to the parent scope
    };
}

var add10 = add(10);      // create a new scope for x and return a function
print(add10(20));         // create a new scope for y and return x + y

JavaScript, как и большинство языков программирования, имеет лексическую область видимости.

Динамическая сфера

В отличие от лексической области видимости, в динамической области видимости переменные должны принадлежать области вызова (области действия вызывающей функции). Например (это также не JS - у него нет динамических областей):

function add(y) {   // template of a new scope, y is bound, x is free
    return x + y;   // x resolves to the calling scope
}

function add10(y) { // template of a new scope, bind y
    var x = 10;     // bind x
    return add(y);  // add x and y
}

print(add10(20));   // calling add10 creates a new scope (the calling scope)
                    // the x in add resolves to 10 because the x in add10 is 10

Вот и все. Просто верно?

Эта проблема

Проблема с вашей первой программой в том, что JavaScript не имеет динамической области видимости. У него есть только лексическая область видимости. Видишь ошибку?

function f1() {
    var a = 1;
    f2();
}

function f2() {
    return a;
}

f1(); // a is not defined (obviously - f2 can't access the `a` inside f1)

Ваша вторая программа - очень большой беспорядок:

function f() {
    var b = "barb";

    return function() {
        return b;
    }
}

console.log(b); //ReferenceError: b is not defined

Вот ошибки:

  1. Ты никогда не звонил f, Отсюда и переменная b никогда не создается.
  2. Даже если ты позвонил f переменная b будет местным f,

Это то, что вам нужно сделать:

function f() {
    var b = "barb";

    return function() {
        return b;
    }
}

var x = f();

console.log(x());

Когда вы звоните x это возвращается b, Однако это не делает b Глобальный. Делать b Глобальный вам нужно сделать это:

var x = f();
var b = x();
console.log(b);

Надеюсь, что это помогло вам понять объемы и функции.

Вы получите "ReferenceError: b не определено", потому что "b" не определено там, где ваш console.log() Звонок есть. Внутри этой функции есть буква "b", но не снаружи. Ваше утверждение о том, что "b возвращается в глобальное пространство", неверно.

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

    function f1() {
          var a = 1;
          f2();
          }

    function f2() {
       return a;
    }
    f1(); // a is not defined
  1. f2(); не знает об a, потому что вы никогда не передавали ему "a" (то есть Scope создаются, когда функции определены). Функция look f2 () смогла бы получить доступ к a, если бы она была определена внутри f1();[Функции могут обращаться к переменным в той же области видимости, в которой они "ОПРЕДЕЛЕНЫ", а НЕ "ВЫЗОВАНЫ"]

    function f() {
       var b = "barb";
       return function(){
                         return b;
                        }
    }
    console.log(b); 
    
  2. Прежде всего, вам нужно вызвать f (); после выполнения f (); он вернул бы другую функцию, которая должна быть выполнена. т.е.

    var a=f();
    a();
    

    это приведет к "barb", в этом случае вы возвращаете функцию, а не var b;

    function f() {
       var b = "barb";
       return b;
                 };
    
    console.log(f());
    

    Это напечатало бы бородку на экране

Но разве вышеприведенная внутренняя функция не имеет доступа к своему пространству, пространству f() и т. Д.

Да, это имеет. Доступ к b переменная и возвращает ее значение из функции.

То, что "б" возвращается в мировое пространство

Нет. Возврат значения из функции не означает "сделать переменную доступной в области действия вызывающего". Вызов функции (с f()) - это выражение, результатом которого является значение, которое вернула функция (в вашем случае, объект без имени). Это значение может быть назначено где-то x), к его свойству можно получить доступ или от него можно отказаться.

Переменная b однако остается частным в области, где это было объявлено. Это не [определяется] определено в области, где вы звоните console.logВот почему вы получаете ошибку.

То, что вы хотите, кажется,

var x = f();
var b = x(); // declare new variable b here, assign the returned value
console.log( b ); // logs "barb"
Другие вопросы по тегам