2012-08-10 37 views
3

这是一个棘手的问题,让我挠了脑袋几天。用JavaScript清除窗口对象中的自定义变量

我正在研究一个项目,该项目涉及到一个十年的Web应用程序并将其作为单页应用程序重新处理。应用程序非常庞大 - 我们必须工作的时间非常紧密,因此必须制定一些捷径。

然而,总体来说,我们对我们来到的距离印象深刻,因为我们必须克服一些有趣的技术障碍。

一个涉及清除所有自定义窗口变量。由于我们正在动态地重新加载应用程序的不同页面,因此我们需要清除所有自定义变量,以免发生冲突。我们所做的首先是加载应用程序的基本引导程序,并将窗口对象中的所有属性保存在一个数组中。然后,在加载每个新页面之前,我们循环浏览窗口属性并清除所有不在我们保存的数组中的对象(将窗口状态返回到加载页面之前)。

现在,在我们测试过的所有浏览器中,除了IE7和IE8(这两者都需要支持)以外,这样的工作正常。问题似乎是全局变量似乎并不总是在窗口对象上注册。

有没有人对这个问题有所了解?任何想法如何解决这个IE7?

任何信息将不胜感激。

编辑: 在引导装入我们这样做:

for (i in window) { 
    this.globalVars[i] = 1; 
} 

然后当我们加载一个新的页面(通过AJAX),我们这样做:

for (i in window) { 
    if (!this.globalVars[i]){ 
     window[i] = undefined; 
    } 
} 

最终的解决方案:

最后,由于时间有限,最简单的修复方法是简单地将所有变量定义为var x;到var x = null;

然而,我发现了另一种解决方案。这里有一个小型图书馆,我用它作为替代解决方案的起点:http://www.thomasfrank.se/global_namespace.html

这并不完美(可能需要进行一些调整以使其更稳定一些,例如在AJAX调用中添加try-catch块例如,以便跨域脚本不会崩溃)。它的工作方式是对所有外部脚本文件和内部脚本进行分析,提取大量单词,然后可以使用这些单词清除窗口对象的属性。

我们实际上经历了一些非常奇怪的事情 - 这个脚本没有正确地提取很多变量......事实证明,它使用document.scripts来获取页面上所有加载的脚本,以便能够循环通过他们并解析它们。问题是jQuery不会以这种方式在页面上加载外部页面。它所做的只是将代码从我知道的传递给exec。因此,没有脚本标记实际上被添加到页面中。

解决方法是解析原始AJAX响应并存储对所有脚本标记的引用(以及我想提取内联脚本),然后修改该库以便能够处理这些文件。这应该有效,但所有这些处理过程都因为速度原因而太可怕 - 发现我们可以简单地在所有变量定义上进行搜索&替换,并且大部分工作无需每个页面加载的大量工作显然我们应该采取哪条道路。

+0

为“清除”自定义变量的任何示例代码? – 2012-08-10 05:53:57

+0

窗口对象的哪些属性在这里似乎是问题?你确认他们在循环浏览窗口对象时显示了吗?我的第一个想法是,已知的问题循环使用'x in something',也许你遇到了这个问题。 – WTK 2012-08-10 13:20:36

+0

这些问题不是主要与循环数组相关的问题,而不是与对象相关的问题?无论如何,问题在于IE7似乎并没有在窗口对象上添加所有全局变量作为属性,所以它不会像循环一样出现。但是,如果您尝试直接访问它,则可以访问它。 – NRaf 2012-08-11 03:09:57

回答

3

据我所知,如果你想这是一个“快速”的解决方案,确保所有全局变量的100%被重置,并且这与oldIE兼容,你基本上必须保存您修改的窗口/文档属性的初始值......以及为特定页面上的每个全局手写空值。

如果你希望它是100%准确的,完全不用重构任何形式的......这就是我在未来所预见的。

贵公司听起来像几个我知道(我敢肯定,每个人都知道几) -
“奇迹可以在任何时间发生的没有钱,如果我们告诉开发者,使他们发生”如果涉及到它,我会通过手工挑选并修复全局var问题(或者编写一个解析器来查找页面上的全局范围变量 - 或者至少指向它们可能在的位置) 。 该框架的其余部分可能会被黑客攻击......尽管如此,如果可能的话,我还是希望能找到沙盒页面(会让整个状态变得毫无意义,对于初学者来说,一旦没有全局变量)。

