这一切都始于这些简单的代码行:
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()调用期间会发生什么;
我真的很感激。
答案 0 :(得分:2)
var
创建一个局部变量,其范围限定在它出现的函数中。在全局范围中声明的任何变量都将成为全局对象的属性(在浏览器中,window
),并且在该函数中未使用var
声明的函数中引用的任何变量引用周围的范围,很可能是全球范围。
还有一个新的关键字let
,它将在即将推出的ECMAScript版本中出现,并且已经在某些浏览器中创建了一个块范围的变量。
因此,在您的第一个示例中(我将假设它在浏览器中运行),您创建分别绑定到3和2的window.a
和window.b
。函数line
声明局部变量a
和b
。当window.a传递给line时,参数x
绑定到值3(window.a的值)。局部变量a
和b
分别为5和4。 这些与window.a和window.b无关。计算a*x+b
因此是5 * 3 + 4或19。
代码b = line(a) - b
将window.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”将查找范围链,直到它找到变量或命中全局范围(此时它将创建它)。
如果是第一个函数,则会先处理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
尚未初始化,则不会发生任何事情。
这与PRIVATE
和LOCAL
变量以及命名约定的概念有关。
首先,您有两个名为a
的变量和两个名为b
的变量。这是不好的做法,因为您可能会错误地更改另一个的值,或者它的旧值仍然可以位于内存中,因为它已经初始化并且已经给出了值。请记住,初始化时并不总是需要分配值,这只是最佳实践。
其次,您的函数可以从它上面的级别修改变量。换句话说,通过在该行上删除VAR
,可以修改在文件开头设置为b
的{{1}}的原始值。
<强> TLDR; 强> 不要多次使用相同的变量名,并且在尝试创建新变量时始终使用VAR。