Javascript 闭包的具体用途是什么?

Javascript 闭包的具体用途是什么?,javascript,closures,Javascript,Closures,我一直在阅读关于闭包和javascript的文章,我想我已经了解了,直到我尝试了以下内容: var Object5 = function (param) { var x = 0; var squareBrace = function () { return '[' + param + x + ']'; }; this.toString = function () { x = x + 1; return squar

我一直在阅读关于闭包和javascript的文章,我想我已经了解了,直到我尝试了以下内容:

var Object5 = function (param) {
    var x = 0;

    var squareBrace = function () {
        return '[' + param + x + ']';
    };

    this.toString = function () {
        x = x + 1;
        return squareBrace();
    };
};
然后我运行了以下代码:

var counter = new Object5("Counter: ");
print("Has x:" + ('x' in counter));
print("Has f:" + ('f' in counter)); 
print("Can access x:" + (!!counter.x));   
print("Can Invoke f:" + (!!counter.f));   
print(counter.toString());
print(counter.toString());
print(counter.toString());
print(counter.toString());
print(counter.toString());
print(counter.toString());
这就是我得到的:

Has x:false
Has f:false
Can access x:false
Can Invoke f:false
[Counter: 1]
[Counter: 2]
[Counter: 3]
[Counter: 4]
[Counter: 5]
[Counter: 6]
我以为我会得到一个“TypeError”,因为“x”和“f”是“未定义的”,但后来我让它工作了。我认为闭包是用来启用这种行为的,“x”和“y”是“私有的”,如果没有闭包,这些成员将被遗忘

很明显我搞错了,或者我错过了一些重要的东西

有人能告诉我闭包是用来做什么的吗?为什么要这样做

谢谢。

闭包是一种范围界定技术。这是一种将一个范围中定义的参数拉入另一个范围的方法。当你这样做的时候

var x = 1;

var f = function(){
   console.log(x); // you've just 'closed in' the variable x.
};

f();
x
将在函数中可用,即使其未在函数中声明


在您的特定实例中,关闭了两个变量:
param
x
。它们被绑定到您定义的函数的范围。当您执行
toString
时,您的值将递增在
x
中关闭的值。当执行
toString
时,该方法同时使用
x
param
。因此,在变量
x
周围有两个闭包,每个方法有一个闭包(它也在对象本身的范围内)

为了解决闭包问题,我们必须了解变量范围在JavaScript中是如何工作的。让我们先看一个基本函数和相关问题:

function uniqueInteger(){     
     var counter = 0;
     return ++counter;
}

console.log(uniqueInteger()); // returns '1'
console.log(counter); // undefined
此函数声明变量
计数器并为其赋值0,然后返回递增的值。正如我们所看到的,当函数执行时,变量计数器可以在函数中访问。但是,一旦函数返回,就不再定义变量,因为它是
uniqueInteger()
函数作用域的一部分。我们也可以说
计数器
变量是私有的;只有函数
uniqueInteger()
可以访问它

但如果我们想“记住”该变量的值,以便下次调用该函数时,
计数器从1开始,而不是从0开始,该怎么办呢。一种方法是在函数外部声明变量
计数器
,但它将不再是私有的,其他函数可以更改计数器变量

为了解决这个问题,我们需要了解函数是如何工作的。调用函数时(如上所示),其变量在返回后就不再存在。但在该函数的范围内,任何嵌套函数仍将能够访问其父函数的“私有”变量:

function uniqueInteger(){     
     var counter = 0; 

     // an example of nested function accessing the counter variable:
     return (function() { return ++counter })(); 
}

console.log(uniqueInteger()); // returns '1'
console.log(counter); // undefined
*请注意,带括号()的调用数与定义的函数数一致。嵌套函数是自调用的,外部函数是通过
console.log(uniqueInteger())行调用的因此,相同的函数可以写成:

function uniqueInteger(){     
     var counter = 0; 

     // an example of nested function accessing the counter variable:
     return function() { return ++counter }; 
}

console.log(uniqueInteger()()); // returns '1'
console.log(counter); // undefined
我们可以看到,嵌套函数仍然可以访问变量计数器,
uniqueInteger()
函数仍然返回“1”。尽管在
uniqueInteger()
返回后计数器变量仍然消失(我们稍后会解决这个问题),但嵌套函数可以访问
counter
这一事实使它能够对该变量执行操作,然后返回结果。无论何时调用
uniqueInteger()
,都将存在相同的“作用域链”。非常简单地说,这被称为词汇范围

现在让我们来讨论变量计数器在函数返回后消失的问题。这里发生的事情是JavaScript一个名为垃圾收集的特性的结果。当函数及其变量不再使用时,它们会被“抛出”。但是,如果有一个对该函数返回值的引用(例如,如果该函数被分配给外部变量),则根据上面提到的“作用域链”,它将与其中的任何变量一起被“记住”:

function uniqueInteger(){    
     var counter = 0;
     return function() { return ++counter };
}

var uniqueInt = uniqueInteger();

console.log(uniqueInt()); // returns '1'
console.log(uniqueInt()); // returns '2'

console.log(counter) // still "undefined"
发生了什么事?因为我们将嵌套函数的返回值“保存”在外部变量中,所以变量
计数器
没有被垃圾收集,并且下次调用
uniqueInt()
时,计数器仍然等于1。我们也可以说,它的状态被拯救了。我们实现了我们的目标:我们制作了一个函数,在调用之间记住它的变量,而不在它之外定义它的变量,保持它们的私有性

我们可以将上述函数重写为函数定义表达式:

var uniqueInteger = (function(){     
     var counter = 0;
     return function() { return ++counter };
})();

console.log(uniqueInteger()); // returns '1'
console.log(uniqueInteger()); // returns '2'

console.log(counter) // still "undefined"
请注意,仍然有两个函数,因此有两个相应的调用。只有这一次外部函数是自调用的,以便将其返回值(而不仅仅是函数本身)保存到变量
uniqueInteger
。否则,变量
uniqueInteger
的返回值将是
function(){return++counter;}
。上述技术本质上就是闭包:在函数中使用函数(*或对象)对内部值进行操作,这些值在调用之间保存状态,同时保持私有状态

*还可以返回具有对外部函数的值进行操作的函数的对象:

var uniqueInteger = (function(){     
     var counter = 0;
     return {
          value: function() { return counter },
          count: function() { return ++counter },
          reset: function() { counter = 0; return counter;}
     };

})();

console.log(uniqueInteger.value()); // 0
uniqueInteger.count();
console.log(uniqueInteger.value()); // 1
uniqueInteger.reset()
console.log(uniqueInteger.value()); // again 0
此模式允许您拥有一个自包含的函数对象,该对象对其自己的私有变量进行操作,而不存在名称冲突或外部恶意篡改的风险


我也很难理解闭包,但如果你继续阅读相关文献,最终你会得到答案。继续玩你的代码:)

所以我在“x”上有两个闭包,但这两个方法都共享这个变量,对吗?我读到过,过多的闭包对性能有害,有没有一种方法可以在没有闭包的情况下实现同样的效果?