我正在阅读道格拉斯·克罗克福德的书“Javascript:The Good Parts”。他在讲JS的范围并表示JS没有块级作用域:
在许多现代语言中,建议变量尽可能晚地在第一次使用时声明。这对JavaScript来说是错误的建议,因为它缺少块级作用域。所以最好在函数体的顶部声明函数中使用的所有变量。
然而,我无法想到一个好的例子说明这个声明是有道理的,如果能看到一些例子来验证这个声明将会非常好。
我正在阅读道格拉斯·克罗克福德的书“Javascript:The Good Parts”。他在讲JS的范围并表示JS没有块级作用域:
在许多现代语言中,建议变量尽可能晚地在第一次使用时声明。这对JavaScript来说是错误的建议,因为它缺少块级作用域。所以最好在函数体的顶部声明函数中使用的所有变量。
然而,我无法想到一个好的例子说明这个声明是有道理的,如果能看到一些例子来验证这个声明将会非常好。
在顶部声明变量可以帮助你避免像这样的情况:
function outer() {
var i = 50;
function inner() {
alert(i);
var i= 30;
}
inner();
}
outer();
许多人会期望警报显示 50
,但看到 undefined
时会感到惊讶。这是因为变量 i
在 inner
函数中声明,但直到警报后才初始化。因此,它具有完整的函数作用域,即使在初始使用之后声明。
i
是一个常见的循环变量。C 程序员可能会看到 for(var i = ...)
并错误地认为 i
具有块级作用域。在顶部声明变量可以帮助可读性和可维护性,但我必须承认我很少在使用前声明循环变量。 - Rick Hitchcockvar i; alert(i); i = 30;
。 - Assafvar i = 30;
。去掉 var
就会得到 50
。当你在函数内使用关键字 var
时,它将该 var
作用域限定在该函数内。 - StackSlave将变量在函数顶部声明是一种记录所有使用变量的方式。
这也可以避免因为有人错误地想象变量是块作用域而导致混淆,例如下面的情况:
var i=0;
if (true) {
var i=1;
}
// what is i? C programmer might imagine it's 0.
如果在声明变量时也进行初始化操作,将声明放在顶部可以避免与初始化的时间产生潜在问题:
console.log(foo);
var foo = 1;
foo
被提升,因此在console.log
发生时声明,但尚未初始化。因此,这实际上就像var foo;
console.log(foo); // no ReferenceError, but undefined
foo = 1;
从我的角度来看,由于JavaScript没有块级作用域,在函数顶部声明所有变量可以更容易地发现您不必使用的变量,因为您可以重复使用其他变量。
例如:
function test(){
var pages = [
'www.stackoverflow.com',
'www.google.com'
];
var users = [
'John',
'Bob'
];
for (var page = 0; page < pages.length; page++) {
console.log(pages[page]);
};
for (var user = 0; user < users.length; user++) {
console.log(users[user]);
};
}
可以更改为:
function test(){
var index, pages, users;
pages = [
'www.stackoverflow.com',
'www.google.com'
];
users = [
'John',
'Bob'
];
for (index = 0; index < pages.length; index++) {
console.log(pages[index]);
};
for (index = 0; index < users.length; index++) {
console.log(users[index]);
};
}
并从内存中节省一个变量空间。
在这样一个小函数中,主要点可能不太明显,但想象一下有数千行代码的整个项目。这可以使您的代码运行更快。
for
循环中移除var
吗? - user663031var
。如果您的循环现在在一个函数中,并且您的增量是全局的,则可能会出现问题。您可能没有考虑到这一点,意外地重新定义了一个变量在更高级别的范围内。 - StackSlave那并不总是一个好主意。它取决于你在做什么。当他们说不需要声明“顶级”变量时,意思是无所谓。但在函数内部可能有影响。请考虑以下示例:
varOne = 1; varTwo = 2; varThree = 3; // undeclared
function lameFunc(){
var varOne = 'Something'; // does no affect varOne at the top level
return varOne;
}
同上:
var varOne = 1, varTwo = 2, varThree = 3; // declared
function lameFunc(){
var varOne = 'Something'; // does no affect varOne at the top level
return varOne;
}
var
更容易看到变量,并且由于在"顶层"没有副作用,因此建议使用。lameFunc()
时,都会影响较高级别的var
。function lameFunc(){
/* varOne is effected at the higher level whether or not `var` is declared
above as in `varOne = 1` or `var varOne = 1` */
varOne = 'Something';
return varOne;
}
var someInputVal = document.getElementById('someInput').value;
,然后假设你想要在某个元素的点击事件中获取该变量的值。你应该将var
声明在Element.onclick = function(){/* in here */}
内部,因为在点击Element
之前可能会改变输入的值。如果该元素没有变成undefined
,那么在处理事件的函数之外声明var someInput = document.getElementById('someInput');
也是可以的,你可以像这样访问它:var doc = document, bod = doc.body;
function E(e){
return doc.getElementById(e);
}
var someInput = E('someInput'), someInputVal = someInput.value;
E('clickButton').onclick = function(){
console.log(someInputVal); // will not be what document.getElementById('someInput').value is if it was changed before clicking
var declared = someInput.value;
console.log(declared);
}
i
变量来考虑for
循环。首先声明i
并重复使用它似乎更加正确或习惯化。 - elclanrsvar
就是变量声明的方式,那么它怎么会是一个完全不同的话题呢? - user663031