【问题标题】:WeakMap polyfill throwing error when trying to define property on inextensible object尝试在不可扩展对象上定义属性时,WeakMap polyfill 抛出错误
【发布时间】:2016-02-02 06:28:42
【问题描述】:

WeakMap polyfill 在尝试定义不可扩展对象的属性时抛出错误。 这些位于一堆节点、javascript代码和库的中间,所以我实际上无法指出导致问题的原因。还有许多其他库也有自己的 polyfill。很难调试哪个库导致错误。而且,错误仅在 IE10 上。
为了摆脱它,我在定义一个属性之前添加了一个检查器(上面文件中的第 26 行):

if (entry && entry[0] === key) {
    entry[1] = value;
}
else if (Object.isExtensible(key)) {
    defineProperty(key, this.name, {
        value: [ key, value ],
        writable: true
    }); 
}

我的问题是,像上面的代码那样修复它是否安全/正确?如果没有,我应该如何解决我的问题?

【问题讨论】:

  • 什么类型的对象在 IE10 中给您带来了问题?也许有一种解决方法可以解决该类型对象的可扩展性。
  • 这很难知道。 1 个系统中有许多包,每个包都有不同的 polyfill。它们可能相互重叠。

标签: javascript mutation-observers


【解决方案1】:

据我所知,weakMap polyfill 仅设计用于使用可扩展对象作为键。它根本不适用于不可扩展的对象。

您的修改已完成,因此它不会引发异常,但不可扩展项也不会出现在 weakMap 中。所以,你的修复并不是真正的修复。必须重写该特定的 polyfill 以处理不可扩展的键。这不是一个简单的解决方案,因为它需要一种概念上不同的方法。

还有许多其他 polyfill 采用不同的方法。我还没有研究在这方面哪些可能更好。我怀疑实际上是“弱”(例如允许垃圾收集)与可以处理不可扩展的对象之间存在一些难题。根本的问题是,如果你要变弱,那么你就不能存储对对象本身的引用。因此,您需要存储对对象的某些字符串表示形式的引用。好吧,JS 对象没有内置的保证唯一字符串表示。因此,通常的解决方法是使用某种计数器创建一个并将其作为属性存储在对象上,然后将该字符串表示形式存储在地图中。但是,如果对象不可扩展,那么您也不能这样做。所以,你被困在你的地图中存储实际的对象引用,但它不再是真正的“弱”了。你可以看到你是如何被卡住的。

我认为这是一种 polyfill 不能完全满足真实情况的情况。不同的 polyfill 在这方面会有不同的权衡。您选择了一个确实很弱,但要求对象是可扩展的,以便可以添加属性。

【讨论】:

  • @CygnusKnight - 这回答了你的问题吗?如果是这样,请通过单击答案左侧的绿色复选标记向社区表明这一点。如果没有,请说明您仍需要帮助的地方。
【解决方案2】:

在我的问题中,我想要一个不会对其他功能或插件产生巨大影响的解决方案,所以这是我对这个问题的修复。该修复基于上述@jfriend00 的答案以及互联网上其他实现的参考。

var defineProperty = Object.defineProperty;
var counter = Date.now() % 1e9;
var FrozenStore = function() {
    this.a = [];
};
var findFrozen = function(store, key){
    return store.a.forEach(function(it){
        if (it[0] === key) {
            return it;
        }
    });
};
var findIndexFrozen = function(store, key){
    return store.a.forEach(function(it, id){
        if (it[0] === key) {
            return id;
        }
    });
};
FrozenStore.prototype = {
    get: function(key){
        var entry = findFrozen(this, key);
        if (entry) return entry[1];
    },
    has: function(key){
        return !!findFrozen(this, key);
    },
    set: function(key, value){
        var entry = findFrozen(this, key);
        if (entry) entry[1] = value;
        else this.a.push([key, value]);
    },
    "delete": function(key){
        var index = findIndexFrozen(this, key);
        if (~index) this.a.splice(index, 1);
        return !!~index;
    }
};
var WeakMap = function() {
    this.name = "__st" + (Math.random() * 1e9 >>> 0) + (counter++ + "__");
};
var frozenStore = function(that){
    return that._l || (that._l = new FrozenStore);
};
WeakMap.prototype = {
    set: function(key, value) {
        var entry = key[this.name];
        if (entry && entry[0] === key) {
            entry[1] = value;
        } else {
            if (!Object.isExtensible(key)) {
                frozenStore(this).set(key, value);
            } else {
                defineProperty(key, this.name, {
                    value: [ key, value ],
                    writable: true
                });
            }
        }
        return this;
    },
    get: function(key) {
        var entry;
        if ((entry = key[this.name]) && entry[0] === key) {
            return entry[1];
        } else if (!Object.isExtensible(key)) {
            frozenStore(this).get(key);
        } else {
            return undefined;
        }
    },
    "delete": function(key) {
        var entry = key[this.name];
        if (!entry || entry[0] !== key) return false;
        if (!Object.isExtensible(key)) frozenStore(this)['delete'](key);
        entry[0] = entry[1] = undefined;
        return true;
    },
    has: function(key) {
        var entry = key[this.name];
        if (!entry) return false;
        if(!Object.isExtensible(key)) return frozenStore(this).has(key);
        return entry[0] === key;
    }
};
window.WeakMap = WeakMap;

这引入了 FrozenStore,它将管理所有添加到 WeakMap 的不可扩展键。我不确定它是否打破了 WeakMap 的概念,但它确实让我摆脱了这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-06
    • 2011-07-30
    相关资源
    最近更新 更多