简体   繁体   English

JavaScript 变量如何工作?

[英]How do JavaScript variables work?

I know that JavaScript vars point to a value:我知道 JavaScript 变量指向一个值:

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

So in that example I've changed foo pointing to true -> foo pointing to false , but if I do:所以在那个例子中,我改变了foo指向true -> foo指向false ,但如果我这样做:

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

Am I creating a new var for each iteration?我是否为每次迭代创建一个新的 var?

Is there any difference in the following two ways of doing the same?以下两种方式做同样的事情有什么区别吗?

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

and

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

If so, why?如果是这样,为什么?

There is no block scope in Javascript ES5 and earlier, only function scope.在 Javascript ES5 及更早版本中没有块作用域,只有函数作用域。 Furthermore, the declarations of all javascript variables declared within a function scope are automatically "hoisted" to the top of the function.此外,在函数范围内声明的所有 javascript 变量的声明都会自动“提升”到函数的顶部。

So, declaring a variable within a loop isn't doing anything different than declaring it at the top of the function and then referencing it within the loop.因此,在循环中声明变量与在函数顶部声明然后在循环中引用它没有什么不同。

See these two references for some useful explanation: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting and http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/ .有关一些有用的解释,请参阅这两个参考资料: http : //www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoistinghttp://net.tutsplus.com/tutorials/javascript-ajax/quick-tip -javascript-hoisting-explained/

Note: the assignment to a variable is not hoisted, just the declaration of the variable.注意:对变量的赋值不会被提升,只是变量的声明。 So, if you do this:所以,如果你这样做:

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

It works like this:它是这样工作的:

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

If you wanted to create a new scope inside your for loop, you could use an IIFE (immediately invoked function expression) like this:如果你想在你的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
        })();
    }
}

Update in 2015. ES6 (or sometimes called ES2015) offers the let declaration which does offer block scope. 2015 年更新。 ES6(或有时称为 ES2015)提供了let声明,它确实提供了块作用域。 In that case a let variable declaration is hoisted only to the top of the current block scope.在这种情况下,一个let变量声明只会被提升到当前块作用域的顶部。 As of mid 2015, this is not yet widely implemented in browsers, but is coming soon and it is available in server-side environments like node.js or via transpilers.截至 2015 年年中,这尚未在浏览器中广泛实现,但即将推出,它可以在 node.js 等服务器端环境中或通过转译器使用。

So, in ES6 if you did this:所以,在 ES6 中,如果你这样做:

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

Both i and someVar would be local to the loop only. isomeVar都只是循环本地的。

No, there is no difference;不,没有区别; in JavaScript, variables are scoped on the function level, not the block level.在 JavaScript 中,变量的作用域是函数级别,而不是块级别。

As @icktoofay said, in javascript there is no difference.正如@icktoofay 所说,在 javascript 中没有区别。 In some languages, at each iteration, the variable will be instantiated, then go out of scope, and left to be garbage collected.在某些语言中,在每次迭代中,变量将被实例化,然后超出范围,并留给垃圾收集。

To simulate this in javascript, you could do:要在 javascript 中模拟这一点,您可以执行以下操作:

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

In this case, myvar only exist in the scope of the anonymous function, so at each iteration, a new instance of myvar is created.在这种情况下,myvar 只存在于匿名函数的范围内,因此在每次迭代时,都会创建一个新的 myvar 实例。

Tools like JSLint recommend that you put all your var statements at the top of functions. JSLint 之类的工具建议您将所有var语句放在函数的顶部。 It's because JavaScript essentially does it for you if you don't, so it's less confusing if you do.这是因为如果您不这样做,JavaScript 基本上会为您完成,因此如果您这样做,就不会那么混乱。 In your example, it doesn't matter where you put var as long as it occurs before one definition of myvar .在您的示例中,只要它出现在myvar一个定义之前,将var放在哪里并不重要。 Likewise, you may as well declare i at the top of the function as well.同样,您也可以在函数顶部声明i

What's more interesting is the hierarchical scope chain in which JavaScript searches for names when it wants to look one up.更有趣的是分层作用域链,当 JavaScript 想要查找名称时,它会在其中搜索名称。 It searches up the scope chain from local to global until it finds the first instance of said name.它从本地全局搜索作用域链,直到找到所述名称的第一个实例。

Which is why you can play games like this to annoy your friends:这就是为什么你可以玩这样的游戏来惹恼你的朋友:

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

foofinder();
>>> "beers"

By constantly declaring var before the variable name, you could be instructing the JavaScript engine or interpreter to re-initialize the variable to an undefined value ( undefined as opposed to a number, string/text, boolean value, or null ) before assignment, which would be extra instructions, slowing down the speed of loop execution.通过在变量名之前不断声明var ,您可以指示 JavaScript 引擎或解释器在赋值之前将变量重新初始化为未定义的值( undefined ,而不是数字、字符串/文本、布尔值或null ),即将是额外的指令,减慢循环执行的速度。 You're also inflating code size and reducing the speed at which the code is parsed/interpreted/compiled.您还增加了代码大小并降低了解析/解释/编译代码的速度。

For virtually any application, there is no functional difference, but there still is one and the difference might be noticeable after hundreds of thousands or billions of loop executions.对于几乎任何应用程序,都没有功能差异,但仍然存在差异,并且在数十万或数十亿次循环执行后差异可能会很明显。 However, repeated VAR declarations of the same name within a function leads to fatal exceptions in Chrome / V8.但是,在函数中重复使用同名 VAR 声明会导致 Chrome / V8 中的致命异常。

UPDATE: Using var before the variable name is provably slower than omitting var as demonstrated by the following benchmark run on Chrome / v8 with the JavaScript console.更新:事实证明,在变量名之前使用var比省略 var,如下面在 Chrome / v8 上使用 JavaScript 控制台运行的基准测试所证明的那样。

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

The first test executed in 161 ms and the second test (with var ) took 169 ms to execute.第一个测试在 161 毫秒内执行,第二个测试(使用var )用了 169 毫秒来执行。 That's a difference of 7 ms, consistent after multiple runs of the benchmark.这是 7 毫秒的差异,在多次运行基准测试后保持一致。

The entire benchmark was pasted into the Chrome JavaScript console and then compiled before its execution, which is why the first output does not appear below the first call to console.log().整个基准测试被粘贴到 Chrome JavaScript 控制台中,然后在执行前编译,这就是为什么第一个输出不会出现在第一次调用 console.log() 的下方。

Try it yourself!自己试试吧!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM