In this question I did not see suggestions to use constructor.
So instead of typeof callback == "function"
I would use callback && (callback.constructor==Function)
.
To me it seems obvious that comparison to memory pointers is always better than comparison to strings in terms of both runtime performance and coding safety.
Why not use constructor to detect all types and forget about ugly typeof
?
It works for all primitive types, functions and arrays:
undefined === undefined
null === null
[1,2,3].constructor == Array
(1).constructor == Number
(true).constructor == Boolean
(()=>null).constructor == Function
'abc'.constructor == String
(new Date()).constructor == Date
else it's an object, where instanceof helps to detect it's parents if needed.
If string interning can be relied upon then runtime performance advantage goes away. But safe coding advantage still stays.
typeof: Per the MDN docmentation, typeof is a unary operator that returns a string indicating the type of the unevaluated operand. instanceof: is a binary operator, accepting an object and a constructor. It returns a boolean indicating whether or not the object has the given constructor in its prototype chain.
Use the typeof operator to get the type of an object or variable in JavaScript. The typeof operator also returns the object type created with the "new" keyword. As you can see in the above example, the typeof operator returns different types for a literal string and a string object.
typeof null evaluates to 'object' , thus the correct way to use typeof to detect an object is typeof object === 'object' && object !== null .
JavaScript type checking is not as strict as other programming languages. Use the typeof operator for detecting types. There are two variants of the typeof operator syntax: typeof and typeof(expression) . The result of a typeof operator may be misleading at times.
instanceof
is better because it works with inherited constructors. .constructor
is a mutable property on an object, so it's not a good thing to check because one can simply change it. You can't change the instanceof
something.
const x = new Date();
console.log("Date Constructor", x.constructor);
x.constructor = "herpderpderp";
console.log("Date Constructor", x.constructor);
You can also define your own functions for both tests that also work on primitives by using getPrototypeOf and isPrototypeOf. E.G.:
function typeOf(obj) {
return Object.getPrototypeOf(obj).constructor;
}
typeOf(2) === Number // true
typeOf("cats") === String // true
class Foo {}
typeOf(new Foo()) === Foo // true
class Bar extends Foo {}
typeOf(new Bar()) === Bar // true
typeOf(new Bar()) === Foo // false
var b = new Number(3)
if (typeOf(b) === Number) {
console.log(b.valueOf() + 5)
}
and
function instanceOf(obj, type) {
var objType = typeOf(obj)
return (
// Allow native instanceof in case of Symbol.hasInstance
obj instanceof type ||
// Handle case where is of type type
typeOf(obj) === type ||
// Handle general case
type.isPrototypeOf(objType) ||
// Handle special case where type.prototype acts as a
// prototype of the object but its type isn't in the
// prototype chain of the obj's type
// OPTIONALLY remove this case if you don't want
// primitives to be considered instances of Object
type.prototype.isPrototypeOf(objType.prototype)
);
}
instanceOf(3, Number) // true
instanceOf(new Number("2"), Number) // true
instanceOf(2, Number) // true, OPTIONAL with the last condition
// but is probably preferable as 2 does
// indeed get all methods of Objects
class Hat {}
instanceOf(new Hat(), Hat) // true
class Fedora extends Hat {}
instanceOf(new Fedora(), Fedora) // true
instanceOf(new Fedora(), Hat) // true
instanceOf(new Fedora(), Object) // true
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With