在javaScript中的词法作用域/闭包 [英] Lexical scope/closures in javaScript

查看:130
本文介绍了在javaScript中的词法作用域/闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我理解'js'中的函数具有词法作用域(即函数创建它们的环境(范围),而不是当它们被执行时。)

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

function f2(){
return a;
}
f1(); // a未定义



当我运行'f()'时,它返回内部函数。

  function f(){
var b =barb ;
return function(){
return b;
}
}
console.log(b); // ReferenceError:b未定义

为什么会出现ReferenceError:b is not defined?
但是上面的内部函数没有访问它的空间,f()的空间等。由于'b'正在返回到全局空间,console.log()不会工作?



但是,当我将'f()'赋给一个新的变量并运行时:

  var x = f(); 
x(); //barb
console.log(b); //参考错误:b未定义

这将返回bar你再次运行console.log()会得到'ReferenceError:'b'is not defined';自从返回后,现在在全局范围中不是b吗?为什么没有'x()'也像'f()'一样返回内部函数?

解决方案

,我的朋友,都彻底困惑。你的第一个语句本身是错误的:



>


其实是相反的。定义函数不会创建作用域。调用函数创建一个范围。



范围是什么?



变量的寿命。你看,每个变量都是出生,生活和死亡。范围的开始标记变量出生的时间,范围的结束标记它死亡的时间。



开始时只有一个范围(称为程序范围或全局范围)。在此范围内创建的变量只有在程序结束时才会生效。它们被称为全局变量。



例如,考虑这个程序(它不是JavaScript):

  x = 10 //全局变量x 

{//作用域的开始
x = 20 //局部变量x
print(x) / 20
} //范围结束

print(x)// 10

这里我们创建了一个名为 x 的全局变量。然后我们创建了一个块范围。在这个块范围内,我们创建了一个局部变量 x 。因为当我们打印 x 时局部变量影子全局变量,我们得到 20 。回到全局范围,当我们打印 x 时,我们得到 10 (本地 code>现在已经死了。)



阻止范围和函数范围



现在有两个主



上一个示例中的作用域是一个块作用域。它只是一个代码块。因此名字。块范围将立即执行。



另一方面,函数作用域是块作用域的模板。顾名思义,函数作用域属于一个函数。然而,更准确地说,它属于一个函数调用。函数作用域在调用函数之前不存在。例如:

  var x = 10 

函数inc(x){
print (x + 1)。
}

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

正如你可以看到每次调用函数时创建一个新的作用域。这是你得到输出 4 10 8



JavaScript只有函数作用域。它没有块范围。因此,如果你想创建一个块范围,你需要创建一个函数并立即执行:

  var x = 10; //全局变量x 

(function(){//开始一个作用域
var x = 20; //局部变量x
print(x); // 20
}()) //作用域的结束

print(x); // 10

此模式称为

词汇作用域和动态作用域



函数作用域可以是两种类型 - 词法和动态。您会看到,在函数中有两种类型的变量:


  1. 自由变量


在范围内声明的变量被绑定到该范围。未在范围内声明的变量是免费的。这些自由变量属于一些其他范围,但是哪一个?



词法范围



必须属于父范围。例如:

  function add(x){//新范围的模板,x在此范围内绑定
return function(y){//一个新作用域的模板,x是自由的,y是绑定的
return x + y; // x解析到父作用域
};
}

var add10 = add(10); //为x创建一个新作用域并返回一个函数
print(add10(20)); //为y创建一个新作用域并返回x + y

JavaScript和大多数编程语言一样,



动态范围



与词法范围相反,在动态范围自由变量必须属于调用范围(调用函数的作用域)。例如(这也不是JS - 它没有动态作用域):

  function add(y){//模板的新范围,y是绑定,x是免费的
return x + y; // x解析到调用范围
}

函数add10(y){//一个新范围的模板,绑定$ $ $ $ $ $ $ $ var var var var = // bind x
return add(y); // add x and y
}

