尝试在不可扩展对象上定义属性时,弱映射填充项引发错误

WeakMap polyfill throwing error when trying to define property on inextensible object

本文关键字:映射 填充 错误 属性 可扩展 对象 定义      更新时间:2023-09-26

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
    }); 
}

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

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

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

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

我认为这是填充物无法完全达到真实情况的一种情况。 在这方面,不同的填充物将有不同的权衡。 你选择了一个真正弱的,但要求对象可扩展,以便可以添加属性。

就像我的问题一样,我想要一个对其他功能或插件没有巨大影响的解决方案,所以这是我对这个问题的修复。该修复基于上述@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的概念,但它确实将我从这个问题中解救出来。