关于可变范围的简单点 - Javascript

时间:2012-10-09 17:44:26

标签: javascript global-variables scope

  

可能重复:
  JavaScript Variable Scope

我(显然)对Javascript很新,我在其他线程上看到了关于Global和Local变量使用的几个不同点,但我试图在一个地方锁定一些关于这个主题的基本点

在函数外部(或在函数内部)声明的以下内容之间有什么区别?

var thing = 1;

thing = 1;

我知道使用var会在其当前范围内声明变量。因此,将var视为全局。可以出现哪些陷阱?有人能给出一个简单的例子,说明在这种情况下变量可能会相互衔接吗?

提前致谢。

3 个答案:

答案 0 :(得分:2)

  1. 如果您已经在全球范围内,差异非常小,您不必担心它

  2. 假设您有两个for循环,并且您想对它们执行某些操作。

  3. for (i = 0; i < elements.length; i++) {
        element = elements[i];
        for (i = 0; i < items.length) {
            item = items[i];
            element.add(item);
        }
    }
    

    这段伪代码可以在许多不同的语言中正常工作。 该程序将看到内循环和外循环,并且可以告诉i不是指同一件事。

    在JavaScript中,它们是相同的i 这是因为其他语言都有块范围 - 只要你输入新的花括号,程序就会将变量视为新的。

    在JavaScript中只有函数作用域,这意味着函数变量内部被视为new,但在控制语句(ifforswitch)内部,它们是具有相同值的相同变量 因此外部循环将i设置为0,然后进入内部循环 内部循环遍历其所有项目列表,并在其进行时构建i ...
    然后它返回到外循环,i仍然等于items.length - 1 ...
    如果它小于elements.length,那么它会向i添加一个,现在高于items长度,因此内循环中没有任何事情发生了...... ...如果items.length大于elements.length,那么外部循环只会在一次结束后结束。

    现在,我确信您可以开始考虑您可能想要使用xnamevalueel或{{1在您的整个计划中数次(或数千)或sumidefaultsrcurlimg等多次甚至是行,你可以开始考虑上面循环的情况,如果你尝试用同一个名字调用两个不同的东西,那么事情可能会出错。

    这与var-fallthrough相同的问题

    如果你有一个使用名为script的变量的函数和另一个使用另一个名为x的变量的函数,那就太好了...... ......除非你忘记申报变量。

    x

    // no problems! function func1 () { var x = 0; } function func2 () { var x = "Bob"; } // big problems! function func1 () { x = 0; } function func2 () { x = "Bob"; } 设置func1 window.x = 0;设置func2

    ...如果window.x = "Bob";应该等于42,那么其他一些程序可以正常工作,现在你有可能有3个破坏的应用程序,只是因为缺少window.x个。

    但它并没有立即设置全局变量。它实际上做的是通过功能链。如果你在另一个函数中创建一个函数,那么一个未声明的var将会查看其父级的变量,然后是它的祖父母的变量,然后是它的曾祖父母的变量...... 如果它一直到var并且没有人拥有该名称的var,那么它会在window上创建一个具有该名称的名称。

    window

    当你调用func1时,它会将自己的function func1 () { var x = 0; function func2 () { var y = 1; x = 2; z = 3; } func2(); } 设置为0,并调用func2。 func2将自己的x设置为1。 然后它将func1的y设置为2。 然后,因为func2没有x且func1没有zz没有window,所以它将z设置为3。

    这只是混乱的开始,为什么它是一个非常非常好的想法,以确保你定义需要在该函数内部(以及在该函数内部创建的任何函数)中可用的变量。 .. ...当你引用预先存在的变量时,你仔细地引用它们,并在你的代码中知道变量应该在哪里(哪个函数定义了它......所以在程序链的哪个链上)在它到达window.z之前停止查看,以及为什么要从另一个函数内部更改它。

答案 1 :(得分:1)

一个常见的陷阱是循环计数器 - 它们总是被命名为i并且会发生冲突。例如:

function a() {
    for (i = 0; i < 5; i++)
        b();
}
function b() {
    for (i = 0; i < 3; i++)
        ; // something
    // now, the /global/ i is reset to 3
    // … and the condition in function a will never be met
}
// so
a();
// is an infine loop instead of executing something 15 times

答案 2 :(得分:0)

与许多C风格的语言不同,JavaScript支持块语法,但不支持块范围,因此以下内容可能无法按预期运行:

var foo = 'bar';

{
  var foo = 'baz';
}

console.log(foo); // 'baz'

在其他支持if等块的JavaScript构造中也很明显:

var foo = 'bar';

if (true) {
  var foo = 'baz';
}

console.log(foo); // 'baz'

此外,正如Bergi指出的那样,i的{​​{1}}计数器将相互覆盖,因为for不会创建新的范围。

Crockford认为JavaScript缺少块范围{+ 3}}。相反,JavaScript有"Awful Part",因此只有函数才会创建一个新范围:

for

JavaScript中的每个函数都可以访问包含它的函数中的变量;内部可以访问外部,但反之亦然。对于上面的示例,lexical scoping(立即调用的函数表达式)可以访问全局范围中定义的var foo = 'bar'; (function() { var foo = 'baz'; console.log(foo); // 'baz' }()); console.log(foo); // 'bar' ,但我们选择使用本地覆盖foo = 'bar'; foo声明并将其设置为var

奖励点:Shog9发现'baz'可以使用像这样的对象文字来模拟块范围:

with

Crockford IIFE由于其含糊不清,但如果您真的希望阻止范围,我认为var foo = 'bar'; with ({foo: 'baz'}) { console.log(foo); // 'baz' } console.log(foo); // 'bar' 解决方法没有任何危害。