print(add10(20)); //调用add10创建一个新的作用域(调用作用域)
// add in中的x解析为10,因为add10中的x为10

就是这样。简单吧?



问题



您的第一个程序的问题是JavaScript没有动态范围。它只有词汇作用域。看错了?

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

function f2(){
return a;
}

f1(); // a未定义(显然 - f2无法访问f1内的a)

你的第二个程序是一个非常大的混乱:

  function f(){
var b =barb

return function(){
return b;
}
}

console.log(b); // ReferenceError:b未定义

以下是错误:


  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);

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


I understand functions in 'js' have lexical scope (i.e. functions create their environment (scope) when they are defined not when they are executed.)

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

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

When I run just 'f()' it returns the inner function. Which I get, that's what 'return' does!

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

Why do you get 'ReferenceError: b is not defined?' But doesn't the inner function above have access to it's space, f()'s space etc. Being that 'b' is being returned to the global space, wouldn't the console.log() work?

However when I assign 'f()' to a new variable and run it:

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

This returns 'b' which is "barb", but when you run console.log() again you'll get 'ReferenceError: 'b' is not defined'; Isn't 'b' in the global scope now since it has been returned? SO why didn't 'x()' also return the inner function just like 'f()' did?

解决方案

You, my friend, are thoroughly confused. Your very first statement itself is wrong:

functions create their environment (scope) when they are defined not when they are executed

Actually it's the opposite. Defining a function doesn't create a scope. Calling a function creates a scope.

What's a scope?

To put it simply, a scope is the lifespan of a variable. You see, every variable is born, lives and dies. The beginning of a scope marks the time the variable is born and the end of the scope marks the time it dies.

In the beginning there's only one scope (called the program scope or the global scope). Variables created in this scope only die when the program ends. They are called global variables.

For example, consider this program (it's not 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

Here we created a global variable called x. Then we created a block scope. Inside this block scope we created a local variable x. Since local variables shadow global variables when we print x we get 20. Back in the global scope when we print x we get 10 (the local x is now dead).

Block Scopes and Function Scopes

Now there are two main types of scopes in programming - block scopes and function scopes.

The scope in the previous example was a block scope. It's just a block of code. Hence the name. Block scopes are immediately executed.

Function scopes on the other hand are templates of block scopes. As the name suggests a function scope belongs to a function. However, more precisely, it belongs to a function call. Function scopes do not exist until a function is called. For instance:

var x = 10

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

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

As you can see every time you call a function a new scope is created. That's the reason you get the outputs 4, 10 and 8.

JavaScript only has function scopes. It doesn't have block scopes. Hence if you want to create a block scope then you need to create a function and immediately execute it:

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

This pattern is called an immediately invoked function expression (IIFE).

Lexical Scopes and Dynamic Scopes

Function scopes can again be of two types - lexical and dynamic. You see, in a function there are two types of variables:

  1. Free variables
  2. Bound variables

Variables declared inside a scope are bound to that scope. Variables not declared inside a scope are free. These free variables belong to some other scope, but which one?

Lexical Scope

In lexical scoping free variables must belong to a parent scope. For example:

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, like most programming languages, has lexical scoping.

Dynamic Scope

In contrast to lexical scoping, in dynamic scoping free variables must belong to the calling scope (the scope of the calling function). For example (this is also not JS - it doesn't have dynamic scopes):

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

That's it. Simple right?

The Problem

The problem with your first program is that JavaScript doesn't have dynamic scoping. It only has lexical scoping. See the mistake?

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

function f2() {
    return a;
}

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

Your second program is a very big mess:

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

    return function() {
        return b;
    }
}

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

Here are the mistakes:

  1. You never called f. Hence the variable b is never created.
  2. Even if you called f the variable b would be local to f.

This is what you need to do:

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

    return function() {
        return b;
    }
}

var x = f();

console.log(x());

When you call x it returns b. However that doesn't make b global. To make b global you need to do this:

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

Hope this helped you understand about scopes and functions.

这篇关于在javaScript中的词法作用域/闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