我阅读了有关const
、let
、var
的MDN页面。在ES2015
之前,我们只有global scope
和function scope
。在[此MDN页面][1]中,有一个块作用域优点的示例;这表明:没有使用闭包概念来保存函数的相关数据,比如循环迭代次数,而是将循环变量定义为let
。如果let
关键字仅用于块范围界定,如何为我们提供此功能?其他编程语言有这个概念吗?
let divClassX = document.querySelectorAll('.x');
for (let j = 0; j < 2; j++) {
divClassX[j].onclick = function (event) {
console.log('class x div's x ' + j)
}
}
上述代码具有与相同的功能
let divClassX = document.querySelectorAll('.x');
for (var j = 0; j < 2; j++) {
divClassX[j].onclick = (function (j) {
return function (event) {
console.log('class x div's x ' + j)
}
})(j)
}
我假设存在一些类似的功能,所以blow代码必须像上面一样工作,但当我两次点击div1或div2时,我都会得到2,但当点击div1时,我会得到一个,当点击div2时会得到两个。
let div1 = document.querySelector('#div1');
let div2 = document.querySelector('#div2');
let i = 1;
div1.onclick = function (event) {
console.log(i);
}
i = i + 1;
div2.onclick = function (event) {
console.log(i);
}
存在什么我不知道的概念?[1] :https://developer.mozilla.org/en-US/docs/Glossary/IIFE
与其说是修改变量的顺序,不如说是定义变量的作用域。
在上一个示例中,let i
出现在全局范围中。作为事件侦听器创建的每个function
都会创建自己的作用域,其父作用域是全局作用域。创建函数时i
的值是多少并不重要,重要的是作用域链的结构。JavaScript在越来越大的范围中查找变量;链";父作用域的。对于这两个函数,当在调用函数时访问时,i
将解析为全局作用域,而不是在创建函数时。
至于使用let
的循环,我认为let
的部分设计目标是使循环/事件处理程序(或其他嵌套函数(的行为更加直观,并提供一种简单的方法来避免常见问题,即每个事件处理程序引用i
的最后值,而不是创建函数时的值(即在循环的每次迭代时(。
换句话说,在ES2015中,循环的每个迭代都有一个单独的作用域,let
将变量分配给该作用域,而不是分配给周围的function
或像var
这样的全局作用域。此外,当调用嵌套函数(位于for
循环内的函数(时;迭代";在查找作用域链时,首先查找作用域,因此它看到的i
与迭代时一样。
它被称为闭包。
闭包是捆绑在一起的函数的组合(封闭(以及对其周围状态(词汇环境(的引用。在里面换句话说,闭包使您可以访问外部函数的作用域来自内部功能。在JavaScript中,每次都会创建闭包在函数创建时创建函数。
在您的最后一段中
console.log(i);
不打印副本,而是实际变量i
(引用(,它是用初始化的
let i = 1;
并用进行了修改
i = i + 1;