在IE中删除窗口属性

70

我找不到关于这个问题的任何信息;为什么以下代码在IE中无法工作?

window.x = 45;
delete window.x;
// or delete window['x'];

IE报告了一个"对象不支持此操作"的错误。这与在IE中迭代窗口属性有关吗?


30
为了明确一点,因为似乎没有人在任何回答中实际上说过这个:这是Internet Explorer中的一个错误。即使属性不存在或不可删除(您的window.x在任何情况下都不应该是这种情况),1999年(第三版)规范中也没有允许从delete抛出异常,并且新的第五版规范仅允许在新的严格模式下从delete抛出异常。在这方面,window没有任何特殊之处。然而,在2010年,IE8中的JScript引擎仍然表现出这个bug。叹气 - T.J. Crowder
3
优秀的相关文章:http://perfectionkills.com/understanding-delete/。 - alex
T.J.克劳德,window不是一个对象,它是根命名空间的访问器。它没有属性,因此当您对其运行删除操作时(例如在此情况下),没有任何理由强制实际删除它们。在对象名称上设置未定义是可以的,因为gc将通过并消除未引用的对象。希望这有助于了解实际问题以及为什么这不是一个错误,而是一种正在缓慢更新以现代化的语言的差劲实现选择。 - Jeffrey Gilbert
4个回答

49

Gasper在他完成的解决方案中发表了评论,但我认为这值得单独作为一个实际答案提出:

try { 
    delete window.x; 
} catch(e) { 
    window["x"] = undefined; 
}

这是一个有趣的问题,今晚我也在为它挠头。该异常在IE上抛出,但在Firefox上却没有。我怀疑这个解决方法会导致内存泄漏,所以请谨慎使用。

有人问道,为什么不只是赋值为undefined?如果你想稍后枚举键(尽管如果你依赖此解决方法,键的枚举仍然无法做到你想要的...)。但无论如何,为了突显delete和仅仅赋值为undefined之间的区别 (http://jsfiddle.net/fschwiet/T4akL/):

var deleted = {
    a: 1
};

var cleared = {
    a: 1
};

delete deleted["a"];
cleared["a"] = undefined;

for(var key in deleted) {
    console.log("deleted has key", key);
}

for(var key in cleared) {
    console.log("cleared has key", key);
}

console.log("deleted has a?", deleted.hasOwnProperty('a'));
console.log("cleared has a?", cleared.hasOwnProperty('a'));

产生输出:

cleared has key a
deleted has a? false
cleared has a? true 

4
当我向同事展示这个解决方案时,有位同事提出了一个好问题:为什么不跳过中间步骤,用未定义的赋值取代删除调用? - Seth Battin
好问题,我花了一年时间才遇到一个情况,其中差异很重要。 - Frank Schwieterman

38

我会这样做:

    window[x] = undefined;
    try{
        delete window[x];
    }catch(e){}

谢谢,最后我就是这么做的。在IE浏览器中会抛出一个异常,但是被捕获了,没有造成任何损害。 - gasper_k
1
我看过的最详细的delete解释在这里,这是IE部分。(以防将来有人遇到更复杂的问题)http://perfectionkills.com/understanding-delete/#ie_bugs - Patrick McGuire

2

这有帮助吗?

window.x = 45;
alert(window.x);
window.x = null;

我在IE浏览器中尝试过这个方法,window.x确实有一个值,证明它可以被设置。将该值设置为null是清除其内容的最佳方法。


不幸的是,这并不能从内存中删除变量,它只是赋了一个空值,但据我所知,这是唯一的选择。 - Andy E
1
谢谢。我已经更进一步,使用了window.x = undefined。虽然这还不是我想要的,但它可以。奇怪的是,我在网上没有找到任何有用的信息。 - gasper_k

1

在处理自己的数据缓存时,我采用了这种解决方案——数据量不大,但缓存频率很高,可能会导致内存泄漏问题。这种方法成本较高,但定期重新映射对象是我确保它不会失控的最简单方式。

obj = {a: 1, b: 2, c: 3};
var max;

function unset(obj, key) {
    try {
        delete obj[key];
    } catch (e) {
        obj[key] = undefined;
    }

    max++;

    if(max > 200) {
        var keys = Object.keys(obj);
        var len = keys.length;
        var n_obj = {};
        for(var i = 0; i < len; i++) {
            if(obj.hasOwnProperty(keys[i]) && obj[keys[i]] !== undefined) {
                n_obj[keys[i]] = obj[keys[i]];
            }
        }
        return n_obj;
    }
    return obj;
}

obj; //{a: 1, b: 2, c: 3}
obj = unset(obj, "b"); //{a: 1, b: undefined, c: 3} OR {a: 1, c: 3}
//and then eventually we'll garbage collect and...
obj = unset(obj, "b"); //{a: 1, c: 3}   

希望对某些人有用!


2
Object.keys()在<= IE8中无法工作(这些是首先导致delete出问题的原因)。此外,您可能意味着在catch块内部使用obj[key] = undefined。;] - WynandB
那就是它!修订版。 - Mikebert4

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