可变范围和变量

时间:2014-01-13 02:30:14

标签: javascript variables closures scope

这一切都始于这些简单的代码行:

a = 3;
b = 2;

function line(x) {
    var a = 5;
    var b = 4;

    return a*x+b;
}

// returns 17
b = line(a) - b;
alert(b);

// returns 36
c = line(a) + b;
alert(c);

两个警报分别返回17和36 控件按预期工作。直到...


我犯了改变郎的错误 函数内部如下:

function line(x) {
    var a = 5; 
        b = 4;

    return a*x+b;
}

突然第13行返回15,第17行返回23
当我跟踪var时,情况继续恶化 沿着兔子洞,在我下降时变得更加陷入困境。

我意识到我可以做一个心理记录,总是使用var 知道我的代码将始终按预期工作
但这已成为一个原则问题,现在我需要
了解var实际如何运作。

这里有四个地狱的链接,
由(也可能是)我制作:

谜语#1 http://jsfiddle.net/js_test/gNEmY/

谜语#2 http://jsfiddle.net/js_test/FJVYL/

谜语#3 http://jsfiddle.net/js_test/Vz7Sd/

谜语#4 http://jsfiddle.net/js_test/RaA5J/

如果有人能给我洞察力 进入引擎盖下发生的事情
即,每次alert()调用期间会发生什么; 我真的很感激。

4 个答案:

答案 0 :(得分:2)

var创建一个局部变量,其范围限定在它出现的函数中。在全局范围中声明的任何变量都将成为全局对象的属性(在浏览器中,window),并且在该函数中未使用var声明的函数中引用的任何变量引用周围的范围,很可能是全球范围。

还有一个新的关键字let,它将在即将推出的ECMAScript版本中出现,并且已经在某些浏览器中创建了一个块范围的变量。

因此,在您的第一个示例中(我将假设它在浏览器中运行),您创建分别绑定到3和2的window.awindow.b。函数line声明局部变量ab。当window.a传递给line时,参数x绑定到值3(window.a的值)。局部变量ab分别为5和4。 这些与window.a和window.b无关。计算a*x+b因此是5 * 3 + 4或19。

代码b = line(a) - bwindow.a传递给line,计算值19,从中减去window.b的当前值(2),得到17,这是然后分配到window.b。 36的值来自line(3)(仍然是19)加上17(window.b的新值)。

当您将var从作业b中的line中删除后,您进行了更改,以便b不再是局部变量。 在这种情况下,函数中对b的所有引用都是指全局值window.b。

对于你的Riddle#2,你得到23,在第一次调用window.b之后等于15.当第二次调用第(a)行时,window.b被设置回4, a * x + b计算仍然得到19,然后再次添加window.b(4),得到23。

值得注意的是,var关键字声明了一个函数作用域的变量,而不是像其他C语言那样期望的块作用域。例如,在此函数中:

function scope(array) {
    var a = 7;

    for (var b = 0; b < array.length; ++b) {
        var c = array[b];
    }

    alert(a + b + c);
}

所有变量的范围都扩展到整个函数。特别是,c的范围 仅限于for循环。

但是,未在特定范围内声明的变量不一定引用全局变量。如果它嵌套在另一个函数作用域内,它将引用该嵌套作用域。请考虑以下示例:

var b = 7;

function outer() {
    var b = 42;

    function inner() {
        return b; // refers to b in outer, not global
    }

    return inner();
}

alert(outer()); // 42, not 7

答案 1 :(得分:0)

没有var声明的变量是全局变量,这是规则。 但请记住,如果要使用一个var声明多个局部变量,请用逗号分隔它们。

var a = 5; // local variable
    b = 4; // global varialbe

var a = 5, // local variable
    b = 4; // local varialbe

答案 2 :(得分:0)

  

如果你在全球范围内,则没有区别。

     

如果你在函数中,那么“var”将创建一个局部变量,“no var”将查找范围链,直到它找到变量或命中全局范围(此时它将创建它)。

     

Source

如果是第一个函数,则会先处理line(a),并且在运行时,您已设置b = 4。因此,因为b是一个全局定义的变量,所以当它运行line(a) - b时,你得到:

line(a)(返回19)

减去b(b = 4)

19 - 4 = 15

您可以简化陈述并获得相同的结果:

//define global variable b
var b = 2;
function line(x) {
    //x = 3
    //update global variable b; it now = 4
    b = 4;
    //forget the math and just return 19
    return 19;
}

//run function; before, b = 2, after b = 4
b = line(3) - b;
alert(b);

与第二个示例相同,因为您的函数更改了全局变量b的值,唯一的区别是您添加 4而不是减去(19 + 4 = 23) )。

为了避免变量的这种混乱性质,请务必尽可能区分全局变量和局部变量,并且只在需要显式更新函数中的全局变量时才删除var。实际上,由于全局变量始终保留在内存中,因此只有在明确需要时才应使用全局变量。这是一个明确的例子:

var globalVar;
function someFunc(x) {
    var tempVar = 4;
    return x * tempVar;
}

答案 3 :(得分:0)

VAR在内存中为新变量声明一个新实例。只需说出b = 4即可尝试将b的值更改为4。如果b尚未初始化,则不会发生任何事情。

这与PRIVATELOCAL变量以及命名约定的概念有关。

首先,您有两个名为a的变量和两个名为b的变量。这是不好的做法,因为您可能会错误地更改另一个的值,或者它的旧值仍然可以位于内存中,因为它已经初始化并且已经给出了值。请记住,初始化时并不总是需要分配值,这只是最佳实践。

其次,您的函数可以从它上面的级别修改变量。换句话说,通过在该行上删除VAR,可以修改在文件开头设置为b的{​​{1}}的原始值。

<强> TLDR; 不要多次使用相同的变量名,并且在尝试创建新变量时始终使用VAR。