ES6 新增了 let 命令,用来声明变量。它的用法类似于 var,但其声明的变量只在 let 命令所在的代码块内有效。
1. let 命令作用城只局限于当前代码块
示例1
| { |
| let a = 10; |
| var b = 1; |
| } |
| |
| console.log("输出a:"); |
| console.log("a = " + a); |
| |
| |
| [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("输出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
| |
| 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 |
| |
| 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> |

无论单击哪个按钮,最后打印的都是“这是第 5 个按钮”。什么原因呢?因为 for 是同步操作,而 for 循环内部的函数执行的是异步操作,当函数执行找不到 hzh 时,便会往上面的作用域查找,所以 hzh 的值为 5,最后打印的都是“这是第 5 个按钮”。下面通过上机训练 1 来看 let 命令如何解决这个问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?