【问题标题】:Object.getPrototypeOf fail to __proto__ fail to object.constructor.prototype shimsObject.getPrototypeOf 失败到 __proto__ 失败到 object.constructor.prototype 垫片
【发布时间】:2013-05-29 23:17:20
【问题描述】:

我一直在浏览一些 shim/polyfill 库,发现其中一些有一个用于 Object.getPrototypeOf 的 shim。如果不存在,他们会使用__proto__,如果不存在则使用object.constructor.prototype

我知道__proto__ 是“非标准”的,虽然与Object.getPrototypeOf 方法略有不同,但它们可以互换。

我也明白,原则上外部可访问的object.constructor.prototype 在其他两个都不存在的许多情况下就足够了(假设原型没有被重新分配)。

我遇到的问题是以下示例:

    function findPropertyOwner(object, property) {
        var count = 0;

        do {
            if (object.hasOwnProperty(property)) {
                return [object, count];
            }

            object = Object.getPrototypeOf(object);
            count += 1;
        } while (object);

        return undefined;
    }

或者

    function instanceOf(object, constructor) {
        while (object) {
            if (object === constructor.prototype) {
                return true;
            }

            object = Object.getPrototypeOf(object);
        }

        return false;
    }

在上面的例子中,我们可以说是“走链”,如果垫片回落到object.constructor.prototype,那么我们现在就会陷入无限循环的可怕情况。

我的问题:有没有办法在Object.getPrototypeOf__proto__不存在的环境中实现上述代码?

我的感觉是没有,但我只是想检查一下,以防有一些我没有遇到过的信息。

【问题讨论】:

  • 我仍然不明白为什么人们不推荐使用__proto__。它可能已被弃用,但 AFAIK 目前处于 ES6 草案的规范部分。 people.mozilla.org/~jorendorff/es6-draft.html#sec-B.3.1
  • 最好的办法是保留遇到的原型对象列表,并检查列表中的循环引用。如果找到,请跳转至Object.prototype,或直接跳转至return false
  • 而这个:while (object !== undefined && object !== null) { ... 太长了。只需这样做:while (object != null) { ...它会同时测试nullundefined
  • 您能提供更多信息吗?也许在 jsfiddle...
  • @Fabrício Matté 我知道讨论了,我会将措辞更改为“非标准”,就像在 MDN 页面上一样。

标签: javascript inheritance constructor prototype es5-shim


【解决方案1】:

基于@squint 的 cmets,我将介绍我尝试过的解决方案。据我所知,我根据a blog by John Resig 重新设计了Object.getPrototypeOf 的通用垫片,这在图书馆中似乎很常见。

跨浏览器实现

现在显而易见的问题变成了:我们如何开始使用 Object.getPrototypeOf 今天如果大多数浏览器没有实现它 然而?与此同时,我们可以使用类似下面的代码 某种形式的兼容性:

if (typeof Object.getPrototypeOf !== "function") {
    if (typeof "test".__proto__ === "object") {
        Object.getPrototypeOf = function (object) {
            return object.__proto__;
        };
    } else {
        Object.getPrototypeOf = function (object) {
            // May break if the constructor has been tampered with
            return object.constructor.prototype;
        };
    }
}

虽然它不是 100% 正确的(因为 .constructor 属性是 在任何对象上都是可变的——它完全有可能是 由用户在某些时候操纵)上面的代码应该用作 一个“足够好”的解决方案,可以让您渡过难关,直到浏览器拥有良好的 ECMAScript 3.1 兼容性。

这就是我想出的

if (typeof Object.getPrototypeOf !== "function") {
    if (Object.prototype.__proto__ === null) {
        Object.getPrototypeOf = function getPrototypeOf(object) {
            return object[proto];
        };
    } else {
        Object.getPrototypeOf = function getPrototypeOf(object) {
            if (object === Object.prototype) {
                return null;
            }

            if (object === object.constructor.prototype) {
                return Object.prototype;
            }

            return object.constructor.prototype;
        };
    }
}

正如我在 cmets 中提到的,这解决了我在使用 John Resig 版本时遇到的循环原型链问题。

我确实遇到的问题(除了如果构造函数被篡改可能会破坏)是在我的测试期间我发现我在一个特定的测试中得到了错误的结果(可能有更多,但不是那个我还没有找到)。测试关注Error objects

实例

new TypeError() instanceof Error; // --> true

函数 instanceOf 与 ES5 Object.getPrototypeOf 或 _proto_

instanceOf(new TypeError(), Error); // --> true

function instanceOf with object.constructor.prototype fallthrough

instanceOf(new TypeError(), Error); // --> false

我所有的其他测试都给了我匹配的结果,但正如我所说,可能存在更多的不一致(构造函数没有被篡改)。这是我想出的最好的方法,但至少我不再有可能在类似于我的问题中给出的函数上出现无限循环。

这是一个jsfiddle,它演示了这个问题。 (在 Chromium v​​25、FireFox v20 和 Opera 12.14 上测试:它们都是我可用的)

【讨论】:

    猜你喜欢
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 2011-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多