清除 Javascript 中窗口对象中的自定义变量

Clearing custom variables in the window object in Javascript

本文关键字:自定义 变量 窗口 Javascript 清除 对象      更新时间:2023-09-26

这是一个棘手的问题,让我挠头几天了。

我正在从事一个项目,该项目涉及将一个十年前的 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 响应并存储对所有脚本标记的引用(以及,我想,提取内联脚本),然后修改库以便能够处理这些文件。这应该有效,但由于速度原因,所有这些处理都太可怕了 - 发现我们可以简单地对所有变量定义进行搜索和替换,并且不需要为每个页面加载进行大量工作,这使得我们应该采取哪条路径变得显而易见。

看看这个问题:JavaScript:列出IE中的全局变量

在 IE 中,全局变量不可枚举,除非将它们显式定义为窗口对象的属性。

因此,如果您要分配这样的变量:

var number = 42; // not inside any function

当您循环访问window时,它不会显示。您必须像这样定义所有全局变量:

window.number = 42; 

或者像这样:

this.number = 42; 

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

如果您希望它 100% 准确,完全 BC 与旧 IE... 并且没有任何形式的重构...这就是我对你未来的预见。

你的公司听起来像是我知道的几个(我相信每个人都知道一些)——
"奇迹可以在没有钱的情况下立即发生,如果我们告诉开发人员让它们发生。

如果归根结底,我会手动选择并修复全局变量问题(或者编写一个解析器来查找页面上的全局范围的变量 - 或者至少指向它们可能的位置)。框架的其余部分可以一起被黑客入侵...不过,如果可能的话,我最终仍然想对页面进行沙盒处理(对于初学者来说,一旦没有全局变量,整个状态的事情就会变得毫无意义)。

但是...手动将每个页面的全局变量定空,或者手动修复它们以将它们作为window[key]应用(如果绝对必要),或者作为formerly_global_properties[key]或包含在函数中的完全不同的范围内应用。所有这些都将是向后兼容的,所有这些都将是不可估量的糟糕。

但是像这样破解解决方法并将全局变量破解为可行的东西,然后可以在以后使用/维护,两者都将是大致相同的工作量,对吧?

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

delete window.varname;

delete window["varname"];

将变量设置为 undefined 等效于(在全局范围内)

var varname;

这可能不是你想要的。

您是否检查过循环期间未显示的那些属性是否配置为不可枚举。因为如果对象的属性不可枚举,那么它就不会在循环期间"显示"。您可以使用以下方法"属性是可枚举的"进行检查。

例:

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

作为旁注:

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

如果您将旧脚本包装在闭包中并保存/导出需要保留的变量会怎样?

    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

您希望在呈现新

页面之前在开始时运行垃圾回收,以便在呈现时不会删除任何新变量。