嗨,我仍然不确定在javascript中使用闭包的确切用法。我对闭包有一个想法“闭包是一个内部函数,可以访问外部(封闭)函数的变量 - 作用域链”。但我不知道为什么我们在javascript中使用闭包。
答案 0 :(得分:0)
它允许您简洁地表达逻辑,而无需重复自己或为回调函数提供大量参数和参数。
此处提供了更多信息:javascript closure advantages?
答案 1 :(得分:0)
一般来说,闭包的主要用途是创建一个从其上下文中捕获状态的函数。考虑该函数具有捕获的变量,但它们不作为参数传递。
所以,你可以把它想象成一种创建函数族的方法。例如,如果您需要一系列只有一个值不同的函数,但是您不能将该值作为参数传递,则可以使用闭包创建它们。
Mozilla开发者网络有一个很好的introduction关闭。它显示了以下示例:
function init() {
var name = "Mozilla";
function displayName() {
alert(name);
}
displayName();
}
init();
在这种情况下,函数displayName
已捕获变量name
。虽然这个例子不是很有用,但你可以考虑返回函数的情况:
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
此处函数makeFunc
返回已捕获变量displayName
的函数name
。现在可以通过将函数赋值给变量myFunc
来调用该函数。
要继续此示例,请立即考虑捕获的变量name
实际上是否为参数:
function makeFunc(name) {
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc("Mozilla");
myFunc();
在这里你可以看到makeFunc
创建一个函数,显示一条消息,其中文本作为参数传递。因此,它可以创建一整套函数,仅根据该变量的值(示例中为"Mozilla"
)而有所不同。使用此功能,我们可以多次显示该消息。
这里的相关内容是按摩中显示的值已被封装。我们以类似的方式保护这个值,一个类的私有字段隐藏了其他语言的值。
这允许您创建一个计数的函数:
function makeFunc(value) {
function displayName() {
alert(value);
value++;
}
return displayName;
}
var myFunc = makeFunc(0);
myFunc();
在这种情况下,每次调用存储在myFunc中的函数时,您将获得下一个数字,第一个0,下一个1,2 ......依此类推。
更高级的例子是来自Mozilla开发者网络的“计数器”“类”。它演示了模块模式:
var Counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
})();
alert(Counter.value()); /* Alerts 0 */
Counter.increment();
Counter.increment();
alert(Counter.value()); /* Alerts 2 */
Counter.decrement();
alert(Counter.value()); /* Alerts 1 */
在这里,您可以看到Counter
是一个对象,其方法increment
推进privateCounter
变量,方法decrement
递减它。可以通过调用方法value
来查询此变量的值。
归档的方式是自动调用匿名函数,该函数创建一个声明变量privateCounter
的隐藏作用域。现在,只能从捕获其值的函数中访问此变量。
答案 2 :(得分:0)
这是因为information hiding。
var myModule = (function (){
var privateClass = function (){};
privateClass.prototype = {
help: function (){}
};
var publicClass = function (){
this._helper = new privateClass();
};
publicClass.prototype = {
doSomething: function (){
this._helper.help();
}
};
return {
publicClass: publicClass
};
})();
var instance = new myModule.publicClass();
instance.doSomething();
在javascript中,您没有包含ppp(公共,受保护,私有)属性的类,因此您必须使用闭包来隐藏信息。在类级别上,这将非常昂贵,因此您可以做的唯一事情是在模块级别上使用闭包更好的代码质量,并在该闭包中使用私有帮助器类。因此,闭包是为了隐藏信息。它不便宜,它耗费资源(内存,CPU等),所以你必须在适当的地方使用闭包。所以永远不要在课堂上使用它来隐藏信息,因为它太贵了。
使用回调对bind方法实例的另一种用法。
Function.prototype.bind = function (context){
var callback = this;
return function (){
return callback.apply(context, arguments);
};
};
绑定函数的典型用法是异步调用:defer,ajax,事件监听器等......
var myClass = function (){
this.x = 10;
};
myClass.prototype.displayX = function (){
alert(this.x);
};
var instance = new myClass();
setTimeout(instance.displayX.bind(instance), 1000); //alerts "x" after 1 sec
答案 3 :(得分:0)
想象一下,而不是
alert("Two plus one equals" + (2+1) );
你被迫为你曾经使用的每个常数声明一个变量。
var Two = 2;
var One = 1;
var myString = "Two plus one equals";
alert(myAlert + (Two + One) );
如果你必须为每一个常数定义一个变量,你就会疯狂。
在闭包的情况下访问局部变量是一个优点,但主要作用 - 有用性 - 是使用函数作为主表达式,常量。
取
function Div1OnClick()
{
Counter.clickCount ++;
}
$('#Div1').click(Div1OnClick);
与
$('#Div1').click(function(){ Counter.clickCount++; });
您不会在上面的""中创建一个新的功能名称。命名空间只需使用一次。实际活动就在那里使用它 - 你不需要在代码中追逐它来写它的位置。您可以将实际函数用作常量,而不是先定义和命名它,然后按名称调用它,虽然有无数的警告,优势和技巧与闭包相关联,但这是销售它们的一个属性。 / p>
答案 4 :(得分:0)
闭包是一种功能强大的构造,用于在JavaScript中实现许多其他功能。例如,闭包可用于公开私有状态,如下所示:
function getCounter() {
var count = 0;
return function () {
return ++count;
};
}
var counter = getCounter();
alert(counter()); // 1
alert(counter()); // 2
alert(counter()); // 3
在我们调用getCounter
的上述示例中,我们创建了一个私有变量count
。然后我们返回一个返回count
递增的函数。因此,我们返回的函数是一个闭包,它关闭变量count
,并允许您在count
超出范围后访问它。
这很多信息都塞满了几行。我们分解吧?
好的,所以变量就像人一样有生命。他们出生,他们活着,他们死了。起始范围标志着变量的诞生,范围的结束标志着变量的死亡。
JavaScript只有函数范围。因此,当你在函数中声明一个变量时,它会被提升到函数的开头(它出生的地方)。
当您尝试访问未声明的变量时,您将获得ReferenceError
。但是,当您尝试访问稍后声明的变量时,您将获得undefined
。这是因为JavaScript中的声明已被提升。
function undeclared_variable() {
alert(x);
}
undeclared_variable();
当您尝试访问未声明的变量时,您会获得ReferenceError
。
function undefined_variable() {
alert(x);
var x = "Hello World!";
}
undefined_variable();
当您尝试访问稍后在函数中声明的变量时,您获得undefined
,因为只有声明被提升。定义将在稍后出现。
返回范围变量在超出范围时死亡(通常在声明变量的函数结束时)。
例如,以下程序将提供ReferenceError
,因为x
未在全局范围内声明。
function helloworld() {
var x = "Hello World!";
}
helloworld();
alert(x);
闭包很有意思,因为即使声明变量的函数结束,它们也允许您访问变量。例如:
function getCounter() {
var count = 0;
return function () {
return ++count;
};
}
var counter = getCounter();
alert(counter()); // 1
alert(counter()); // 2
alert(counter()); // 3
在上面的程序中,变量count
在函数getCounter
中定义。因此,当对getCounter
的调用结束时,变量count
也会死亡。
但事实并非如此。这是因为getCounter
返回访问count
的函数。因此,只要该函数(counter
)存活,变量count
也将保持活跃。
在这种情况下,返回的函数(counter
)称为闭包,因为关闭变量count
,称为upvalue
counter
。
足够的解释。为什么我们还需要关闭?
正如我之前已经提到的,闭包的主要用途是公开私有状态,就像getCounter
函数一样。
闭包的另一个常见用例是partial application。例如:
function applyRight(func) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
var rest = Array.prototype.slice.call(arguments);
return func.apply(this, rest.concat(args));
};
}
function subtract(a, b) {
return a - b;
}
var decrement = applyRight(subtract, 1);
alert(decrement(1)); // 0
在上面的程序中,我们有一个名为subtract
的函数。我们使用部分应用程序从此decrement
函数创建另一个名为subtract
的函数。
正如您所看到的,decrement
函数实际上是一个闭包,关闭变量func
和args
。
这几乎是关于闭包的所有知识。