3

What I want to do

I'd like to write a function that is able to deal with two different argument types as its first parameter.

To be more specific, the function shall be able to deal with the first argument either being NodeList or Element.

My research

I was researching a bit on how to detect the type of a variable, since I'm not using libraries like jQuery or underscore and came across a variety of resources. Those were the best:

I didn't expect that this particular corner of JavaScript is this flawed. The resources above list ways of doing this with typeof, instanceof etc.

But none of the resources I've found included isPrototypeOf as a viable option.

The question

I found NodeList.prototype.isPrototypeOf(myParam) and Element.prototype.isPrototypeOf(myParam) to work quite well. Since none of the resources I've found discusses the usage of isPrototypeOf, I'm wondering:

Are there any caveats using isPrototypeOf to check a variable for a specific type?

Community
  • 1
  • 1
rmoestl
  • 3,059
  • 5
  • 24
  • 38
  • I found it difficult to find to find browser support (namely which version of IE it became available). That would be something to consider. If it were the case it's not supported on all your target browers, you could use the `Object.prototype.toString.call()` trick to get the internal `[[class]]` which you could compare to a whitelist. – alex Jun 06 '16 at 09:46
  • why not using `instanceof`? – floribon Jun 06 '16 at 09:47
  • @floribon see the first answer and the links I've posted. E.g. you're not able to use `instanceof` when the object has not been created with a constructor function (e.g. `Object.create`). – rmoestl Jun 06 '16 at 10:29
  • @alex according to [MDN](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf#Browser_compatibility) it's supported everywhere. In my experience MDN is a quite good resource for browser compatibility. – rmoestl Jun 06 '16 at 10:30
  • 1
    @rmoestl Saying "yes" for IE isn't as great as support breakdown for IE 9, 10, 11 etc. – alex Jun 06 '16 at 10:47

2 Answers2

1

My guess there are no any caveats with using isPrototypeOf. However you aren't always able to use isinstanceof. If you have no constructor function and use Object.create you cannot use isinstanceof to check whether object belongs to prototype. However you would always be able to use isPrototypeOf to check it.

var proto = {
    // some properties
}
var o = Object.create(proto);
console.log(proto.isPrototypeOf(o));
// true
console.log(o instanceof proto);   
// TypeError
Andriy Ivaneyko
  • 20,639
  • 6
  • 60
  • 82
  • So one conclusion regarding the caveats is that OP's function could be called with `Object.create(NodeList)` and be considered as a NodeList instance, whereas `instanceof` wouldn't allow that: `NodeList.isPrototypeOf(Object.create(NodeList)) // true` vs `Object.create(NodeList) instanceof NodeList // false` – floribon Jun 06 '16 at 14:23
0

A caveat is you can't use isPrototypeOf on primitive values (numbers, strings, booleans) because they aren't objects. Primitives MDN

console.log(String.prototype.isPrototypeOf('I am string')); // false
console.log(Number.prototype.isPrototypeOf(1)); // false
console.log(Boolean.prototype.isPrototypeOf(true)); // false

Another caveat is many things are prototypes of an Object, like Arrays, Functions, Regular Expressions, Dates, even Elements

console.log(Object.prototype.isPrototypeOf([])); // true
console.log(Object.prototype.isPrototypeOf(function(){})); // true
console.log(Object.prototype.isPrototypeOf(/test/i)); // true
console.log(Object.prototype.isPrototypeOf(new Date())); // true
console.log(Object.prototype.isPrototypeOf(document.querySelector('body'))); // true

Todd Motto has a nice solution for reliable type checking Primitives and Global Objects.

function type(obj) {
  return Object.prototype.toString.call(obj).slice(8, -1);
}

However, this doesn't work if checking that a value is an Element or NodeList. For that isPrototypeOf works well.

Dan0
  • 107
  • 1
  • 12