黄子涵

2 1.1 let 命令

ES6 新增了 let 命令,用来声明变量。它的用法类似于 var,但其声明的变量只在 let 命令所在的代码块内有效。

1. let 命令作用城只局限于当前代码块

示例1
{
    let a = 10;
    var b = 1;
}

console.log("输出a:");
console.log("a = " + a);
// console.log("输出b:");
// console.log("b = " + b);
[Running] node "e:\HMV\JavaScript\JavaScript.js"
输出a:
e:\HMV\JavaScript\JavaScript.js:7
console.log("a = " + a);
                     ^

ReferenceError: a is not defined
    at Object.<anonymous> (e:\HMV\JavaScript\JavaScript.js:7:22)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47

[Done] exited with code=1 in 0.183 seconds
{
    let a = 10;
    var b = 1;
}

// console.log("输出a:");
// console.log(" a = " + a);
console.log("输出b:");
console.log("b = " + b);
[Running] node "e:\HMV\JavaScript\JavaScript.js"
输出b:
b = 1

[Done] exited with code=0 in 0.175 seconds

在示例 1 的代码中,分别用 let 和 var 声明了 一个变量 ,然后在声明代码块之外调用输出,结果 let 声明的变量报错,var 声明的变量返回了正确的值。这表明,用 let 声明的变量只在它所在的代码块有效。

2. 使用 let 声明的变量作用城不会被提前

var 命令支持“变量提升”,即变量可以在声明之前使用,值为 undefined。这种现象多多少少有些奇怪,按照一般的逻辑,变量应该在声明语旬之后才可以使用。

为了纠正这种现象,let 命令改变了语法行为,它所声明的变量一定要在声明之后才能使用,否则报错。

示例2
// var 的情况
console.log("输出变量hzh:");
console.log("hzh = " + hzh);
var hzh = 2; 
[Running] node "e:\HMV\JavaScript\JavaScript.js"
输出变量hzh:
hzh = undefined

[Done] exited with code=0 in 0.175 seconds
// let 的情况
console.log("输出let变量:");
console.log("hcq = " + hcq);
let hcq = 2;
[Running] node "e:\HMV\JavaScript\JavaScript.js"
输出let变量:
e:\HMV\JavaScript\JavaScript.js:3
console.log("hcq = " + hcq);
                       ^

ReferenceError: Cannot access 'hcq' before initialization
    at Object.<anonymous> (e:\HMV\JavaScript\JavaScript.js:3:24)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47

[Done] exited with code=1 in 0.175 seconds

示例 2 中变量 hzh 用 var 命令声明,会发生变量提升,即脚本开始运行时,变量 hzh 已经存在了,但是没有值,所以会输出 undefined。变量 hcq 用 let 命令声明,不会发生变量提升,表示在声明它之前,变量 hcq 是不存在的,如果用到它,就会抛出一个错误。

3. 在相同的作用城下不能声明相用的变量

let 命令不允许在相同作用域内重复声明同一个变量。

示例3
// 报错
function hzh() {
    let hcq = 10;
    var hcq = 1;
}
[Running] node "e:\HMV\JavaScript\JavaScript.js"
e:\HMV\JavaScript\JavaScript.js:4
    var hcq = 1;
        ^

SyntaxError: Identifier 'hcq' has already been declared
    at wrapSafe (internal/modules/cjs/loader.js:915:16)
    at Module._compile (internal/modules/cjs/loader.js:963:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47

[Done] exited with code=1 in 0.174 seconds
// 报错
function hzh() {
    let hcq = 10;
    let hcq = 1;
}
[Running] node "e:\HMV\JavaScript\JavaScript.js"
e:\HMV\JavaScript\JavaScript.js:4
    let hcq = 1;
        ^

SyntaxError: Identifier 'hcq' has already been declared
    at wrapSafe (internal/modules/cjs/loader.js:915:16)
    at Module._compile (internal/modules/cjs/loader.js:963:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47

[Done] exited with code=1 in 0.169 seconds
// 报错
function hzh(hcq) {
    let hcq;
}
[Running] node "e:\HMV\JavaScript\JavaScript.js"
e:\HMV\JavaScript\JavaScript.js:3
    let hcq;
        ^

SyntaxError: Identifier 'hcq' has already been declared
    at wrapSafe (internal/modules/cjs/loader.js:915:16)
    at Module._compile (internal/modules/cjs/loader.js:963:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47

[Done] exited with code=1 in 0.174 seconds
// 不报错
function hzh(hcq) {
    {
        let hcq;
    }
}
[Running] node "e:\HMV\JavaScript\JavaScript.js"

[Done] exited with code=0 in 0.185 seconds

不能在函数内部重复声明参数,声明的参数也不能与形参同名。如果声明的参数是在另外一个作用域下,则是可以进行重复声明的。

4. for 循坏体中 let 的父子作用城

有 5 个按钮,当单击某个按钮时,控制台可以打印输出当前单击的是第几个按钮。按照常规的实现思路,代码实现如下:

示例4
<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>for 循环体中 let 命令</title>
</head>

<body>
  <button>按钮</button> 
  <button>按钮</button>
  <button>按钮</button> 
  <button>按钮</button>
  <button>按钮</button>
  <script>
    var hzhBtns = document.querySelectorAll('button');
    for(var hzh = 0; hzh < hzhBtns.length; hzh++) {
      hzhBtns[hzh].onclick = function () {
        console.log("这是第" + hzh + "个按钮");
      }
    }
  </script>
</body>
</html>

image

无论单击哪个按钮,最后打印的都是“这是第 5 个按钮”。什么原因呢?因为 for 是同步操作,而 for 循环内部的函数执行的是异步操作,当函数执行找不到 hzh 时,便会往上面的作用域查找,所以 hzh 的值为 5,最后打印的都是“这是第 5 个按钮”。下面通过上机训练 1 来看 let 命令如何解决这个问题。

posted @ 2022-06-08 16:09  黄子涵  阅读(84)  评论(0编辑  收藏  举报