但是......任一空的每一页的全局手工,或修复它们,用手将它们应用或者作为window[key](在绝对必要的),或作为formerly_global_properties[key]或在完全不同的范围内,封闭在一个功能。所有这些都是向后兼容的,并且都将会非常糟糕。

但是黑客攻击这样的解决办法和黑客的全局弄成可行的,然后可以用/维持工作在以后的日子都将是大致相同的工作数量,对不对?

+0

这是我们经历并实施的解决方案(定义为空)。实际上,这只是数量有限的页面,而且效果不佳。 – NRaf 2012-08-16 23:25:01

4

退房这个问题:JavaScript: List global variables in IE

在IE浏览器,它的全局变量是不可枚举的,除非你明确地将它们定义为window对象的属性。

所以,如果你正在分配这样的变量:

var number = 42; // not inside any function 

它不会显示出来,当你通过迭代window。你必须定义所有的全局变量是这样的:

window.number = 42; 

或者这样:

this.number = 42; 
+0

xD,+1似乎我们在同一时间写作:D – gaspyr 2012-08-12 22:47:20

+0

是的,我知道这一点。我所希望的是一种解决方案,无需更改应用程序中的每个全局变量声明(这可能导致错误,难以测试并且非常耗时)。 – NRaf 2012-08-13 00:38:42

+0

@NRaf我认为情况会如此。我想知道你是否可以重新加载所有的js ...我根本不是那个想法的粉丝,但它可能是解决问题的唯一方法。 – lbstr 2012-08-13 00:47:11

1

你检查如果循环过程中不显示这些属性设置为不可枚举。因为如果一个对象的属性不是可枚举的,那么它在循环过程中不会“显示”。你可以用下面的方法“propertyIsEnumerable”来检查它。

例如:

var o = {x:1, y:2, z:3}; // Three enumerable own properties 
o.propertyIsEnumerable("toString") // => false: not enumerable 

作为附带说明:

据的ECMAScript 5 for/in循环一次为每个 枚举属性运行循环体(自身或继承)的指定对象,将该属性的名称分配给循环变量。对象继承的内置方法不是 可枚举,但是您的代码添加到对象的属性是可枚举的(除非 您使它们不可枚举)。

0

,如果你包裹在什么封闭的旧脚本并保存/导出,你需要坚持的变量?

1

我会建议使用删除,一个鲜为人知的JS功能正常摆脱全局变量,例如

delete window.varname; 

OR

delete window["varname"]; 

设置为未定义的变量是相当于(以全球范围)

var varname; 

这可能不是你想要的。

+0

在ie8中不起作用。实际上抛出异常... – Ajax 2014-10-10 18:40:48

0
clone(obj) { 
     var _ = this, 
      copy; 
     if (null == obj || "object" != typeof obj) return obj; 
     if (obj instanceof Date) { 
      copy = new Date(); 
      copy.setTime(obj.getTime()); 
      return copy; 
     } 
     if (obj instanceof Array) { 
      copy = []; 
      for (var i = 0, len = obj.length; i < len; i++) { 
       copy[i] = _.clone(obj[i]); 
      } 
      return copy; 
     } 
     if (obj instanceof Object) { 
      copy = {}; 
      for (var attr in obj) { 
       if (obj.hasOwnProperty(attr)) copy[attr] = _.clone(true); 
      } 
      return copy; 
     } 
     throw new Error("Unable to copy obj"); 
    } 

    windowGarbageCollection(){ 
     var removeObjects = Object 
      .keys(window) 
      .map((currentValue) => { 
       if(!window.window_cache[currentValue]){ 
        if(currentValue != 'window_cache' && currentValue != '0'){ 
         window[currentValue] = false; 
        } 
       } 
      }); 
    } 

    // run this at the moment you want to grab the initial variables 
    // probably at the very beginning 
    window.window_cache = clone(window); 

首先创建初始window变量(你不需要整个窗口对象)的快照,并将其存储在window.window_cache

然后每次你在你的应用程序切换页面时,运行windowGarbageCollection(),这会比较window.window_cache当前的window,把事情以后添加到false

你会想在开始新的页面呈现之前运行的垃圾收集,这样,当它呈现的任何新变量将不会删除。