Data type detection
Typeof The operator used to detect data types
Typeof [value]=> A character string containing the corresponding data type
- Limitations:
- Typeof null – > ‘object’ (null)
- Typeof detects object types, all of which are “object” except for the executable “function” which can be detected as “function” (because of the call).
- If a variable is not declared, it will be undefined based on typeof. If a variable is not declared, it will be undefined based on let.
- Typeof detects the value of the object type corresponding to the original value, resulting in “object” (not the Number we want).
+ Why: The typeof test data type is based on the underlying binary value of the computer, it is treated as “000” starting object, and null is all zero + benefits + simple, good performance (because it is based on the underlying binary value)
Instanceof is a temporary test datatype that is intended to check whether the current instance belongs to this class
[value] instanceof Ctor=>true/false
- Advantage Subdivide object datatype value “But just because the result is true does not mean it is a standard common object”
Let arr=[10,20,30,40] //arr.__proto__=> array. prototype=> object.prototype console.log(arr instanceof Array); //true console.log(arr instanceof Object); //trueCopy the code
- Disadvantages: Cannot detect a value of a primitive value type “But the object format instance of the primitive value can”
console.log(new Number(1) instanceof Number); //true console.log(1 instanceof Number); //falseCopy the code
- Principle: according to the prototype chain detection; The result is TRUE as long as the currently detected constructor (its prototype object) appears on the instance’s prototype chain; FALSE if onject. prototype is not found
Function Fn(){} Fn. Prototype = array. prototype let f=new Fn; //trueCopy the code
- f instanceof Fn ->FnSymbol.hasInstance
- How to detect the underlying:
- When we use instanceof, we first check if the Fn constructor has symbol.hasinstance (). If it does, fnSymbol.hasinstance is a function that passes in the instance f, So f instanceof Fn = = = FnSymbol. HasInstance / / true
- The prototype for Function will have this property:
function Fn(){} let f=new Fn; console.log(f instanceof Fn); //true console.log(Fn[Symbol.hasInstance](f)); //true console.log(f instanceof Fn===Fn[Symbol.hasInstance](f)); //trueCopy the code
- This is the default when using instanceof (if the browser has this property, it usually does)
- Fn[symbol.hasinstance]=function(){}// The symbol.hasinstance property cannot be modified; As you can see in the figure below, symbol.hasinstance is still a function of its own rather than an addition
- But Es6 syntax can be modified, so there are some problems
class Fn{ static[Symbol.hasInstance](){ console.log('OK'); return true } } let f=new Fn; console.log(f instanceof Fn); // return true(ES6); // Return true(ES6);Copy the code
- An amazing thing happens, and if we know this mechanism, we can rewrite the results!
class Fn{ static[Symbol.hasInstance](obj){ if(Array.isArray(obj)) return true return false } } let f=new Fn; Let arr=[10,20,30,40] console.log(arr instanceof Fn); //true console.log(f instanceof Fn); //falseCopy the code
+ arr instanceof Fn also calls symbol. hasInstance by default to pass in arr which has nothing to do with Fn but returns trueCopy the code
-
Conclusion: When instanceof is used in the underlying process, the first thing the underlying layer does is to call its symbol. hasInstance. If there is one, it will do this and pass in the instance to be checked. If this method is not written by itself, it will be executed according to the method on the prototype. By default, it will be searched according to the prototype chain mechanism to see if the current constructor prototype appears on the prototype chain of the instance. If the result is true, the result is false
-
Interview question: Rewrite instanceof
- The original instanceof test left instance must be an object and a function object (must have prototype)
- Object. GetPrototypeOf (primitive value type) will have a boxing operation by default, so there is no further judgment here, can do it yourself
- So arrow functions don’t work, objects on the right but objects that aren’t functions don’t work either
Const instance_of = function instance_of(obj, Object if (Ctor == null) throw new TypeError(' right-hand side of instanceof is not an object'); let type=typeof Ctor if (! /^(object)|(function)$/i.test(type)) throw new TypeError('Right-hand side of instanceof is not an object'); if (! /^function$/i.test(type)) throw new TypeError('Right-hand side of instanceof is not callable'); if (! Ctor.prototype) throw new TypeError( 'Function has non-object prototype undefined in instanceof check' ); let proto = Object.getPrototypeOf(obj); while (proto) { if (proto === Ctor.prototype) return true; proto = Object.getPrototypeOf(proto); } return false; }; console.log(instance_of([], Array)); //true console.log(instance_of([], RegExp)); //false console.log(instance_of(1, Number)); //true object.getProtoTypeof (1) defaults to a boxing operation console.log(instance_of(Symbol(), Symbol)); //true console.log(instance_of([], 1)); Console. log(instance_of([], {})); Let f=()=>{} console.log(instance_of([],f)); / / an errorCopy the code
Constructor is very strong.
- Instance of (); instance of (); instance of (); instance of (
- But constructor’s modifications are more “unscrupulous” than Instanceof
Let arr = [], n = 10, m = new Number(10); // console.log(arr.constructor === Array); //true console.log(arr.constructor === RegExp); //false console.log(arr.constructor === Object); //false // If CTOR is equal to Object, console.log(n.constructor === Number); //true console.log(m.constructor === Number); //trueCopy the code
- Just because the result is false doesn’t mean it’s not an object
function Fn() {} let f = new Fn(); console.log(f.constructor===Fn); //true console.log(f.constructor===Object); //falseCopy the code
- Because fn’s prototype redirection loses consructor
function Fn() {} Fn.prototype={} let f = new Fn(); console.log(f.constructor===Fn); //false console.log(f.constructor===Object); //trueCopy the code
+ redirect () {constructor ();Copy the code
- Therefore, its constructor cannot be said to be an Object, as in the case of the redirect prototype it is an instance Object
Object.prototype.to string.call ([value]) This is the only JS test that does not have any flaws, the most accurate, except that it has slightly less performance than typeof and is a bit more cumbersome to write
- Its detection results are in a fixed format
- “[Object Number/String/Boolen/Null/Undefined/Symbol/BigInt/RegExp/Date/Math/Error…] “
- Can resolve typeOF detecting raw value object type values
- Most of the built-in classes have a to String method on their prototypes that converts strings, but the Object prototype checks that the return of the data type contains information about the constructor to which it belongs
- Most built-in classes have a toString method that converts to a String, but object.prototype. toString checks the data type and returns information about the constructor it belongs to…
Object.prototype.to String.call(value)
- Why “call”?
- ([]).toString() calls array.prototype toString, which is converted to a string
+({}).toString() calls object.prototype toString and changes this to ->({}).toString.call()
- What are the rules for detecting return values?
- This typically returns information about the constructor to which the current instance belongs
- But if the instance object has the Symbol. ToStringTag attribute, the value of the attribute will be returned. For example: Math[Symbol.toStringTag]=”Math”=>Object.prototype.to String.call(Math) =>”[object Math]”
- Math itself is an instance of Object (but with the symbol.toStringTag attribute)
- The interview questions
- How to change the result of detection f to [object Fn]
class Fn {} let f = new Fn(); console.log(Object.prototype.toString.call(Fn)); //[object Function] console.log(Object.prototype.toString.call(f)); //[object Object]Copy the code
- Because Symbol. ToStringTag can easily solve this interview question
class Fn { [Symbol.toStringTag]='Fn' } let f = new Fn(); console.log(Object.prototype.toString.call(Fn)); //[object Function] console.log(Object.prototype.toString.call(f)); //[object Fn]Copy the code