File tree Expand file tree Collapse file tree 1 file changed +27
-0
lines changed
docs/languages/javascript Expand file tree Collapse file tree 1 file changed +27
-0
lines changed Original file line number Diff line number Diff line change @@ -505,4 +505,31 @@ counters[2](); // 4
505
505
506
506
这样的代码不仅正确了,可读性也很好。
507
507
508
+ !!! note "为什么是对的?"
509
+
510
+ 事实上这里正确并不是因为 `let` 关键字带来了什么特殊处理,而是因为作用域不再是函数作用域。
511
+ 考虑下面的代码,虽然使用了 `let` 关键字,但作用域仍是函数作用域:
512
+
513
+ ```javascript
514
+ function getCounters() {
515
+ let arr = [];
516
+ let i = 0; // 注意在这里声明的 i 是函数作用域
517
+ for (i = 0; i < 3; ++i) {
518
+ arr.push(function () { console.log(i * i); });
519
+ }
520
+ return arr;
521
+ }
522
+
523
+ let counters = getCounters();
524
+ counters[0](); // 9
525
+ counters[1](); // 9
526
+ counters[2](); // 9
527
+ ```
528
+
529
+ 可以看到,结果仍然是错误的。
530
+
531
+ 那么为什么作用域是局部作用域时就对了呢?
532
+ 原因在于在闭包捕获变量时,对局部作用域的变量会**复制**,而对函数作用域的变量会**引用**。
533
+ 因此,通过在 `for` 语句中使用 `let` 声明变量,我们声明了局部变量,从而获得了期望的复制捕获行为。
534
+
508
535
此外需要注意的是,JavaScript 在任何情况下都不会帮你复制** 对象** (上面被捕获的 ` int ` 是基本值而非对象),如果你的闭包捕获一个对象的值,无论这个对象的作用域如何,都会产生类似问题。事实上,这里并非基本值被特殊地对待,而是对象类型的变量存储的值是到实际对象的引用,因此在捕获时复制的是引用(浅拷贝)而非实际对象(深拷贝)。除非你明确地想要保存一些值,否则在构造闭包时请注意捕获实际的值,而非引用。
You can’t perform that action at this time.
0 commit comments