变量的作用域
变量的作用域无非分为两种:全局变量和局部变量。
- 函数内部用var声明的变量为局部变量,未用var声明的为全局变量。
- 函数外部用var声明的变量为全局变量,全局作用域下的变量最终会变成window对象的属性或方法。
//函数内部可以读取全局变量
var a = 10;
function adc() {
console.log(a);
}
adc();//10
//函数外部不能读取函数内部用var声明的变量
function adc2() {
var b = 20;
}
//console.log(b);// b is not defind
那么如何从外部读取内部局部变量
//在此函数内部再定义一个函数,因为子函数会一级一级地向上寻找所有父对象的变量
//即:父函数内的局部变量对于他里面的子函数都是可访问的,对于他外面的函数则不能访问
function f1() {
var b = 20;
function f2() {
console.log(b);
}
return f2();
}
f1();
闭包的概念
简单来说,闭包就是在另一个作用域中保存了一份它从上一级函数或作用域取得的变量(键值对),而这些键值对是不会随上一级函数的执行完成而销毁。
一个简单的闭包例子
function f3() {
var n = 999;
nadd = function() {
n += 1
};
function f4() {
console.log(n)
}
return f4;
}
var result = f3();
result(); // 999
nadd();
result(); // 1000
//闭包的作用
//读取函数内部的变量。让这些变量的值始终保持在内存中。能够避免全局变量的污染。
垃圾回收机制
js内部会不断扫描内存,清理不被作用的对象。
闭包的注意点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,
在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,
把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),
这时一定要小心,不要随便改变父函数内部变量的值。
在阮一峰的网络日志里看到的两个例子
var name = "the window";
var obj = {
name: "object",
getName: function() {
return function() {
return this.name;
}
}
}
var result = obj.getName(); //返回一个函数 function(){} 再执行该函数时this指向的是window对象而不是当前的obj。
console.log(result()); //the window
var name = "the window";
var obj2 = {
name: "object",
getName: function() {
var self = this;
return function() {
return self.name;
}
}
}
var result = obj2.getName(); //返回一个函数 function(){} 再执行该函数时由于声明了self指向当前的对象,所以结果 return self.name == object;
console.log(result()); //object
闭包打印索引值
//需求:点击li标签打印当前索引值。
<ul>
<li class="aa">1</li>
<li class="aa">2</li>
<li class="aa">3</li>
<li class="aa">4</li>
<li class="aa">5</li>
</ul>
<script type="text/javascript">
var li = document.getElementsByClassName('aa');
for (var i=0;i<li.length;i++) {
li[i].onclick = function() {
console.log(i); //每次打印的都是5,因为最终执行时是window在调用console.log()这个方法,而此时i这个变量已经变成了5。
}
}
//修改为闭包函数把每次变化的i保存下来
for (var i=0;i<li.length;i++) {
li[i].onclick = (function(i) {
return function() {
console.log(i);
}
})(i)
}
</script>