var funcs = [];// let's create 3 functionsfor (var i = 0; i < 3; i++) {// and store them in funcsfuncs[i] = function() {// each should log its value.console.log("My value: " + i);};}for (var j = 0; j < 3; j++) {// and now let's run each one to seefuncs[j]();}
var foo = "Foo"; // globally scopedlet bar = "Bar"; // not allowed to be globally scoped
console.log(window.foo); // Fooconsole.log(window.bar); // undefined
重新声明
在严格模式下,var将允许您在同一范围内重新声明相同的变量,而let会引发一个语法错误。
'use strict';var foo = "foo1";var foo = "foo2"; // No problem, 'foo1' is replaced with 'foo2'.
let bar = "bar1";let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared
// An array of adder functions.var adderFunctions = [];
for (var i = 0; i < 1000; i++) {// We want the function at index i to add the index to its argument.adderFunctions[i] = function(x) {// What is i bound to here?return x + i;};}
var add12 = adderFunctions[12];
// Uh oh. The function is bound to i in the outer scope, which is currently 1000.console.log(add12(8) === 20); // => falseconsole.log(add12(8) === 1008); // => trueconsole.log(i); // => 1000
// It gets worse.i = -8;console.log(add12(8) === 0); // => true
// Let's try this again.// NOTE: We're using another ES6 keyword, const, for values that won't// be reassigned. const and let have similar scoping behavior.const adderFunctions = [];
for (let i = 0; i < 1000; i++) {// NOTE: We're using the newer arrow function syntax this time, but// using the "function(x) { ..." syntax from the previous example// here would not change the behavior shown.adderFunctions[i] = x => x + i;}
const add12 = adderFunctions[12];
// Yay! The behavior is as expected.console.log(add12(8) === 20); // => true
// i's scope doesn't extend outside the for loop.console.log(i); // => ReferenceError: i is not defined
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><p>Clicking on each number will log to console:</p><div id="div1">1</div><div id="div2">2</div><div id="div3">3</div><div id="div4">4</div><div id="div5">5</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><p>Clicking on each number will log to console:</p><div id="div1">1</div><div id="div2">2</div><div id="div3">3</div><div id="div4">4</div><div id="div5">5</div>
function varTest() {var x = 31;if (true) {var x = 71; // Same variable!console.log(x); // 71}console.log(x); // 71}
function letTest() {let x = 31;if (true) {let x = 71; // Different variableconsole.log(x); // 71}console.log(x); // 31}
function process(data) {//...}
var hugeData = { .. };
process(hugeData);
var btn = document.getElementById("mybutton");btn.addEventListener( "click", function click(evt){//....});
function process(data) {//...}
{ // anything declared inside this block can be garbage collectedlet hugeData = { .. };process(hugeData);}
var btn = document.getElementById("mybutton");btn.addEventListener( "click", function click(evt){//....});
let loops
let in the loop can re-binds it to each iteration of the loop, making sure to re-assign it the value from the end of the previous loop iteration. Consider,
// print '5' 5 timesfor (var i = 0; i < 5; ++i) {setTimeout(function () {console.log(i);}, 1000);}
但是,将var替换为let
// print 1, 2, 3, 4, 5. nowfor (let i = 0; i < 5; ++i) {setTimeout(function () {console.log(i);}, 1000);}
// i IS NOT known here// j IS NOT known here// k IS known here, but undefined// l IS NOT known here
function loop(arr) {// i IS known here, but undefined// j IS NOT known here// k IS known here, but has a value only the second time loop is called// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {// i IS known here, and has a value// j IS NOT known here// k IS known here, but has a value only the second time loop is called// l IS NOT known here};
// i IS known here, and has a value// j IS NOT known here// k IS known here, but has a value only the second time loop is called// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {// i IS known here, and has a value// j IS known here, and has a value// k IS known here, but has a value only the second time loop is called// l IS NOT known here};
// i IS known here, and has a value// j IS NOT known here// k IS known here, but has a value only the second time loop is called// l IS NOT known here}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {// i IS NOT known here// j IS NOT known here// k IS known here, and has a value// l IS NOT known here};
for( let l = 0; l < arr.length; l++ ) {// i IS NOT known here// j IS NOT known here// k IS known here, and has a value// l IS known here, and has a value};
loop([1,2,3,4]);
// i IS NOT known here// j IS NOT known here// k IS known here, and has a value// l IS NOT known here
function printnums(){// i is not accessible herefor(let i = 0; i <10; i+=){console.log(i);}// i is not accessible here
// j is accessible herefor(var j = 0; j <10; j++){console.log(j);}// j is accessible here}
(() => {var functionScopedVariable = 42;let blockScopedVariable = 43;
console.log(functionScopedVariable); // 42console.log(blockScopedVariable); // 43})();
console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not definedconsole.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined
在一个街区里
在块内使用let声明的变量不能在该块之外访问。
{var globalVariable = 42;let blockScopedVariable = 43;console.log(globalVariable); // 42console.log(blockScopedVariable); // 43}
console.log(globalVariable); // 42console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined
在一个循环中
在循环中用let声明的变量只能在该循环中引用。
for (var i = 0; i < 3; i++) {var j = i * 2;}console.log(i); // 3console.log(j); // 4
for (let k = 0; k < 3; k++) {let l = k * 2;}console.log(typeof k); // undefinedconsole.log(typeof l); // undefined// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.
var a;var a; // Works fine.
let b;let b; // SyntaxError: Identifier 'b' has already been declared
var c;let c; // SyntaxError: Identifier 'c' has already been declared
const
const与let非常相似-它是块范围的并且具有TDZ。然而,有两件事是不同的。
没有重新分配
使用const声明的变量不能重新分配。
const a = 42;a = 43; // TypeError: Assignment to constant variable.
function varTest() {var x = 1;if (true) {var x = 2; // same variable!console.log(x); // 2}console.log(x); // 2}
function letTest() {let x = 1;if (true) {let x = 2; // different variableconsole.log(x); // 2}console.log(x); // 1}`
在程序和函数的顶层,与var不同,让不在全局对象上创建属性。例如:
var x = 'global';let y = 'global';console.log(this.x); // "global"console.log(this.y); // undefined
var a = 1;var b = 2;
if (a === 1) {var a = 11; // the scope is globallet b = 22; // the scope is inside the if-block
console.log(a); // 11console.log(b); // 22}
console.log(a); // 11console.log(b); // 2
{x = x + 1; // ReferenceError during parsing: "x is not defined".let x;console.log(`x is ${x}`); // Never runs.}
相比之下,具有var的相同示例解析并运行而不抛出任何异常。
3.不得重新声明:下面的代码演示了用let声明的变量以后可能不会重新声明:
let x = 1;let x = 2; // SyntaxError: Identifier 'x' has already been declared
4.没有附加到window的全局:
var button = "I cause accidents because my name is too common.";let link = "Though my name is common, I am harder to access from other JS files.";console.log(link); // OKconsole.log(window.link); // undefined (GOOD!)console.log(window.button); // OK
{let l = 'let';const c = 'const';var v = 'var';v2 = 'var 2';}
console.log(v, this.v);console.log(v2, this.v2);console.log(l); // ReferenceError: l is not definedconsole.log(c); // ReferenceError: c is not defined
function varTest() {var x = 1;if (true) {var x = 2; // same variable!console.log(x); // 2}console.log(x); // 2}
function letTest() {let x = 1;if (true) {let x = 2; // different variableconsole.log(x); // 2}console.log(x); // 1}
function testVar () {if(true) {var foo = 'foo';}
console.log(foo);}
testVar();// logs 'foo'
function testLet () {if(true) {let bar = 'bar';}
console.log(bar);}
testLet();// reference error// bar is scoped to the block of the if statement
const name = 'Max';let age = 33;var hasHobbies = true;
name = 'Maximilian';age = 34;hasHobbies = false;
const summarizeUser = (userName, userAge, userHasHobby) => {return ('Name is ' +userName +', age is ' +userAge +' and the user has hobbies: ' +userHasHobby);}
console.log(summarizeUser(name, age, hasHobbies));
(function timer() {for(var i = 0; i <= 5; i++) {setTimeout(function notime() { console.log(i); }, i * 1000);}})();
Stack VariableEnvironment //one VariablEnvironment for timer();// when the timer is out - the value will be the same value for each call5. [setTimeout, i] [i=5]4. [setTimeout, i]3. [setTimeout, i]2. [setTimeout, i]1. [setTimeout, i]0. [setTimeout, i]
####################
(function timer() {for (let i = 0; i <= 5; i++) {setTimeout(function notime() { console.log(i); }, i * 1000);}})();
Stack LexicalEnvironment - each iteration has a new lexical environment5. [setTimeout, i] [i=5]LexicalEnvironment4. [setTimeout, i] [i=4]LexicalEnvironment3. [setTimeout, i] [i=3]LexicalEnvironment2. [setTimeout, i] [i=2]LexicalEnvironment1. [setTimeout, i] [i=1]LexicalEnvironment0. [setTimeout, i] [i=0]
当timer()被调用时,会创建一个执行入口,它将包含与每次迭代对应的变量环境和所有词典环境。
一个简单的例子
【功能范围】
function test() {for(var z = 0; z < 69; z++) {//todo}//z is visible outside the loop}
块范围
function test() {for(let z = 0; z < 69; z++) {//todo}//z is not defined :(}
var cat = "cat";let dog = "dog";
var animals = () => {var giraffe = "giraffe";let lion = "lion";
console.log(cat); //will print 'cat'.console.log(dog); //will print 'dog', because dog was declared outside this function (like var cat).
console.log(giraffe); //will print 'giraffe'.console.log(lion); //will print 'lion', as lion is within scope.}
console.log(giraffe); //will print 'giraffe', as giraffe is a global variable (var).console.log(lion); //will print UNDEFINED, as lion is a 'let' variable and is now out of scope.
let msg = "Hello World";
function doWork() { // msg will be available since it was defined above this opening bracket!let friends = 0;console.log(msg);
// with VAR though:for (var iCount2 = 0; iCount2 < 5; iCount2++) {} // iCount2 will be available after this closing bracket!console.log(iCount2);
for (let iCount1 = 0; iCount1 < 5; iCount1++) {} // iCount1 will not be available behind this closing bracket, it will return undefinedconsole.log(iCount1);
} // friends will no be available after this closing bracket!doWork();console.log(friends);