admin管理员组

文章数量:1323714

function A(){}
A.prototype = "Foo bar";

new A() instanceof A;
// TypeError: Function has non-object prototype 'Foo bar' in instanceof check

As you can see, if the prototype of a constructor is not an object, it will fail and throw an error. Is there a way to make sure instanceof will not fail?

typeof new A().constructor.prototype === "object"

and

typeof Object.getPrototypeOf(new A()) === "object"

apparently do not work.

function A(){}
A.prototype = "Foo bar";

new A() instanceof A;
// TypeError: Function has non-object prototype 'Foo bar' in instanceof check

As you can see, if the prototype of a constructor is not an object, it will fail and throw an error. Is there a way to make sure instanceof will not fail?

typeof new A().constructor.prototype === "object"

and

typeof Object.getPrototypeOf(new A()) === "object"

apparently do not work.

Share Improve this question asked Apr 7, 2017 at 2:24 Derek 朕會功夫Derek 朕會功夫 94.4k45 gold badges197 silver badges253 bronze badges 8
  • 2 Maybe wrap it in try/catch? – Barmar Commented Apr 7, 2017 at 2:25
  • 1 How about typeof A.prototype === "object"? – Barmar Commented Apr 7, 2017 at 2:27
  • @Barmar How did I not think of that before? Thanks. – Derek 朕會功夫 Commented Apr 7, 2017 at 2:30
  • @Barmar Close, but typeof A.prototype == "object" && A.prototype != null || typeof A.prototype == "function" it is – Bergi Commented Apr 7, 2017 at 2:31
  • 1 why would you ever do A.prototype = "Foo bar"; in the first place – Jaromanda X Commented Apr 7, 2017 at 2:41
 |  Show 3 more ments

4 Answers 4

Reset to default 3

The error says A.prototype needs to be an object, so you should check for that:

function isObject(x) {
    return x != null && (typeof x == "object" || typeof x == "function");
}

but isObject(A.prototype) is not all you can do to assert an instanceof call won't throw. Going by the spec, you should test

function allowsInstanceCheck(C) {
    try {
        if (!isObject(C)) return false;
        var m = C[Symbol.hasInstance];
        if (m != null) return typeof m == "function";
        if (typeof C != "function") return false;
        return isObject(C.prototype);
    } catch (e) {
        // any of the property accesses threw
        return false;
    }
}

Use try/catch to catch the error;

function isItA(obj) {
  try {
    return obj instanceof A;
  } catch (e) {
    return false; //
  }
}

function A() {}
A.prototype = "Foo bar";
function B() {}
B.prototype = "Baz Quux";
console.log(isItA(new A()));
console.log(isItA(new B()));

Perhaps not really an answer, but an interesting conclusion.

When a function is called as a constructor, if its prototype property isn't an Object, then the new instance is assigned the intrinsicDefaultProto as its [[Prototpye]] as described in GetPrototypeFromConstructor.

In the process of creating a new instance, the intrinsicDefaultProto is passed the value of the fallbackProto, which seems to be (in Firefox at least), Object.prototype.

And since the constructor property of Object.prototype is Object, then testing whether the instance's constructor property references the candidate object won't work either.

function Foo(){}
Foo.prototype = 'A';
var foo = new Foo();

// foo inherits directly from Object.prototype, not Foo
console.log(Object.getPrototypeOf(foo) == Object.prototype) // true

// foo also inherits constructor property from Object.prototype
console.log(foo.constructor == Object)  // true

So a circumstance in which instanceof fails likely points to more serious issues in the program design or implementation. Hiding such errors seems to not be a good idea (unless the intention is to leave traps within the code for future maintainers to discover).

I use: typeof o.prototype === "function" && o instanceof f

本文标签: javascriptCheck if quotinstanceofquot is going to failStack Overflow