8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

JavaScript 中变量的范围是什么?

MTilsted 1月前

129 0

javascript 中变量的作用域是什么?它们在函数内部和外部的作用域是否相同?或者这有关系吗?此外,如果定义了变量,它们存储在哪里

javascript 中变量的作用域是什么?它们在函数内部和外部的作用域是否相同?或者这有关系吗?此外,如果变量是全局定义的,它们存储在哪里?

帖子版权声明 1、本帖标题:JavaScript 中变量的范围是什么?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由MTilsted在本站《function》版块原创发布, 转载请注明出处!
最新回复 (0)
  • (function foo() { console.log(foo) })();
    console.log(typeof foo); // undefined, because `foo` is scoped to its own expression
    
    //but, like this
    (function foo() {
        console.log('1:', foo) // function foo
        foo = 100
        console.log('2:', foo) // function foo, is not 100, why?
    })()
  • @iAmOren 当然,它们是问题的一部分,是的,它们确实属于 JavaScript。如果要废除的话,应该废除的是 var,但这既不可行也不相关。

  • const 和 let 不是问题的一部分。为什么要提起它们?就我个人而言,它们不属于 javascript...

  • ECMAScript 6 引入了 let 和 const 关键字。这些关键字可以代替 var 关键字使用。与 var 关键字相反,let 和 const 关键字支持在块语句内声明局部作用域。

    var x = 10
    let y = 10
    const z = 10
    {
      x = 20
      let y = 20
      const z = 20
      {
        x = 30
        // x is in the global scope because of the 'var' keyword
        let y = 30
        // y is in the local scope because of the 'let' keyword
        const z = 30
        // z is in the local scope because of the 'const' keyword
        console.log(x) // 30
        console.log(y) // 30
        console.log(z) // 30
      }
      console.log(x) // 30
      console.log(y) // 20
      console.log(z) // 20
    }
    
    console.log(x) // 30
    console.log(y) // 10
    console.log(z) // 10
    
  • 在 EcmaScript5 中,主要有两个作用域: 本地作用域 全局作用域 。但是在 EcmaScript6 中,主要有三个作用域:本地作用域、全局作用域和一个称为 块作用域的新作用域。 .

    块范围的示例是:-

    for ( let i = 0; i < 10; i++)
    {
     statement1...
    statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
    }
    
  • 我真的很喜欢这个被接受的答案,但我想补充一点:

    范围收集并维护所有已声明的标识符(变量)的查找列表,并强制执行一组严格的规则,以确定当前正在执行的代码如何访问这些标识符。

    范围是一组通过标识符名称查找变量的规则。

    • 如果在直接作用域中找不到变量,引擎会查询下一个外部包含作用域,继续查找直到找到或到达最外层(又称全局)作用域。
    • 是一组规则,用于确定在何处以及如何查找变量(标识符)。此查找可能是为了分配给变量(即 LHS(左侧)引用),也可能是为了检索其值(即 RHS(右侧)引用)。
    • LHS 引用来自赋值运算。与作用域相关的赋值可以通过 = 运算符或通过将参数传递给(赋值给)函数参数来实现。
    • JavaScript 引擎首先在执行代码之前对其进行编译,在此过程中,它将 var a = 2; 之类的语句拆分为两个单独的步骤:第一。首先,使用 var a 在该范围内对其进行声明。此操作在开始时执行,在代码执行之前。第二。之后,使用 a = 2 查找变量(LHS 引用)并在找到后将其赋值给该变量。
    • LHS 和 RHS 引用查找均从当前执行的范围开始,如果需要(即它们在那里找不到它们要查找的内容),它们会逐个向上查找嵌套范围,一次查找一个范围(底层),查找标识符,直到它们到达全局(顶层)并停止,找到它或找不到它。未实现的 RHS 引用会导致引发 ReferenceError。未实现的 LHS 引用会导致自动、隐式创建该名称的全局变量(如果未处于严格模式),或引发 ReferenceError(如果处于严格模式)。
    • 作用域由一系列“气泡”组成,每个气泡都充当容器或桶,标识符(变量、函数)在其中声明。这些气泡整齐地嵌套在一起,这种嵌套是在编写时定义的。
  • const 和 let 不在问题中。你为什么要提起它们?问题是关于 vars 的……const 和 let 很烦人,而且会破坏 javascript。

  • 在 JavaScript 中有两种类型的作用域:

    • 本地范围
    • 全球范围

    下面的函数有一个局部作用域变量 carName 。并且该变量不能从函数外部访问。

    function myFunction() {
        var carName = "Volvo";
        alert(carName);
        // code here can use carName
    }
    

    下面的类有一个全局范围变量 carName 。并且这个变量可以在类中的任何位置访问。

    class {
    
        var carName = " Volvo";
    
        // code here can use carName
    
        function myFunction() {
            alert(carName);
            // code here can use carName 
        }
    }
    
  • 引用 10

    ES5 以及更早之前:

    JavaScript 中的变量最初(在 之前 ES6 )是词法函数作用域。“词法作用域”一词意味着您可以通过“查看”代码来了解变量的作用域。

    使用 var 关键字声明的每个变量的作用域都限定在函数内。但是,如果在该函数内声明了其他函数,则这些函数将可以访问外部函数的变量。这称为 作用域链 。其工作方式如下:

    1. 当函数试图解析变量值时,它首先查看其自身的作用域。这是函数主体,即花括号 {} 之间的所有内容(除此 作用域内的 其他 函数
    2. 如果在函数体内找不到变量,它 就会沿着作用域链向上 查找函数 定义处 。这就是词法作用域的含义,我们可以在代码中看到这个函数的定义位置,因此只需查看代码就可以确定作用域链。

    例子:

    // global scope
    var foo = 'global';
    var bar = 'global';
    var foobar = 'global';
    
    function outerFunc () {
     // outerFunc scope
     var foo = 'outerFunc';
     var foobar = 'outerFunc';
     innerFunc();
     
     function innerFunc(){
     // innerFunc scope
      var foo = 'innerFunc';
      console.log(foo);
      console.log(bar);
      console.log(foobar);
      }
    }
    
    outerFunc();

    当我们尝试记录变量 foo , bar foobar 记录到控制台时,发生的情况如下:

    1. 我们尝试将 foo 打印到控制台,foo 可以在函数 innerFunc 本身内部找到。因此,foo 的值被解析为字符串 innerFunc .
    2. 我们尝试将 bar 打印到控制台,但在函数本身内部找不到 bar innerFunc 。因此,我们需要 爬上作用域链 。我们首先查看定义该函数的外部函数 innerFunc 。这就是函数 outerFunc 。在作用域中, outerFunc 我们可以找到变量 bar,它保存着字符串“outerFunc”。
    3. 在 innerFunc 中找不到 foobar。因此,我们需要 沿着作用域链爬到 innerFunc 作用域。这里也找不到,我们再爬一层到 全局作用域 (即最外层作用域)。我们在这里找到变量 foobar,它包含字符串 'global'。如果爬过作用域链后仍找不到变量,JS 引擎将抛出一个 referenceError .

    ES6 (ES 2015)及更早版本:

    相同的词法作用域和作用域链概念仍然适用于 ES6 。然而,引入了声明变量的新方法。有以下几种:

    • let :创建一个块范围变量
    • const :创建一个块范围的变量,该变量必须初始化并且不能重新分配

    var <之间最大的区别code>后者 let / const 在于,前者 var 是函数作用域,而 let / const 是块作用域。下面是一个例子来说明这一点:

    let letVar = 'global';
    var varVar = 'global';
    
    function foo () {
      
      if (true) {
        // this variable declared with let is scoped to the if block, block scoped
        let letVar = 5;
        // this variable declared with let is scoped to the function block, function scoped
        var varVar = 10;
      }
      
      console.log(letVar);
      console.log(varVar);
    }
    
    
    foo();

    在上面的例子中, letVar 记录的值是 global,因为用 声明的变量 let 是块作用域的。它们在各自的块之外不复存在,因此无法在 if 块之外访问该变量。

  • 我的理解是,作用域有 3 个:全局作用域,全局可用;局部作用域,可用于整个函数,无论块如何;块作用域,仅适用于使用它的块、语句或表达式。全局和局部作用域用关键字“var”表示,可以在函数内或函数外,块作用域用关键字“let”表示。

    对于那些认为只有全局和局部范围的人,请解释为什么 Mozilla 会用一整页来描述 JS 中块范围的细微差别。

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

  • 引用 12

    (答案发布已久)块范围;developer.mozilla.org/en/docs/Web/JavaScript/Reference/…

  • JS 中只有函数作用域。没有块作用域!您还可以看到什么是提升。

    var global_variable = "global_variable";
    var hoisting_variable = "global_hoist";
    
    // Global variables printed
    console.log("global_scope: - global_variable: " + global_variable);
    console.log("global_scope: - hoisting_variable: " + hoisting_variable);
    
    if (true) {
        // The variable block will be global, on true condition.
        var block = "block";
    }
    console.log("global_scope: - block: " + block);
    
    function local_function() {
        var local_variable = "local_variable";
        console.log("local_scope: - local_variable: " + local_variable);
        console.log("local_scope: - global_variable: " + global_variable);
        console.log("local_scope: - block: " + block);
        // The hoisting_variable is undefined at the moment.
        console.log("local_scope: - hoisting_variable: " + hoisting_variable);
    
        var hoisting_variable = "local_hoist";
        // The hoisting_variable is now set as a local one.
        console.log("local_scope: - hoisting_variable: " + hoisting_variable);
    }
    
    local_function();
    
    // No variable in a separate function is visible into the global scope.
    console.log("global_scope: - local_variable: " + local_variable);
    
  • 试试这个有趣的例子。在下面的例子中,如果 a 是一个初始化为 0 的数字,你会看到 0 然后是 1。但 a 是一个对象,javascript 会将 a 的指针而不是它的副本传递给 f1。结果是你两次都会收到相同的警报。

    var a = new Date();
    function f1(b)
    {
        b.setDate(b.getDate()+1);
        alert(b.getDate());
    }
    f1(a);
    alert(a.getDate());
    
  • 你的意见不会改变答案的有效性。问题是关于作用域的。const 和 let 是定义作用域的 var 的现代替代品。提出这个问题时,它们都不存在

  • 关于 var 的问题。'const' 和 'let' = javascript 的破坏者,不在问题中,也不应该在 javascript 中......

  • 现代 Js、ES6+、' const ' 和 ' let '

    您应该像大多数其他主流语言一样,对创建的每个变量使用块作用域。 var 过时 。这使您的代码更安全,更易于维护。

    const 95% 的情况都 应该使用 。它使得变量 引用 不会改变。数组、对象和 DOM 节点属性可能会改变,因此应该 const .

    let 应该用于任何需要重新赋值的变量。这包括在 for 循环中。如果您在初始化之外更改值,请使用 let .

    块作用域意味着变量仅在声明它的括号内可用。这扩展到内部作用域,包括在作用域内创建的匿名函数。

  • 补充一下其他答案,作用域是所有声明的标识符(变量)的查找列表,并强制执行一组严格的规则,规定当前正在执行的代码如何访问这些变量。此查找可能是为了分配给变量,这是一个 LHS(左侧)引用,也可能是为了检索其值,这是一个 RHS(右侧)引用。这些查找是 JavaScript 引擎在编译和执行代码时在内部执行的操作。

    因此从这个角度来看,我认为 Kyle Simpson 所著的《作用域与闭包》电子书中的一张图片会有所帮助:

    image

    引用他的电子书:

    该建筑代表我们程序的嵌套作用域规则集。无论您身在何处,建筑的第一层代表您当前正在执行的作用域。建筑的顶层是全局作用域。您可以通过查看当前楼层来解析 LHS 和 RHS 引用,如果找不到,请乘坐电梯到下一层,在那里查找,然后再查找下一层,依此类推。一旦您到达顶层(全局作用域),您要么找到您要找的东西,要么找不到。但无论如何你都必须停下来。

    值得一提的是,“一旦找到第一个匹配项,范围查找就会停止”。

    这个“作用域级别”的概念解释了为什么如果在嵌套函数中查找“this”,则可以使用新创建的作用域进行更改。这里有一个链接,详细介绍了所有这些细节, 您想要了解的有关 JavaScript 作用域的所有内容

  • JavaScript 作用域几乎只有两种类型:

    • 每个 var 声明的作用域与最直接的封闭函数相关联
    • 如果 var 声明没有封闭函数,则它是全局作用域

    因此,除函数之外的任何块都不会创建新的作用域。这解释了为什么 for 循环会覆盖外部作用域变量:

    var i = 10, v = 10;
    for (var i = 0; i < 5; i++) { var v = 5; }
    console.log(i, v);
    // output 5 5
    

    改用函数:

    var i = 10, v = 10;
    $.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
    console.log(i,v);
    // output 10 10
    

    在第一个例子中,没有块作用域,因此最初声明的变量被覆盖。在第二个例子中,由于函数而产生了新的作用域,因此最初声明的变量被隐藏,并且没有被覆盖。

    这就是你在 JavaScript 作用域方面需要知道的几乎全部内容,除了:

    所以你可以看到 JavaScript 作用域实际上非常简单,尽管并不总是直观的。需要注意以下几点:

    • var 声明被提升到作用域的顶部。这意味着无论 var 声明发生在哪里,对于编译器来说,var 本身就像发生在顶部一样
    • 同一作用域内的多个 var 声明被合并

    所以这个代码:

    var i = 1;
    function abc() {
      i = 2;
      var i = 3;
    }
    console.log(i);     // outputs 1
    

    相当于:

    var i = 1;
    function abc() {
      var i;     // var declaration moved to the top of the scope
      i = 2;
      i = 3;     // the assignment stays where it is
    }
    console.log(i);
    

    这看起来可能违反直觉,但从命令式语言设计者的角度来看,这是有道理的。

  • 全球范围:

    全局变量就像是全球明星(成龙、曼德拉)。您可以从应用程序的任何部分访问它们(获取或设置值)。全局函数就像是全球事件(新年、圣诞节)。您可以从应用程序的任何部分执行(调用)它们。

    //global variable
    var a = 2;
    
    //global function
    function b(){
       console.log(a);  //access global variable
    }
    

    本地范围:

    如果你在美国,你可能认识金·卡戴珊,臭名昭著的名人(她以某种方式设法登上小报)。但美国以外的人不会认出她。她是一位本土明星,只限于她的地盘。

    局部变量就像是局部星星。您只能在作用域内访问它们(获取或设置值)。局部函数就像是局部事件 - 您只能在该作用域内执行(庆祝)。如果您想从作用域外访问它们,您将收到引用错误

    function b(){
       var d = 21; //local variable
       console.log(d);
    
       function dog(){  console.log(a); }
         dog(); //execute local function
    }
    
     console.log(d); //ReferenceError: dddddd is not defined    
    

    请参阅本文以深入了解范围

返回
作者最近主题: