我应该将功能块封装在匿名JavaScript函数中吗?

9

我认为将代码块封装在匿名函数中是一个好主意,像这样:

(function() {
  var aVar;
  aVar.func = function() { alert('ronk'); };
  aVar.mem = 5;
})();

因为我不会再需要 aVar ,所以我假设当它超出作用域时垃圾回收器会删除 aVar 。这是正确的吗?或者解释器是否足够聪明,能看出我不再使用该变量并立即清理它?是否有任何原因(例如风格或可读性)不应该以这种方式使用匿名函数?
此外,如果像这样命名函数:
var operations = function() {
  var aVar;
  aVar.func = function() { alert('ronk'); };
  aVar.mem = 5;
};
operations();

operations操作是否必须一直存在,直到超出范围?还是解释器可以立即判断它不再需要?

更好的例子

我还想澄清的是,我并不一定在谈论全局范围。考虑一个类似下面代码块的区域:

(function() {

  var date = new Date(); // I want to keep this around indefinitely

  // And even thought date is private, it will be accessible via this HTML node
  // to other scripts.
  document.getElementById('someNode').date = date;

  // This function is private
  function someFunction() {
    var someFuncMember;
  }

  // I can still call this because I named it. someFunction remains available.
  // It has a someFuncMember that is instantiated whenever someFunction is
  // called, but then goes out of scope and is deleted. 
  someFunction();

  // This function is anonymous, and its members should go out of scope and be
  // deleted
  (function() {
    var member;
  })(); // member is immediately deleted
  // ...and the function is also deleted, right? Because I never assigned it to a
  // variable. So for performance, this is preferrable to the someFunction
  // example as long as I don't need to call the code again.

})();

我的假设和结论是否正确?每当我不打算重用一个代码块时,我不仅应该将其封装在一个函数中,而且还应该将其封装在匿名函数中,这样函数就没有引用并且在调用后被删除,对吗?


只是好奇,是否考虑了内存泄漏问题? - jebberwocky
2个回答

4
你说得对,将变量放在匿名函数中是一个很好的实践方法,可以避免全局对象混乱。
回答你后两个问题:只要有一个全局可见的引用,解释器就无法知道对象不会再次被使用。对于解释器来说,你随时都可能评估一些依赖于window['aVar']或window['operation']的代码。
基本上,记住两件事情:
1. 只要一个对象存在,它的所有插槽就不会在没有你的许可下自动释放。 2. 在全局上下文中声明的变量是全局对象(在客户端JavaScript中是window)的插槽。
综合起来,这意味着全局变量中的对象在脚本的生命周期内都存在(除非重新分配变量)。这就是我们声明匿名函数的原因——变量得到一个新的上下文对象,该对象在函数执行完毕后消失。除了效率的提升外,它还减少了名称冲突的机会。
不过,你第二个例子(内部匿名函数)可能有点过度热衷。我不会担心在那里“帮助垃圾收集器”——GC可能根本不会在函数中间运行。担心那些会持久保留的东西,而不仅仅是比原来稍微长一点的东西。这些自执行的匿名函数基本上是代码模块,它们自然地属于一起,因此一个好的指南是思考你正在做什么是否描述了这个。
不过,在匿名函数内部使用匿名函数也有其原因。例如,在这种情况下:
(function () {
  var bfa = new Array(24 * 1024*1024);
  var calculation = calculationFor(bfa);
  $('.resultShowButton').click( function () {
    var text = "Result is " + eval(calculation);
    alert(text);
  } );
})();

这会导致巨大的数组被点击回调函数所捕获,从而使其永远不会消失。你可以通过将该数组隔离在其自己的函数内来避免这种情况。

我理解并同意使用这种方式来避免全局命名空间的混乱。我认为我的原始示例没有充分展示我的问题范围。我修改了我的问题,以包括一个更好的示例。 - Justin Force
不要只关注那些稍微比其他东西存留时间长一点的事情,要关注那些会持续存在的问题。 这正是我一直在寻找的!感谢你的帮助! - Justin Force

1

任何添加到全局作用域的内容都会一直保留,直到页面卸载(除非您明确删除它)。

通常最好将属于同一组的变量和函数放在本地作用域或对象中,以便尽可能少地向全局命名空间添加内容。这样,您可以将不同的脚本组合在一个页面中,而最小化命名冲突的风险,从而更容易重用代码。


好的,我同意。我的问题更多地是关于是否将代码块粘贴到匿名函数中以最小化其范围是否好。一个例子可能是一个我一直保留的对象,也许通过将其分配为HTML节点的成员,但其中的一个单独块只能完成它的任务,然后被删除。我想我的问题更多地涉及垃圾收集的具体细节,以及我应该让这些细节如何影响我的编程风格。 - Justin Force

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接