nev*_*ame 7 javascript closures
我试图在Javascript中包围我的头.
以下是教程中的示例:
function greeter(name, age) {
var message = name + ", who is " + age + " years old, says hi!";
return function greet() {
console.log(message);
};
}
// Generate the closure
var bobGreeter = greeter("Bob", 47);
// Use the closure
bobGreeter();
Run Code Online (Sandbox Code Playgroud)
作者说这是使用闭包来制作私有变量的有效方法,但我不明白这一点.
有人可以启发像这样编码的好处吗?
ide*_*ide 23
甲闭合是一个双功能和环境(假定在它被定义词法作用域其中JavaScript使用).因此,闭包函数可以访问其环境中的变量; 如果没有其他函数可以访问该环境,那么其中的所有变量都是私有的,只能通过闭包函数访问.
您提供的示例相当好地证明了这一点.我添加了内联注释来解释环境.
// Outside, we begin in the global environment.
function greeter(name, age) {
// When greeter is *invoked* and we're running the code here, a new
// environment is created. Within this environment, the function's arguments
// are bound to the variables `name' and `age'.
// Within this environment, another new variable called `message' is created.
var message = name + ", who is " + age + " years old, says hi!";
// Within the same environment (the one we're currently executing in), a
// function is defined, which creates a new closure that references this
// environment. Thus, this function can access the variables `message', `name',
// and `age' within this environment, as well as all variables within any
// parent environments (which is just the global environment in this example).
return function greet() { console.log(message); };
}
Run Code Online (Sandbox Code Playgroud)
当var bobGreeter = greeter("Bob", 47);运行时,创建一个新的闭包; 也就是说,您现在已经有了一个新的函数实例以及创建它的环境.因此,您的新函数在所述环境中引用了"message"变量,尽管没有其他人这样做.
额外阅读:SICP Ch 3.2.虽然它侧重于Scheme,但这些想法是相同的.如果您对本章有所了解,那么您将对环境和词法范围的工作方式有一个很好的基础.
Mozilla还有一个专门用于解释闭包的页面.
闭包的目的是保证在给定函数内使用的变量"闭合",这意味着它们不依赖于外部变量 - 它们只依赖于并使用它们的参数.这使得您的Javascript方法更接近纯函数,即为同一给定参数返回相同值的函数.
如果不使用封口,您的功能就像瑞士奶酪一样,它们会有漏洞.闭包会堵塞这些孔,因此该方法不依赖于范围链中较高的变量.
现在,到目前为止,我的答案仅仅是组织代码和样式.举个简单的例子吧.在注释的行中,我调用一个函数并a捕获变量的值以供将来使用.
var a = "before";
var f = function(value) {
return function()
{
alert(value);
}
} (a); //here I am creating a closure, which makes my inner function no longer depend on this global variable
a = "after";
f(); //prints "before"
Run Code Online (Sandbox Code Playgroud)
现在,你为什么需要这样做?嗯,这是一个实际的例子.请考虑以下使用jQuery添加5个文档链接的代码.当您单击链接时,您会期望它alert与链接相关联的数字,因此单击您认为会提示0的第一个,依此类推.但是,情况并非如此,每个链接alert的值都是5.这是因为我定义的函数取决于在i函数上下文之外修改的变量.我传入的功能bind是瑞士奶酪功能.
for (var i = 0; i < 5; i++)
{
var a = $('<a>test link</a>').bind('click', function(){
alert(i);
});
$(a).appendTo('body');
}
Run Code Online (Sandbox Code Playgroud)
现在,让我们通过创建一个闭包来解决这个问题,以便每个链接alert都有正确的数字.
for (var i = 0; i < 5; i++)
{
var fn = function (value) {
return function() {
alert(value);
};
} (i); //boom, closure
var a = $('<a>test link</a>').bind('click', fn);
$(a).appendTo('body');
}
Run Code Online (Sandbox Code Playgroud)