0

我试图围绕 Javascript、临时变量和 GC 中的私有变量。但是,我不太清楚在以下情况下会发生什么:

MyClass = function() {
   this.myProp = new createjs.Shape();

   var tempVar = this.myProp.graphics;
   tempVar.rect(0, 0, 10, 100);
   tempVar = null;

   var isDisposed = false;
   this.dispose = function() {
      if (isDisposed) return;
      isDisposed = true;
   }
}
var anInstance = new myClass();

我的意图是让isDisposed代表一个私有状态变量,而tempVar是一个使用和抛出变量。

tempVar被标记为 GC 吗?isDisposed也会被标记为 GC 吗?GC 如何知道我何时试图声明一个用于处置的临时变量,以及何时我试图在对象中拥有一个私有变量?

我尝试在 Chrome 中测试以下内容,只要 myClass 的实例存在,似乎tempVar 就永远不会被 GC-ed。所以我不确定现在该相信什么。我不相信我为临时使用而创建的每个局部变量都将存在于对象生命周期的范围内。

4

1 回答 1

3

Javascript 没有强类型对象。通过设置tempVar为 null,您并没有声明您不想再使用它或将其标记为在 Java 或 C# 中进行收集,您只是为其分配了一个(完全有效的)值。开始认为仅仅因为您将 tempVar 作为对象的“实例”,变量实际上是一个对象并且可以在其整个生命周期中被视为对象,这是一个陷阱。

基本上,变量只是 Javascript 中的变量。它们可以包含任何东西。在这方面,它就像 VB 或 VBScript。在许多情况下,标量确实会进行装箱(例如'a|c'.split('|')将字符串转换为字符串),但在大多数情况下,忘记这一点。函数是一等对象,这意味着您可以将它们分配给变量、从函数返回它们、将它们作为参数传递等等。

现在,要真正销毁 Javascript 中的某些内容,您可以删除对它的所有引用(如在对象的情况下),或者在对象的属性的情况下,您可以像这样删除它们:

delete obj.propertyname;
// or //
delete obj[varContainingPropertyName];

为了扩展这一点,以下两个代码片段实现了相同的结果:

function abc() {window.alert('blah');}
var abc = function() {window.alert('blah');}

两者都创建了一个名为的局部变量abc,该变量恰好是一个函数。第一个可以被认为是第二个的捷径。

但是,根据您引起我注意的这篇关于删除的优秀文章,您不能删除局部变量(包括函数,它们实际上也是局部变量)。有例外(如果变量是使用创建的eval,或者它在全局范围内并且您没有使用 IE <= 8,或者您正在使用 IE <= 8 并且变量是在全局范围内隐式创建的,因为在x = 1技术上一个巨大的错误),因此请阅读文章以获取有关 的完整详细信息delete

另一个可能对您有用的关键是要知道在 Javascript 中只有函数具有作用域(以及window浏览器实现或其他实现中的任何全局作用域)。包含在其中的非函数对象和代码块{ }没有作用域(我这样说是因为Functionis的原型Object,所以函数也是对象,但是是特殊的)。这意味着,例如,考虑以下代码:

function doSomething(x) {
   if (x > 0) {
      var y = 1;
   }
   return y;
 }

这将1在执行时返回,x > 0因为变量 y 的范围是函数,而不是。所以实际上将var声明放在块中是错误和误导的,因为它实际上(尽管可能不是真正的实践)提升到函数范围。

您应该阅读 javascript 中的闭包(我不能保证该链接的质量)。这样做可能会有所帮助。任何时候只要在任何地方维护一个变量的函数范围,那么该函数的所有私有变量也是如此。您可以做的最好的事情是将它们设置为undefined(这比 Javascript 中的“null”更“无”)将释放它们拥有的任何对象引用,但不会真正释放变量以使其可用于 GC。

至于一般的 GC 陷阱,请注意,如果一个函数对 DOM 元素有一个闭包,并且某个 DOM 元素也引用了该函数,那么在卸载页面或破坏循环引用之前,两者都不会被 GC。在某些——或所有?——版本的 IE 中,这样的循环引用会导致内存泄漏,并且在浏览器关闭之前它永远不会被 GC。

要尝试更直接地回答您的问题:

  • tempVar在它所属的函数的所有引用释放之前不会被标记为 GC,因为它是一个局部变量,并且无法删除 Javascript 中的局部变量。
  • isDisposed具有与 相同的品质tempVar
  • “用于处置的临时变量”在 Javascript 中没有区别。在较新版本的 ECMAScript 中,有可用的实际 getter 和 setter 来定义函数的公共(或私有?)属性。
  • 正如有关使用 Firefox 删除的文章中所讨论的,浏览器的控制台可能会为您提供误导性结果。
  • 确实,尽管可能令人难以置信,在 Javascript 中,只要变量存在于闭包中,该变量就会保持实例化。这通常不是问题,而且我还没有经历过浏览器由于未收集垃圾的微小变量而真正耗尽内存。完成后设置一个变量undefined,并放心-我真诚地怀疑您是否会遇到问题。如果您担心,则声明一个本地对象var tmpObj = {tempVar: 'something'};,完成后您可以发出delete tmpObj.tempVar;. 但在我看来,这将不必要地使您的代码混乱。

基本上,我的建议是理解在来自其他编程语言的过程中,你对编程语言应该如何做有先入为主的观念去工作。就理想的编程语言而言,其中一些概念可能是有效的。但是,最好放弃这些概念,并至少现在接受 Javascript 的实际工作方式。除非您真正有足够的经验,可以自信地违反前人(例如我)的建议,否则您在 Javascript 代码中引入有害反模式的风险要比纠正任何严重缺陷的风险更大在语言中。不必 Dispose() 东西可能是个好消息——这是 Javascript 根本不需要你做的这个令人讨厌的普遍任务,所以你可以花更多的时间编写功能和更少的时间管理变量的生命周期。赢!

I hope you take my words as kindly as they are meant. I don't by any means consider myself a Javascript expert--just that I have some experience and a solid competence in understanding how to use it and what the pitfalls are.

Thanks for listening!

于 2012-11-30T06:34:42.947 回答