我了解``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”,即“倒钩”,但是当您再次运行console.log()时,将得到“ReferenceError:'b'is not defined'”;自从它返回后,它现在不在全局范围内吗?那么,为什么'x()'也没有像'f()'一样返回内部函数呢?

最佳答案

您,我的 friend ,非常困惑。您的第一个陈述本身就是错误的:

其实是相反的。定义函数不会创建作用域。调用函数将创建作用域。
范围是什么?
简而言之,作用域是变量的生命周期。您会看到,每个变量都是天生的,是生死的。作用域的开始标记变量的出生时间,作用域的结束标记变量死亡的时间。
一开始只有一个范围(称为程序范围或全局范围)。在此范围内创建的变量仅在程序结束时消失。它们称为全局变量。
例如,考虑以下程序:

const x = 10;       // global variable x

{                   // beginning of a scope
    const x = 20;   // local variable x
    console.log(x); // 20
}                   // end of the scope

console.log(x);     // 10

在这里,我们创建了一个名为x的全局变量。然后,我们创建了一个块作用域。在此块作用域内,我们创建了一个局部变量x。由于当我们记录x时局部变量会遮盖全局变量,因此我们得到20。当我们记录x时,回到全局范围中,我们得到10(本地x现在已死)。
块范围和功能范围
现在,编程中的作用域主要有两种类型:块作用域和函数作用域。
上一个示例中的作用域是一个块作用域。这只是一段代码。由此得名。块作用域将立即执行。
另一方面,功能范围是块范围的模板。顾名思义,功能范围属于功能。但是,更确切地说,它属于函数调用。在调用函数之前,函数作用域不存在。例如:

const x = 10;

function inc(x) {
    console.log(x + 1);
}

inc(3);         // 4
console.log(x); // 10
inc(7);         // 8

如您所见,每次调用函数时,都会创建一个新的作用域。这就是获得输出4108的原因。
最初,JavaScript仅具有函数作用域。它没有块作用域。因此,如果要创建块作用域,则必须创建一个函数并立即执行它:

const x = 10;         // global variable x

(function () {        // beginning of a scope
    const x = 20;     // local variable x
    console.log(x);   // 20
}());                 // end of the scope

console.log(x);       // 10

这种模式称为immediately invoked function expression (IIFE)。当然,如今,我们可以使用 const let 创建块作用域变量。
词汇范围和动态范围
函数范围又可以是两种类型-词法和动态。您会看到,在函数中有两种类型的变量:
  • 免费变量
  • 绑定(bind)变量

  • 在作用域内声明的变量将绑定(bind)到该作用域。未在范围内声明的变量是免费的。这些自由变量属于其他范围,但是哪一个呢?
    词汇范围
    在词法作用域中,自由变量必须属于父作用域。例如:

    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
        };
    }
    
    const add10 = add(10);    // create a new scope for x and return a function
    console.log(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

    这是错误:
  • 您从未调用过f。因此,永远不会创建变量b
  • 即使您调用了f,该变量b也将是f的本地变量。

  • 这是您需要做的:

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

    当您调用x时,它将返回b。但是,这并不能使b成为全局的。要使b成为全局代码,您需要执行以下操作:

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

    希望这有助于您了解范围和功能。

    关于javascript - javaScript中的词法作用域/闭包,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17279437/

    10-13 09:03