【问题标题】:js global and local scopejs 全局和局部范围
【发布时间】:2021-04-25 09:58:27
【问题描述】:

我正在对范围进行一些试验,但偶然发现了这个我不明白的东西。

var GV = 'global_var'

    function changeVar(lv) {
     console.log('inside function lv is '+lv);
     lv='local_var'
     console.log('after changing value lv is '+lv);
     console.log('inside function GV is '+GV);
    }

    console.log('before function GV is '+GV);   
    changeVar(GV);  
    console.log('after function GV is '+GV);    

如果我在 lv 的范围之上运行代码是本地的,并且任何修改都不会更改全局范围内的 GV,但是如果我将 GV 更改为数组并在同一函数中修改其元素之一,那么全球 GV 也发生了变化。这是为什么?我有一种感觉,它可能与实例有关,但我不明白。

var GV = [1,5,8]

    function changeVar(lv) {
     console.log('inside function lv is '+lv);
     lv[1]=[0]
     console.log('after changing value lv is '+lv);
     console.log('inside function GV is '+GV);
    }

    console.log('before function GV  '+GV); 
    changeVar(GV);  
    console.log('after function GV is '+GV);    

我考虑过提升(所以如果 ls 在函数内部声明为一个新变量),但如果是因为这样,函数内部的第一个 console.log 不应该显示未定义吗?

【问题讨论】:

  • 这种行为与作用域无关,纯粹是因为在 JS 中对象(例如数组)是“通过引用”传递和分配的,所以当你改变一个“副本”时,你会改变所有引用的变量相同的值 - 这就是第二个示例中 LVGV 发生的情况。在第一个示例中没有发生这种情况的原因是它重新分配给LV,而不是对其进行变异。 (请注意,即使您愿意,也不能改变字符串等原始值。)
  • 非常感谢 :)
  • 将此视为 Robin 回答的旁注,尽量避免使用“var”,而是尝试使用块范围等效项,如“const”和“let”,这可以帮助您编写更严格的代码。
  • 是的,我只是在试验,但这是一个好点 :)

标签: javascript scope global-variables local-variables


【解决方案1】:

这是因为当var GV = 'global_var' 时,GV 变量包含实际的字符串'global_var'。当您将 GV 传递给 changeVar 时,它是按值传递的,即在 changeVar 函数的范围内,会创建一个新变量 lv,并将值 'global_var' 复制到新的新变量中。函数被调用后的状态:

GV 仍然包含“global_var”,而 lv 包含“global_var”的副本,值完全相同。

现在在本地范围内,lv='local_var' 和 lv 已更新,但 GV 保持不变。因此,在您退出函数后,GV 保持不变,因为它位于完全不同的内存位置。

现在让我们看看第二种情况,GV = [1,5,8]。在这种情况下,GV 被分配了一个 JavaScript 数组,记住,数组是对象。对象有引用,因此 GV 变量包含对 [1, 5, 8] 数组的引用。现在,一旦您调用函数changeVar,将GV 作为参数传入,数组的引用就会被传递并存储在lv 中。现在在函数调用之后,这是状态:

GV 包含对 [1, 5, 8] 的引用,而 lv 也包含对 [1, 5, 8] 的相同引用。所以它是按值传递引用,即传递引用,而不是整个数组作为副本传递给函数。在函数内部,当你执行lv[1]=[0]时,它会将内存中的原始数组更新为[1,0,8]。

当你退出函数时,GV 仍然指向原始数组,当你打印 GV 时,它显示更新后的数组 [1, 0, 8]。

【讨论】:

  • 第一部分不正确。传递参数时不会复制任何内容,无论是对象还是原语。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-05
  • 1970-01-01
相关资源
最近更新 更多