Javascript闭包——它们之间的区别是什么

Javascript闭包——它们之间的区别是什么,javascript,closures,Javascript,Closures,编辑 下面的回答是“你可以做私人的东西!”我也要把这个添加到顶部: 我知道可以在闭包中模拟私有变量。这不是我要问的。我在问,鉴于下面的两个例子,我正在“导出”闭包中的所有内容,这两个例子之间的根本区别是什么 给定以下两种创建对象/方法的方法: var test = {} test = (function(){ var a_method = function(print_me){ return "hello "+print_me; } return {p

编辑

下面的回答是“你可以做私人的东西!”我也要把这个添加到顶部:

我知道可以在闭包中模拟私有变量。这不是我要问的。我在问,鉴于下面的两个例子,我正在“导出”闭包中的所有内容,这两个例子之间的根本区别是什么

给定以下两种创建对象/方法的方法:

var test = {}

test = (function(){
    var a_method = function(print_me){
        return "hello "+print_me;
    }

    return {print_me: a_method};
})();

test.print_me2 = function(print_me2){
   return "hello "+print_me2;
}

test.print_me('world');
>>> returns "hello world"

test.print_me2('world');
>>> returns "hello world"
我知道第一种方法允许使用私有变量(作为python开发人员,我根本不想使用私有变量),但对我来说,这两种方法似乎相当相似,只有第一种方法看起来“更酷”(就像所有大型javascript用户那样),而第二种方法看起来非常过时

那么,有什么区别

我已经看过了这里的收尾问题——大多数问题都围绕着你使用它们的内容或原因;我理解它们的效用,我只是想知道为什么你会做第一件而不是第二件,以及它有什么好处


我更喜欢确凿的证据,而不是猜测——不是寻找“酷孩子就是这样做的”或“我听说当你使用闭包时mozilla会更好地使用内存”,而是寻找一个比另一个更好的定性证据。

在第一个例子中,闭包用于将局部变量排除在全局范围之外

var thisIsGlobal = 2;
var test = (function () {
  var thisIsLocal = 3;
  return function () {
    return thisIsLocal;
  };
}());

您得到的是一个函数
test
,调用该函数时返回局部变量
thisIsLocal
的值。无法更改变量的值。您可以将其视为一个私有变量。

方法之间的区别在于创建闭包的匿名函数包装器,而且第一个方法替换整个对象,而第二个方法仅在现有方法中设置一个属性

向对象添加方法有多种方式。创建对象时,可以将它们放在那里:

var test = {
  print_me: function(text) { return "hello " + text; }
};
可以将方法作为属性添加到现有对象:

var test = {};
test.print_me = function(text) { return "hello " + text; };
您可以创建构造函数,并向其原型添加方法:

function Test() {}
Test.prototype.print_me = function(text) { return "hello " + text; };
var test = new Test();
由于Javascript有一个基于原型的对象模型,最后一个是如何创建方法。其他方法是可能的,因为对象属性可以有一个函数作为值


您可以在需要局部变量的任何代码周围使用函数包装器,因此您可以通过设置属性的第二种方法来实现这一点:

test.print_me2 = (function(){

  var method = function(print_me2) {
    return "hello "+print_me2;
  }

  return method;
})();

您提供的第一个方法(立即执行的匿名函数)使您的程序不在全局范围内。在该私有范围内,您可以决定要作为API公开的属性:

(function(win){
  var a, b, c = 1;  

  function init(){ 
    return aa(b);
  }

  function exit(){
    if(cc()){
      return a;
    }
  }

  function aa(){
  }

  function bb(){
  }

  function cc(){
  }

  win.myProgram = {init: init,
                   exit: exit };
})(window);


// We now have access to your API from within the global namespace:    
myProgram.init();    
//etc

“不可能”并不完全正确。一些(旧的)js引擎允许访问函数的
。\uuuuu parent\uuuuuu
属性,这实际上允许访问封闭的父作用域。@JanKuča我理解这里的范围界定问题——我所要求的与私有/公共或其模拟无关,而是两个例子之间的区别——一个在闭包中导出所有内容,另一个在闭包之外。我认为这两个例子之间没有任何实际的区别。你应该使用后者。自动执行的匿名包装器不提供任何附加值。这是一个比以前更好的答案。是的,我知道我正在将对象设置为立即执行的函数的结果,而不是设置所述对象的属性——让我们假设我正在尝试使它成为测试对象上唯一的属性。在闭包中做这件事的好处是什么,而不是把它当作一个直接的任务来做?@tkone:在闭包中做这件事的好处就是你有了闭包。您可以创建局部变量,这样就不会污染全局名称空间。但是,如果您正在编写库代码或插件,那么使用全局名称空间时要小心一些。例如,大型库jQuery只向全局名称空间添加了两个名称。ok cool。我知道在全局名称空间中添加大量名称是一个坏主意(因此使用名称空间),但我只是想知道人们是否因为“热”而进行闭包,或者是否在上述情况下提供了实用程序。