| ✍️ Tangxt | ⏳ 2020-06-15 | 🏷️ JS 专题 | 
typeof null -> "object" -> null不是对象,它是空对象指针,一般我们用完了一个对象变量,就会把该对象赋值为 null ,就目前的Chrome浏览器而言,它时不时就会去回收咩有被占用的堆内存,如本来一个 obj 变量,占用了 {name:'frank'} 这个堆内存,我们用完了这个堆内存,我们就 obj = null ,这样一来 {name:'frank'} 就咩有被 obj 占用了,没有被占用,那么就会被Chrome浏览器的辣鸡回收机制给回收掉! -> IE的辣鸡回收机制与chrome不同typeof 很强大的话,就不需考虑其它检测方式了面试的坑(也不算是坑):
console.log(typeof []); // => "object"
console.log(typeof typeof []); // => "string"
运算规则是:从右往左!
instanceof/constructor__proto__ 或者 prototype 改动原型链的动向,所以基于 instanceof 检测出来的结果并不一定是准确的__proto__ ,虽说也是所属类的实例,在JS中也可以调取所属类原型上的方法,但是instanceof是不认的测试:
console.log(12 instanceof Number); // => false
console.log(new Number(12) instanceof Number); // => true
console.log([] instanceof Array); // => true
console.log([] instanceof Object); // => true
关于浏览器的隐式转换:
(12).__proto__<=>new Number(12).__proto__
可以看到 12 明明是Number的实例,但是 instanceof 就是不认
搞坏 instanceof 的测试:
let arr = []
function fn() {}
arr.__proto__ = fn.prototype
arr instanceof Array // -> false

可以看到,通过JS,原型链基于 __proto__ 或者 prototype 是可以随意改动的,因此, instanceof 检测出来的结果并不一定准确! -> 所以 instanceof 只能用作于一个简单的参考姿势!
小结:
instanceof 检测基本类型,而 typeof 则可以 -> instanceof 检测引用类型值要比 typeof 准确点!如 /^$/ instanceof RegExp -> true同 instanceof 基本一样
// 私有constructor属性找不到就找公有的
console.log([].constructor === Array) // -> true -> 表示 [] 为数组
console.log([].constructor === Object) // -> false -> 不可跨级
console.log(({}).constructor === Array) // -> false
console.log((12).constructor === Number) // -> true
constructor 这个值也是可以随便改的,而且比 instanceof 还要更恶心!如:
let arr = []
Array.prototype.constructor = null
arr.constructor === Array // -> false
凡是可以随便改的,都是不严谨的,或多或少会出现潜在的bug,不过一般来说,我们基本都不会去动 constructor 的指向,或者是原型链的指向……
总之,对于基本类型而言,我们也是可以用 constructor 来搞的! -> 简单参考用 constructor 和 instanceof 这两个东西吧!
就上边我们所看到的那样,不管是 typeof 、 instanceof ,还是 constructor ,都有自己很多的局限性
那么是否存在一种没有局限性的方案呢?
有的,那就是 Object.prototype.toString 方法啦! -> 注意,这是Object原型上的 toString 方法!可不是其它类(如Array等)上的 toString 方法!
Object.prototype.toString.call没有局限性的方案!
注意,也是有 Null 和 Undefined 这两个内置类的,只是我们开发者无法使用罢了 -> 你一使用就会报错!
敲黑板:
Object原型上的
toString方法可不是用来转换为字符串的,而是返回当前实例所属类的信息

写法(本质上是其它类型数据的方法借用,就像是伪数组,如arguments借用数组的slice方法变为真正的数组):
Object.prototype.toString.call([value])
// or
({}).toString.call([value])
返回值的格式:
"[object 所属类信息]"
可能有的结果:
"[object Object/Array/RegExp/Date/Function/Null/Undefined/Number/String/Boolean/Symbol...]"
原理:

数组字面量不需要这样
([]),而普通对象是需要的 ->({}),因为{}在JS中有太多含义了,如代码块,对象字面量等等,所以如果你这样{}.toString(),那么就会报语法错误!
测试(检测各种值的数据类型):

即便你更改原型或原型链:

也不会影响 ({}).toString.call() 的判断!
所以:
这种方式基本上没有什么局限性,是检测数据类型最准确的方式
但在我看来,这还是有弊端的:

typeof -> 为啥用这个? -> 因为简单呀!没必要搞那些复杂的姿势{} :
        instanceof 就搞定,如 xxx instanceof Array 」,或者另一种姿势: xxx.constructor === Array({}).toString.call(xxx) 这种姿势来搞!1 ,那么它就是 Number 类型的 -> 我看到 /^$/ 这种结构的数据,那么它就是 RegExp 类型的 -> 我看到 [] 这种结构的数据,那么它就是 Array 类型的 -> 我看到 {} 这种结构的数据,那么它就是 Object 类型的 -> 我看到 function(){} 这种结构的数据,那么它就是 Function 类型的 -> ……