Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities
First of all,
- How do I determine if a variable is an array type?
- Why not Typeof?
- Instanceof why is object true?
- How to implement Instanceof?
- How can toString print [object Array]?
- Why does toString use call?
- What’s the difference between toString judging arrays and isArray judging arrays?
The principle of
typeof
The first thing we know about judgment types is this Typeof. But: do you know what types typeof can determine? C: Object, function, number, symbol, string, undefined, Boolean c: object, function, number, symbol, string, undefined, Boolean c: Object, function, symbol, string, undefined, Boolean
console.log(typeof null); // object
Copy the code
Reason: When js stores variables at the bottom, it stores their type information in the lowest 1-3 bits of the variable’s machine code.
000
Object:010
: a floating point number100
String:110
: Boolean1
: an integer
Null and undefined are a little special. The machine code of null is 0, so its lowest 3 bits are also 000, thus it is object. Undefined: it is an integer of −2^30
But there’s another problem.
console.log(null instanceof null); //Right-hand side of 'instanceof' is not an object
console.log(null instanceof Object) //false
Copy the code
I did a lot of research here and did a little bit of reading of the V8 source code (just click on it) but I couldn’t read it and couldn’t find the location. Instanceof = null; instanceof = null; instanceof = null; So NULL is not Object.
Typeof determines function but not array.
If the object implements a method inside [[Call]], return function. Refer to the article
There’s one more caveat here
console.log(typeof Object); // function
console.log(typeof Array); // function
Copy the code
instanceof
Instanceof: The principle is only 3 word prototype chain
function instanceofCode(left, right) {
var rightPrototype = right.prototype
while(true) {
if(left.__proto__ == rightPrototype) {
return true
}else if(left.__proto__ == null) { // The end of the prototype chain is null
return false
}
left = left.__proto__
}
}
var arr = []
console.log(instanceofCode(arr, Array));
Copy the code
Oh, and one more caveat about Instanceof:
console.log('1' instanceof String); // false
var string = new String(1)
console.log(string instanceof String); // true
Copy the code
Go figure
Value is a primitive value and an object. The first ‘1’ is a primitive value and the second is a new String, so it is an object.
toString
In response to a common interview question: how to determine an object is an array.
Everyone will think of the Object. The prototype. ToString. Call ()
Note:
console.log(Object.toString()); //function Object() { [native code] }
console.log(Object.prototype.toString); // [Function: toString]
Copy the code
Principle: the Object. The prototype. ToString returns the format is [Object tag] we said this tag is how to determine key. Es6 used to have a [[class]] attribute to represent different object types. Es6 changed the [[class]] attribute to [[NativeBrand]], which changed the tag based on the enumeration.
This diagram is stolen, want to learn more can see this principle reference blog
Null and undefined are also determinable.
console.log(Object.prototype.toString.call(null)); // [object Null]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
Copy the code
When we define an object ourselves and want to modify its internal [[NativeBrand]].
const obj = {
[Symbol.toStringTag]: 'obj'
}
console.log(Object.prototype.toString.call(obj)); //[object obj]
Copy the code
Q: Why “call”?
This is because both [[class]] and [[NativeBrand]] are based on the current this.
isArray
This is the way to check whether an array is an array, echoing the previous interview question. A comforting blind guess is that the object being judged has all the API methods and properties within the Array itself. V8 –isArray source code (path: “SRC /builtins/array-isarray.tq”)
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
namespace runtime {
extern runtime ArrayIsArray(implicit context: Context)(JSAny): JSAny;
} // namespace runtime
namespace array {
// ES #sec-array.isarray
javascript builtin ArrayIsArray(js-implicit context: NativeContext)(arg: JSAny):
JSAny {
// 1. Return ? IsArray(arg).
typeswitch (arg) {
case (JSArray): {
return True;
}
case (JSProxy): {
// TODO(verwaest): Handle proxies in-place
return runtime::ArrayIsArray(arg);
}
case (JSAny): {
returnFalse; }}}}// namespace array
Copy the code
We can change the return value based on toString.
Array.prototype[Symbol.toStringTag] = 'arr'
const arr = new Array(1.2.3)
const arr1 = [1.2.3]
console.log(Object.prototype.toString.call(arr)); //[object arr]
console.log(Object.prototype.toString.call(arr1));// [object arr]
console.log(Array.isArray(arr)); // true
console.log(Array.isArray(arr1)); // true
Copy the code
So the Object. The prototype. ToString. Call () and Array isArray (), When using [Symbol toStringTag] change Object. The prototype. ToString. The call () of the tag value is changed, isArray judgment will not change. Finally, in vue2 the source code is judged using array.isarray ().
conclusion
Typeof can check the basic data types, but object can only check the function of the object. Legacy Feature: Typeof NULL is object
The Instanceof principle is that the chain of prototypes goes up one layer at a time.
Object. The prototype. ToString. Call () according to the current internal attributes this looking for [[NativeBrand]].
IsArray just guesses and does not know how to verify.
Object. The prototype. ToString. Call () and Array isArray (), When using [Symbol toStringTag] change Object. The prototype. ToString. The value of the call () tag `, Array. The isArray () unchanged.
Finally, there is something wrong with what I wrote. I hope you can give me some advice.