闭包
闭包是个 js 中比较重要的一个概念了,面试前端或者 Node.js 方面的工作几乎95%以上的面试官都会问这方面的问题。但是对初学者来说,闭包是个特别抽象的概念,特别是 ECMAScript 给出的定义:
闭包是函数和声明该函数的词法环境的组合
如果你只是个小白没有实战经验,这句话你懂几个字?
先来看个函数
function init() {
var name = "nys";
// name 是一个被 init 创建的局部变量
function displayName() {
// displayName() 是内部函数,一个闭包
alert(name);
// 使用了父函数中声明的变量
}
displayName();
}
init();
init() 创建了一个局部变量 name 和一个名为 displayName() 的函数。displayName() 是定义在 init() 里的内部函数,仅在该函数体内可用。displayName() 内没有自己的局部变量,然而它可以访问到外部函数的变量,所以 displayName() 可以使用父函数 init() 中声明的变量 name 。但是,如果有同名变量 name 在 displayName() 中被定义,则会使用 displayName() 中定义的 name 。
再看个函数
function makeFunc() {
var name = "nys";
return function displayName() {
alert(name);
}
}
var myFunc = makeFunc();
myFunc();
从运行的结果来看,没有什么不一样,都是会输出 name 的值。但是内部的区别就在于,displayName() 函数在执行前先被返回了,先被返回到了定义的 myFunc 后,再用 myFunc()执行。在很多的编程语言中,函数内部的变量只能在函数执行期间被使用,一旦 makeFunc() 执行完毕,我们会认为 name 变量将不能被访问。然而,因为代码运行得没问题,所以很显然在 JavaScript 中并不是这样的。
其实,这就是 闭包 ,由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。在我们的例子中,myFunc() 是执行 makeFunc() 时创建的 displayName() 函数实例的引用,而 displayName() 实例仍可访问其词法作用域中的变量,即可以访问到 name 。由此,当 myFunc() 被调用时,name 仍可被访问,其值 nys 就被传递到alert 中。
闭包的用处
在很多的编程语言中,都支持将方法、字段等设置为私有,即把它们当作一个类的内部内容所调用,其调用权限仅限于本类。而 JavaScript 没有这种原生支持,但我们可以使用闭包来模拟私有方法。(也被成为模块模式)
var Counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
})();
console.log(Counter.value()); /* logs 0 */
Counter.increment();
Counter.increment();
console.log(Counter.value()); /* logs 2 */
Counter.decrement();
console.log(Counter.value()); /* logs 1 */
在匿名函数 Counter()内只有一个共享的变量 privateCounter ,但是它被内部的三个函数所共享Counter.increment,Counter.decrement 和 Counter.value。三个函数的操作都同时影响唯一变量 privateCounter。
本文详细解析了JavaScript中闭包的概念,通过实例说明闭包如何允许内部函数访问外部函数的变量,即使在外部函数执行完毕后。并展示了闭包在模拟私有变量和方法中的应用。
380

被折叠的 条评论
为什么被折叠?



