Differencebetween Typeof and Instanceof and When Should One Be Used VS. the Other

What is the difference between typeof and instanceof and when should one be used vs. the other?

Use instanceof for custom types:

var ClassFirst = function () {};
var ClassSecond = function () {};
var instance = new ClassFirst();
typeof instance; // object
typeof instance == 'ClassFirst'; // false
instance instanceof Object; // true
instance instanceof ClassFirst; // true
instance instanceof ClassSecond; // false

Use typeof for simple built in types:

'example string' instanceof String; // false
typeof 'example string' == 'string'; // true

'example string' instanceof Object; // false
typeof 'example string' == 'object'; // false

true instanceof Boolean; // false
typeof true == 'boolean'; // true

99.99 instanceof Number; // false
typeof 99.99 == 'number'; // true

function() {} instanceof Function; // true
typeof function() {} == 'function'; // true

Use instanceof for complex built in types:

/regularexpression/ instanceof RegExp; // true
typeof /regularexpression/; // object

[] instanceof Array; // true
typeof []; //object

{} instanceof Object; // true
typeof {}; // object

And the last one is a little bit tricky:

typeof null; // object

Differences between typeof and instanceof in JavaScript

typeof is a construct that "returns" the primitive type of whatever you pass it.

instanceof tests to see if the right operand appears anywhere in the prototype chain of the left.

It is important to note that there is a huge difference between the string literal "abc", and the string object new String("abc"). In the latter case, typeof will return "object" instead of "string".

Why a number isn't instance of Number with typeof and instanceof?

JavaScript has number primitives and Number objects. A number primitive isn't instanceof anything because it isn't an object, and only objects are "instances" of something ("instance" being a term of art from object oriented programming); so instanceof is not useful for primitives.

That's where typeof comes in. The result of typeof for primitive numbers is "number".

Since instanceof expects a constructor function as the right hand operand, you could have your ofType function branch based on whether it gets a function or a string, using instanceof if it's a function and typeof if it's a string. Using your forEach loop:

Array.prototype.ofType = function (type) {
let newArr = [];
if (typeof type === "string") {
this.forEach(i => typeof i === type ? newArr.push(i) : newArr );
} else {
this.forEach(i => i instanceof type ? newArr.push(i) : newArr );
}
return newArr;
};

But I wouldn't use forEach for this, I'd use filter:

Array.prototype.ofType = function (type) {
let newArr;
if (typeof type === "string") {
newArr = this.filter(i => typeof i === type);
} else {
newArr = this.filter(i => i instanceof type);
}
return newArr;
};

Also, I strongly recommend not adding enumerable properties to Array.prototype, it breaks code that incorrectly uses for-in loops on arrays. Use Object.defineProperty instead:

Object.defineProperty(Array.prototype, "ofType", {
value(type) {
let newArr;
if (typeof type === "string") {
newArr = this.filter(i => typeof i === type);
} else {
newArr = this.filter(i => i instanceof type);
}
return newArr;
},
writable: true,
configurable: true,
enumerable: false // This is the default, so you could leave it off
});

Live Example:

Object.defineProperty(Array.prototype, "ofType", {    value(type) {        let newArr;        if (typeof type === "string") {            newArr = this.filter(i => typeof i === type);        } else {            newArr = this.filter(i => i instanceof type);        }        return newArr;    },    writable: true,    configurable: true,    enumerable: false // This is the default, so you could leave it off});
console.log([1, "2", 3, "4"].ofType("number"));
console.log([new Date, "2", new Date, "4"].ofType(Date));

typeof and instanceof operators returns different information for the same var

You're confusing the primitive type string and the type object for your object which is an instance of String. They're different.

var s = "a"; // a string, typeof is "string"
var s = new String("a"); // an instance of String, typeof is "object"

What is the difference between the 'instanceof' and 'in' keywords?

The main difference is that instanceof is a Java keyword, while obj in SomeClass is an equivalent of SomeClass.isCase(obj) method call as you mentioned in your question.

There is one major implication: instanceof cannot be overridden and as Oracle docs says:

The instanceof operator compares an object to a specified type. You can use it to test if an object is an instance of a class, an instance of a subclass, or an instance of a class that implements a particular interface.


Source: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op2.html

Class.isCase(obj) is implemented as follows:

/**
* Special 'Case' implementation for Class, which allows testing
* for a certain class in a switch statement.
* For example:
* <pre>switch( obj ) {
* case List :
* // obj is a list
* break;
* case Set :
* // etc
* }</pre>
*
* @param caseValue the case value
* @param switchValue the switch value
* @return true if the switchValue is deemed to be assignable from the given class
* @since 1.0
*/
public static boolean isCase(Class caseValue, Object switchValue) {
if (switchValue instanceof Class) {
Class val = (Class) switchValue;
return caseValue.isAssignableFrom(val);
}
return caseValue.isInstance(switchValue);
}

Source: org/codehaus/groovy/runtime/DefaultGroovyMethods.java#L1121

As you can see based on the source code Groovy's obj in SomeClass is not an alias to instanceof, because it does a bit more. However, there is one important thing worth mentioning - you can override isCase() implementation, but you can't change how instanceof Java keyword behaves. Overriding Class.isCase() may cause some damage to your code if you use it as an alternative to Java's instanceof keyword.

typeOf without using getClass() or instanceof

Note that Java is statically typed language. There's no need to check the variable primitive type at runtime, because it's known at compile time and cannot change. For example, if you declare

int x = 5;

Then x cannot be anything else other than int, so trying to do something like typeof(x) (like in some other languages) is meaningless.

You can generalize the variable type assigning it to the Object reference type:

int x = 5;
Object obj = x;

But even in this case obj will not be int. In this case Java compiler will automatically box your x to Integer type, so obj.getClass().getName() will return java.lang.Integer and obj instanceof Integer will return true.



Related Topics



Leave a reply



Submit