JavaScript 的闭包
在前面的知识中,已经说过了,在函数作用域中是可以访问全局作用域中声明的变量或函数,但是在全局作用域中不可以访问函数作用域中声明的变量或函数。其实,在全局作用域中也是访问使用函数作用域中声明的变量或函数,只是要通过闭包的方式才可以使用
。
闭包的定义
闭包就是能够读取其他函数内部变量的函数。
由于 JavaScript 中,只有函数内部的子函数才能读取局部变量,因此,闭包可以理解为“定义在一个函数内部的函数”。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包的2个作用
- 可以在函数外部读取函数内部的变量;
- 让函数内部的变量的值一直保持在内存中;
function fun(){
var x=10;
function fun2() {
x++;
console.log(x);
}
return fun2;
}
var a = fun();
a(); //输出 11
a(); //输出 12,并不是重新开辟内存并初始化,而是使用了第1次声明的 x
闭包的注意点
- 由于闭包可以使函数中的变量一直保存在内存中,所以内存消耗过大,不可以滥用闭包。
- 通过闭包也可以改变函数内部变量的值。比如:返回一个带方法的对象时,如下:
function fun(){
var name = "lin";
return {
getName:function(){
console.log(name);
},
setName:function(){
name = "ha"; //改变私有属性
}
}
}
var a = fun();
a.getName(); //输出 lin
a.setName(); //改变函数内部变量的值
a.getName(); //输出 ha
但在封装的思想中,函数是一个对象,函数中声明的变量应该属于一个私有的属性,不应随便在函数外部改变,所以,不要随便改变函数内部变量的值。
拓展:理解 this 关键字
- 浏览器解析器在每次调用函数时,都会向函数内部传递一个隐含的参数 this。
function fun(){
console.log(this);
}
fun(); // 输出 Window
可见,我们并没有将 this 传到函数中,但是函数中会输出 this 为 Window。
- this 并不是变量,而是一个对象。这个对象称为函数的
上下文对象
。 - 根据调用函数的对象不同,this 就是调用这个函数的对象。
var name = "Window";
var obj = {
name: "Object",
getName:function(){
alert(this.name);
}
}
obj.getName();
Window 对象和 Object 对象中都含有 name 属性,在 getName() 方法中的 this 指代的是 Object 对象
,所以输出的 name 是 “Object ”;
var name = "Window";
var obj = {
name : "Object",
getName:function(){
return function(){
alert(this.name);
}
}
}
var a = obj.getName();
a();
在 getName() 方法执行完成后,返回的是一个函数,如下
function(){
alert(this.name);
}
并赋值给 a,a 是 Window 对象的属性方法,所以 this 指代的是 Window 对象,输入的 name 是“Window”。