Question

I have been looking through some shim/polyfill libraries and see that some of them have a shim for Object.getPrototypeOf. On fail to exist they fall through to using __proto__ and if that doesn't exist then to object.constructor.prototype.

I understand that __proto__ is "non-standard" and while slightly different to the Object.getPrototypeOf method, they can be pretty interchangeable.

I also understand that in principle the externally accessible object.constructor.prototype would suffice in many situations where neither of the other two existed (provided the prototype has not been reassigned).

Where I have a problem is with the following examples:

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

Or

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

            object = Object.getPrototypeOf(object);
        }

        return false;
    }

With such examples as above where we "walk the chain" so to speak, if the shim falls back to object.constructor.prototype then we now end up in the horrible situation of an infinite loop.

My question: Is there any way to achieve the above code in an environment where Object.getPrototypeOf and __proto__ do not exist?

My feeling is that there is not, but I just want to check in case there is some information out there that I have not come across.

Was it helpful?

Solution

Based on the comments by @squint I will present the solution that I tried. I reworked the general shim for Object.getPrototypeOf that seems to be common among the libraries, based on a blog by John Resig as far as I can tell.

Cross-Browser Implementation

The obvious question now becomes: How do we begin using Object.getPrototypeOf today if most browsers don’t have it implemented yet? In the meantime we can use something like the following code for some form of compatibility:

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

While it’s not 100% spot-on (since the .constructor property is mutable on any object – it’s fully possible that it could’ve been manipulated by the user at some point) the above code should serve as a “good enough” solution to tide you over until browsers have good ECMAScript 3.1 compatibility.

And this is what I came up with

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

As I mentioned in my comments, this solves the circular prototype chain problem that I experienced with the John Resig version.

The problem that I do have with it (other than it may break if the constructor has been tampered with) is that during my tests I found that I get false result on one particular test (there may be more, but not that I have yet found). The test/s concern the Error objects

instanceof

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

function instanceOf with ES5 Object.getPrototypeOf or _proto_

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

function instanceOf with object.constructor.prototype fallthrough

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

All my other testing gave me matching results, but as I said, there may be more inconsistencies out there (where the constructor has not been tampered with). This is the best that I have managed to come up with, but at least I no longer have the possibility of infinite loops on functions similar to those given in my question.

Here is a jsfiddle that demonstrates the problem. (tested on Chromium v25, FireFox v20 and Opera 12.14: they are all that I have available)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top