JavaScript变量如何工作?

时间:2011-10-27 02:52:34

标签: javascript variables scope var

我知道JavaScript变量指向一个值:

var foo = true;
//... later 
foo = false;

因此,在该示例中,我更改了foo指向true - > foo指向false,但如果我这样做:

for (var i=0; i<100; i++){
    var someVar = i;
}

我是否为每次迭代创建了一个新的var?

以下两种方法有何不同?

var myvar;
for (var i=0; i<100; i++){
    myvar = i;
}

for (var i=0; i<100; i++){
    var myvar = i;
}

如果是这样,为什么?

5 个答案:

答案 0 :(得分:15)

Javascript ES5及更早版本中没有块范围,只有功能范围。此外,在函数范围内声明的所有javascript变量的声明会自动“悬挂”到函数的顶部。

因此,在循环中声明变量与在函数顶部声明它然后在循环中引用它没有任何不同。

有关一些有用的说明,请参阅这两个参考:http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoistinghttp://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/

注意:不会提升对变量的赋值,只是变量的声明。所以,如果你这样做:

function a() {
    for (var i=0; i<100; i++){
        var myvar = i;
    }
}

它的工作原理如下:

function a() {
    var myvar;
    for (var i=0; i<100; i++){
        myvar = i;
    }
}

如果要在for循环中创建新范围,可以使用IIFE(立即调用的函数表达式),如下所示:

function a() {
    for (var i=0; i<100; i++){
        (function() {
            var myvar = i;
            // myvar is now a separate variable for each time through the for loop
        })();
    }
}

2015年更新。 ES6(或有时称为ES2015)提供let声明,该声明确实提供了块范围。在这种情况下,let变量声明仅提升到当前块范围的顶部。截至2015年中期,这还没有在浏览器中广泛实现,但即将推出,它可以在服务器端环境中使用,如node.js或通过转发器。

所以,在ES6中如果你这样做了:

for (let i=0; i<100; i++){
    let someVar = i;
}

isomeVar都只是循环的本地。

答案 1 :(得分:13)

不,没有区别;在JavaScript中,变量的作用域是函数级别,而不是块级别。

答案 2 :(得分:2)

正如@icktoofay所说,在javascript中没有区别。在某些语言中,在每次迭代时,变量将被实例化,然后超出范围,然后被垃圾收集。

要在javascript中模拟这个,你可以这样做:

for (var i=0; i<100; i++){
    (function(){
        var myvar = i;
    })();
}

在这种情况下,myvar仅存在于匿名函数的范围内,因此在每次迭代时,都会创建一个新的myvar实例。

答案 3 :(得分:2)

JSLint这样的工具建议您将所有var语句放在函数顶部。这是因为如果你不这样做,JavaScript本质上就是为你做的,所以如果你这样做,那就不那么容易混淆了。在您的示例中,只要它出现在var的一个定义之前,您放置myvar的位置无关紧要。同样,您也可以在函数顶部声明i

更有趣的是分层范围链,其中JavaScript在想要查找名称时搜索名称。它从 local global 搜索范围链,直到找到所述名称的第一个实例。

这就是为什么你可以玩这样的游戏来惹恼你的朋友:

function foofinder() {
    var bar = function () { return foo; },
        foo="beers";
    return bar();
}

foofinder();
>>> "beers"

答案 4 :(得分:0)

通过在变量名之前不断声明var,您可以指示JavaScript引擎或解释器将变量重新初始化为未定义的值(undefined而不是数字,字符串/文本在赋值之前,布尔值或null),这将是额外的指令,从而降低循环执行的速度。您还要夸大代码大小并降低解析/解释/编译代码的速度。

对于几乎任何应用程序,没有功能差异,但仍有一个,并且在数十万或数十亿次循环执行后,差异可能会很明显。但是,在函数中重复使用相同名称的VAR声明会导致Chrome / V8中出现致命异常。

更新:在变量名称之前使用var 明显慢于而不是忽略var,如使用JavaScript控制台在Chrome / v8上运行以下基准测试所示

var startTime = new Date().getTime();
var myvar;
for (var i=0; i<100000; i++){
    myvar = i;
}
console.log(new Date().getTime() - startTime);

var startTimx = new Date().getTime();
var myvax;
for (var j=0; j<100000; j++){
var myvax = j;
}
console.log(new Date().getTime() - startTimx);
161
169

第一次测试在161 ms内执行,第二次测试(使用var)执行时间为169 ms。这是7毫秒的差异,在多次运行基准测试后保持一致。

整个基准测试被粘贴到Chrome JavaScript控制台中,然后在执行之前进行编译,这就是为什么第一个输出不会出现在第一次调用console.log()之下。

亲自试试!