First, the typeof
The sole purpose of the Typeof operator is to check data types
type | The typeof results | |
---|---|---|
Basic types of | undefined | “undefined” |
Boolean | “boolean” | |
Number | “number” | |
String | “string” | |
BigInt (new in ECMAScript 2020) | “bigint” | |
Symbol | “symbol” | |
null | “object” | |
Reference types | Object (Object, Array, Map, Set, etc.) | “object” |
Function | “function” |
So, when we use typeof to judge a reference to a type variable, it will return Object, no matter what typeof variable it is.
For this, Instanceof was introduced.
Second, the instanceof
Instanceof in contrast to Typeof, the Instanceof method requires the developer to explicitly identify an object as a particular type. That is the method instanceof uses to determine which constructor a reference type belongs to.
var arr = []
arr instanceof Array // true
typeof arr // "object"
// Typeof cannot determine whether a type is an array
Copy the code
The instanceof operator also takes inheritance into account, so instanceof can be used to determine whether an instance is of its parent type.
// Determine if f is an instance of class Foo and of its parent type
function Aoo(){}
function Foo(){}
//JavaScript prototype inheritance
Foo.prototype = new Aoo();
var foo = new Foo();
console.log(foo instanceof Foo) // true
console.log(foo instanceof Aoo) // true
Copy the code
F instanceof Foo
- f
__proto__
Level by level, does that correspond toFoo.prototype
- Let’s go up and see if that corresponds
Aoo.prototype
- Try again
f instanceof Object
That is, instanceof can be used to judge multi-level inheritance relationships.
Iii. Internal implementation principle of Instanceof
Instanceof’s internal implementation is to determine the return value of instanceof by determining whether the object’s prototype can be found on the object’s prototype chain
1. Internal implementation principle
// An internal implementation of instanceof
function instance_of(L, R) {//L indicates the left expression of the table, R indicates the right expression, i.e., L is a variable, R is a type
// take the display prototype of R
var prototype = R.prototype
// take the implicit prototype of L
L = L.__proto__
// Determine whether the type of object (L) is exactly equal to the explicit prototype of type (R)
while (true) {
if (L === null) {
return false
}
// Key here: return true when prototype is strictly L
if (prototype === L) {
return true
}
L = L.__proto__
}
}
Copy the code
The instanceof operator is used to test whether constructor. Prototype exists on the prototype chain of the parameter Object.
For example, why does instanceof return true? Clearly, an is not created by Bottle().
function An() {}
function Bottle() {}
An.prototype = Bottle.prototype = {};
let an = new An();
console.log(an instanceof Bottle); // true
Copy the code
This is because Instanceof is not concerned with constructors, but with prototype chains.
an.__proto__ === An.prototype; // true
An.prototype === Bottle.prototype; // true
/ / that
an.__proto__ === Bottle.prototype; // true
Copy the code
__proto__ === Bottle. Prototype; an instanceof Bottle returns true.
So, according to instanceof’s logic, it is prototype, not the constructor, that really determines the type.
2. The Object. The prototype. ToString (extension)
There is also a good type of method, is the Object. The prototype. ToString, we can use this method to a variable of type to compare accurate judgment
By default (without overriding toString methods), any call to Object’s native toString method returns “[Object type]”, where type is the type of the Object;
let obj = {};
console.log(obj); / / {}
console.log(obj.toString()); // "[object Object]"
Copy the code
[[Class]]
Each instance has a [[Class]] attribute that specifies the type (constructor name) in the above string. [[Class]] can’t directly access, but usually can indirectly by borrowing the default on the value of the Object. The prototype. ToString. Call (..) Method call to show.
Object.prototype.toString.call("abc"); // "[object String]"
Object.prototype.toString.call(100); // "[object Number]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call([1.2.3]); // "[object Array]"
Object.prototype.toString.call(/\w/); // "[object RegExp]"
Copy the code
By the Object. The prototype. ToString. Call (..) To get the type of each object.
function isFunction(value) {
return Object.prototype.toString.call(value) === "[object Function]"
}
function isDate(value) {
return Object.prototype.toString.call(value) === "[object Date]"
}
function isRegExp(value) {
return Object.prototype.toString.call(value) === "[object RegExp]"
}
isDate(new Date()); // true
isRegExp(/\w/); // true
isFunction(function(){}); //true
Copy the code
Or it can be written as:
function generator(type){
return function(value){
return Object.prototype.toString.call(value) === "[object "+ type +"]"}}let isFunction = generator('Function')
let isArray = generator('Array');
let isDate = generator('Date');
let isRegExp = generator('RegExp');
isArray([])); // true
isDate(new Date()); // true
isRegExp(/\w/); // true
isFunction(function(){}); //true
Copy the code
Symbol.toStringTag
Object. The prototype. The toString method can use Symbol. ToStringTag this particular Object properties to customize the output.
For example:
let bottle = {
[Symbol.toStringTag]: "Bottle"
};
console.log(Object.prototype.toString.call(bottle)); // [object Bottle]
Copy the code
Most environment-related objects also have this property. The following output may vary from browser to browser:
// toStringTag for environment-related objects and classes:
console.log(window[Symbol.toStringTag]); // Window
console.log(XMLHttpRequest.prototype[Symbol.toStringTag]); // XMLHttpRequest
console.log(Object.prototype.toString.call(window)); // [object Window]
console.log(Object.prototype.toString.call(new XMLHttpRequest())); // [object XMLHttpRequest]
Copy the code
The output is the same as symbol.toStringTag (if it exists), but wrapped in object… In the water.
So, if you want to get the built-in object type information as a string, rather than just detect the type, you can use this method instead of Instanceof.
3. Summary
Apply to | return | |
---|---|---|
typeof | Basic data types | string |
instanceof | Any object | true/false |
Object.prototype.toString |
Basic data types, built-in objects, and containsSymbol.toStringTag Property object |
string |
Object. The prototype. ToString is basically a enhanced version typeof.
Instanceof is useful in situations involving multi-tier class structures, where class inheritance needs to be taken into account.
Typeof error: null = ‘object’;
// This has been true since the beginning of JavaScript
typeof null= = ='object';
Copy the code
In the original implementation of JavaScript, values in JavaScript were represented by a tag representing a type and actual data values. The type label of the object is 0. Because null represents a null pointer (with a value of 0x00 on most platforms), null has a type label of 0 and typeof NULL therefore returns “object”. (Reference)
There was a proposed fix for ECMAScript (via opt-in), but it was rejected. This proposal causes Typeof NULL === ‘NULL’.
If judged by instanceof:
null instanceof null
// Uncaught TypeError: Right-hand side of 'instanceof' is not an object
Copy the code
Three minutes a day