JavaScript类型判断全解析:从typeof到原型链的深度探索
前言:当代码遇见"你是谁"的灵魂拷问
在JavaScript的奇幻世界里,类型判断是每位开发者必须掌握的生存技能。想象一下:当你面对一个神秘变量时,能否快速识别它的真身?是原始数据类型的简单纯粹,还是引用数据类型的复杂多变?类型判断就像开发者的"火眼金睛",能看穿数据的本质。
本文将带你深入探索JavaScript类型判断的四大核心方法:
typeof- 基础类型的快速识别instanceof- 原型链的侦探工具Object.prototype.toString.call()- 终极类型鉴别器Array.isArray()- 数组专属检测
通过生动的代码示例和底层原理剖析,你将彻底掌握:
- 为什么
typeof null返回"object" - 如何手动实现
instanceof的检测逻辑 toString方法背后的类型鉴别魔法- 各种方法的适用场景与局限性
准备好揭开JavaScript类型判断的神秘面纱了吗?让我们开始这段探索数据本质的旅程! 开始之前,先复习一下js里面有哪几种数据类型)
typeof
- typeof 可以准确判断除了null以外的基本数据类型
- typeof 判断引用数据类型,除了fuction以外,其他的都返回object
- typeof 是同过将值转换为二进制来判断类型的,对于二进制前三位是0的统一识别为对象,而所有的引用数据类型转换为二进制的前三位都是0,null的二进制全是0
let s = "hello";
let n = 123;
let f = true;
let u = undefined;
let nu = null;
let sy = Symbol();
let b = BigInt(123);
let arr = [];
let obj = {};
let func = function () {};
let date = new Date();
let set = new Set(); //只能遍历,不能单独取出来
let map = new Map();
console.log(typeof s);//string
console.log(typeof n);//number
console.log(typeof f);//boolean
console.log(typeof u); ///undefined
console.log(typeof nu);//object
console.log(typeof sy);//symbol
console.log(typeof b);//bigint
console.log(typeof arr);
console.log(typeof obj);
console.log(typeof func);
console.log(typeof date);
console.log(typeof set);
console.log(typeof map);
//使用typeof的判断一个数据是否是对象类型的话我们需要这样
if(typeof arr === 'object' &&arr!= null){
console.log('a一定是对象');
}
instanceof
- 能准确判断引用类型,判断机制是:通过对象的隐式原型链来查找是否存在某一项等于右边的prototype
- 不能判断基本数据类型
console.log(arr instanceof Array);//instanceof当成关键字来用
console.log(arr instanceof Object);//arr.__proto__ === Array.prototype.__proto__=Object.prototype
console.log(obj instanceof Object);
console.log(date instanceof Date);
console.log(set instanceof Set);
console.log(map instanceof Map);
console.log(s instanceof String );//false
console.log(n instanceof Number );//引用 大写首字母 找到对应的构造函数
//console.log(u instanceof Undefined );没有undefined的构造函数
// 引用类型会有隐式原型(对象原型) v8会认为原始类型是没有方法的 ,所以会默认原始类型是 没有隐式原型的(对象原型)
//所以我们没有办法在原始类型数据上添加方法 ,当我们硬要访问原始数据类型的对象原型时,是能访问到的,像字符串访问到的对象原型就是字符串对象
console.log(sy instanceof Symbol );//false
console.log(b instanceof BigInt );
//instanceof 只能判断引用数据类型
引用类型会有隐式原型(对象原型),原始数据类型也有,但是 v8会认为原始类型是没有属性方法的 ,所以会默认原始类型是 没有隐式原型的(对象原型)
所以我们没有办法在原始类型数据上添加方法 ,当我们硬要访问原始数据类型的对象原型时,是能访问到的,像字符串访问到的对象原型就是字符串对象 因此instanceof无法用来判断原始数据类型,v8默认其没有对象原型
手搓instanceof:
function myInstanceof(L,R){
L=L.__proto__
while(L){
if(L===R.__proto__){
return true;
}
else{
L=L.__proto__
}
}
return false
}
console.log(myInstanceof([],Array));
console.log(myInstanceof([],Object));
instanceof判断数据类型,本质是通过判断引用数据类型身上的对象原型是否等于对应的构造函数的对象原型,但是如果一开始没找到,它还会去构造函数原型对象的对象原型上找,如下:
console.log(arr instanceof Object);//arr.__proto__ === Array.prototype.__proto__=Object.prototype
Array.prototype=new Object()而构造函数的原型对象又会有对象原型
Array.prototype.__proto__=Object.prototype构造函数的原型对象是对象,是对象就会有对象原型,其对象原型会等于上一级的构造函数的原型对象
直到Object.prototype.__proto__==null
Object.prototype.toString.call()
- 如果this value未定义,则返回'objcet Undefined'
- 如果this value 为null,则返回'objcet Null'
- 设obj 为调用ToObject的结果,将this值作为参数传递
- 返回String值,该值是连接三个字符串'[ object'、 class和 ']'
let str='hello'
let s=str.slice(0,3)//不影响原数组
console.log(s,str);
slice方法的两个参数是复制的区间,区间是左闭右开
console.log(Object.prototype.toString.call(123));//'[object Stringg]'
let type=Object.prototype.toString.call(123)
console.log(type);
let type1=type.slice(8,-1)
console.log(type1);
let type2=Object.prototype.toString.call(undefined)//需要加上call,不加call的话,构造函数身上的原型对象的方法就会指向实例化对象,而不是undefined
let type3=Object.prototype.toString.call(null)
console.log(type2);
console.log(type3);
通过截取Object.prototype.toString.call(123) 结果可以得到其数据类型,但是为什么呢?
toString的原理
let obj=ToObject(this)
let class =obj.xxx
return '[object '+class+']'
toString方法存在于Object.prototype上
当我们执行 Object.prototype.toString时,相当于执行了上面三步通过Toobject方法将传入参数改为对象, 设obj 为调用ToObject的结果,将this值作为参数传递,这样obj的上面的某个属性就是传入数据的类型,
但是需要注意的是这里toString是Object.prototype的方法,构造函数的this是隐式绑定在实例化对象上,构造函数的原型对象的函数体的this是隐式绑定在了实例对象上面的,toString方法的this是隐式绑定,默认指向了对象,所以这里需要使用call方法将toString方法的this重新指向传入的参数。
Array.isArray()
console.log(Array.isArray([]));
// 判断是不是数组
结语:成为类型判断大师的终极指南
经过本文的深度探索,我们已经揭开了JavaScript类型判断的神秘面纱:
typeof是识别原始类型的第一道防线,但需警惕null的陷阱instanceof通过原型链追踪引用类型的血缘关系,但不适用于原始类型Object.prototype.toString.call()是类型判断的终极武器,能精准识别所有类型Array.isArray()是针对数组的专业检测工具
类型判断黄金法则:
-
基础类型检测:优先使用
typeof(注意null特殊情况) -
引用类型鉴别:
- 数组 →
Array.isArray() - 其他对象 →
Object.prototype.toString.call()
- 数组 →
-
原型关系验证:使用
instanceof检查对象继承关系 -
终极解决方案:复杂场景下使用
Object.prototype.toString.call()
"精通类型判断的开发者,就像拥有数据世界的X光眼——能看透每一行代码背后的本质"
欢迎友友们点赞评论,如有不足欢迎指出!