看这个:
var arr = []
for(var i = 0; i < 10; i++){
arr[i] = function () {
console.log(i)
}
}
arr[0](); // 10
arr[1](); // 10
arr[2](); // 10
arr[3](); // 10
还有这个:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
// 获取元素
var lis = document.querySelectorAll('li');
for(var i = 0; i<lis.length; i ++){
lis[i].onclick = function(){
console.log(i);//5 不能使用i
}
}
</script>
这里是这个全局变量i
出了问题,以上js相当于:
{
var i=0;
lis[0].onclick = function(){
console.log(i);
}
}
{
var i=1;
lis[1].onclick = function(){
console.log(i);
}
}
{
var i=2;
lis[2].onclick = function(){
console.log(i);
}
}
……
{
var i=4;
lis[4].onclick = function(){
console.log(i);
}
}
{
var i = 5;
}
当点击事件触发时,for循环已经执行结束了,由于i是var定义的,后面定义的i会覆盖前面的,所以最后i
为5,当执行函数时,函数内没有i,根据作用域链向父级找,得到的是全局变量i = 5。
同样,把var换成let:
{
let i=0;
lis[0].onclick = function(){
console.log(i);
}
}
{
let i=1;
lis[1].onclick = function(){
console.log(i);
}
}
{
let i=2;
lis[2].onclick = function(){
console.log(i);
}
}
……
{
let i=4;
lis[4].onclick = function(){
console.log(i);
}
}
{
let i = 5;
}
let定义的i作用域仅在他所在的花括号内,几个花括号的i互不影响,函数向上级找到的i自然都不同。
把var换成let就能解决,或者:
for(var i = 0; i<lis.length; i ++){
lis[i].index = i;
lis[i].onclick = function(){
//console.log(i);//5 不能使用i
// 输出每一个li的下标
console.log(this.index);//0 1 2 3 4
}
}
同样,以下代码为例,应该也可以理解了:
var arr = []
for(var i = 0; i < 3; i++){
arr[i] = function () {
console.log(i)
}
}
arr[0](); // 3
arr[1](); // 3
arr[2](); // 3
for循环的执行过程为:
{
var i=0;
arr[0] = function () {
console.log(i)
}
}
{
var i=1;
arr[1] = function () {
console.log(i)
}
}
{
var i=2;
arr[2] = function () {
console.log(i)
}
}
{
var i=3;
}
再看这个:
for(var i = 0; i < 5;i ++){
console.log(i);//0 1 2 3 4
setTimeout(function(){
console.log(i)//5 5 5 5 5
},0)
}
如上:输出结果为 5 5 5 5 5,按照前面的思路似乎可以理解了
有点晕,又好像没晕
for(var i = 0; i < 5;i ++){
function f1(){
console.log(i)
}
}
f1();//5
我们知道输出是5,但如果把函数的执行在里面
for(var i = 0; i < 5;i ++){
f1();//0 1 2 3 4
function f1(){
console.log(i)
}
}
就是0 1 2 3 4
额、、是因为立即执行的原因吗
前面的setTimeout(function(){},0)
不是立即执行吗?两者如何判断?
尝试验证:
for(var i = 0,a = 1; i < 5;i ++){//1 2 3 4 5
console.log(a);//1 1 1 1 1
setTimeout(function(){
a++;
console.log(i)//5 5 5 5 5
},0)
}
输出结果为:先输出5个1,后输出5个5
由此可见,整个for循环执行完才开始执行setTimeout函数,所以它不是立即执行。。。
可以配合this指向问题食用