1.let和var定义的变量
用let声明的变量,只在let命令所在的代码块里有用.
var声明的是全局变量:
"use strict"
{
var i = 1;
console.log(i);//1
}
console.log(i);//1
用在for循环里的声明变量,最好用let。出了循环就用不了了。
2.闭包
闭包就是函数的嵌套。内层函数能使用外层函数的所有变量。哪怕外层函数已经执行完了,也照样能使用。
匿名函数
下面的例子,经过1秒后,执行forTimeout函数,function forTimeout(x, y){
alert(x + y);
}
function delay(x , y , time){
setTimeout(
function(){
forTimeout(x , y);
}
, time);
}
delay(1, 2, 1000);
通过调试可知,delay函数先执行完,但是里面的变量x,y,time都还没释放,等待着forTimeout执行。
闭包示例1
下面这个例子:第一步,定义outer=null,执行一遍那个匿名函数,包括one的定义和赋值,inner函数的定义(此时不执行仅仅定义),让outer指向inner函数。第二步,执行一次outer,弹出的是2;第三步,再执行一遍outer,弹出3。因为outer指向的是inner函数,对inner的引用还在,所以inner所能使用的变量和空间,都不能释放,所以它能记住上一次执行的outer
var outer = null;
(function(){
var one = 1;
function inner (){
one += 1;
alert(one);
}
outer = inner;
})();
outer(); //2
outer(); //3
outer(); //4
这段代码中的变量one是一个局部变量(因为它被定义在一个函数之内),因此外部是不可以访问的。但是这里我们创建了inner函数,inner函数是可以访问变量one的;又将全局变量outer引用了inner,所以三次调用outer会弹出递增的结果。
闭包示例2
再一个例子,工作中遇到过类似的问题,给一个列表元素的每一项赋相同函数的不同执行结果: <ul>
<li>one</li>
<li>two</li>
<li>three</li>
<li>four</li>
</ul>
var list = document.getElementsByTagName('li');
for (var i = 0; i < list.length; i++) {
list[i].onmouseover = function () {
alert(i);
}
}
本来是想每一个li在鼠标滑过时,都弹出它们自己的下标。结果却:每个li弹出的都是4。原因是:给每个项赋值,让每一个li的onmouseover都指向一个函数,但是赋值是赋值,并没有执行这个函数啊,debugger查看可知确实没有执行。等到鼠标放上去,这才真正执行这个函数。执行的时候,发现没有i变量,那就向上找,有i,但已经变成4了,所以它们就都是4。注意,也不能在function定义后再加个(),因为这是立即执行函数了。它当下执行完,鼠标再放上去,就不执行了。真正的解决办法:
var list = document.getElementsByTagName('li');
for (var i = 0; i < list.length; i++){
debugger;
(function(index){
debugger;
list[index].onmouseover = function () {
alert(index);
}
})(i);
}
还可以把希望li要进行的动作函数放在外面:
function mouseoverAction (item, index) {
item.onmouseover = function () {
alert(index);
}
}
var list = document.getElementsByTagName('li');
for (var i = 0; i < list.length; i++) {
mouseoverAction(list[i], i);
}
3.结合
注意了注意了,第一种方法其实在es6里是可以的。只需要把for循环中的var改成let,即可:
"use strict"
var list = document.getElementsByTagName('li');
for (let i = 0; i < list.length; i++) {
list[i].onmouseover = function () {
alert(i);
}
}
此时,每一项确实是弹出各自的index值。for语句有个特别之处,就是:循环语句部分是一个父作用域,而循环体内部是一个单独的子作用域。同样,赋值是赋值,没有执行这个函数。等到鼠标放上去执行它,发现作用域内有这个变量i,那就弹出i。
var声明的变量,全局范围内都有效。循环改变的是var的值;而let声明的变量,只在for循环及循环体里有效