js数据类型检测的方式有哪些?

一、typeof

typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型。它返回值是一个字符串,该字符串说明运算数的类型。

	typeof 100				// number
	typeof NaN				// number
	typeof Infinity			// number
	typeof true				// boolean
	typeof 'message'		// string
	typeof []				// object
	typeof {}				// object
	typeof null				// object
	typeof function(){}		// function
	typeof eval				// function
	typeof Date				// function
	typeof undefined		// undefined
	typeof Symbol()			// symbol
	typeof BigInt(1234567)  // bigint

	// 基本数据类型:number string boolean null undefined symbol bigint
	// 引用数据类型:object(又分为对象、数组、函数)

我们注意到[ ]、{ }、null返回的都是object。所以判断数组类型和null类型时不能用typeof。

为什么typeof null 返回object呢?

typeof null结果是object, 这是个历史遗留bug

第一版的JavaScript是用32位bit来存储值的,且是通过值的低1位或3位来识别类型的。
1:整型(int)
000:引用类型(object)
010:双精度浮点型(double)
100:字符串(string)
110:布尔型(boolean)
另外还用两个特殊值:
1.undefined,用整数−2^30(负2的30次方,不在整型的范围内)
2.null,机器码空指针(C/C++ 宏定义),低三位也是000
这32位有1-3位表示TYPE TAG,其它位表示真实值 而表示object的标记位正好是低三位都是0(000: object). 而js 里的Null 是机器码NULL空指针,所以空指针引用加上对象标记还是0,最终体现的类型还是object…

二、instanceof

instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof 检测的是原型。

	// 用一段伪代码来模拟其内部执行过程。
	const instanceof = (A, B) => A.__proto__ === B.prototype
	100 instanceof Number   			 		// false
	true instanceof Boolean				 		// false
	'message' instanceof String			 		// false
	null instanceof Object				 		// false
	[] instanceof Array					 		// true
	{} instanceof Object				 		// true
	function(){} instanceof Function	 		// true
	new Number(100) instanceof Number	 		// true
	new Boolean(true) instanceof Boolean		// true
	new String('message') instanceof String 	// true

	function Person() {}
	const p1 = new Person()
	p1 instanceof Person			// true
	function Car() {}
	const car1 = new Car()
	car1 instanceof Car				// true

	[] instanceof Object			// true
	[] instanceof Array				// true

[ ] instanceof Object 和 [ ] instanceof Array 都是返回 true。为什么会这样呢?

  • [ ] .__proto__ 指向 Array.prototype
  • Array.prototype.__proto__ 指向 Object.prototype
  • Object.prototype.__proto__ 最终指向 null

[ ]、Array 和 Object 三者内部存在完整的原型链。
从原型链可以看出,[ ] 的 __proto__ 直接指向 Array.prototype,间接指向 Object.prototype,所以按照 instanceof 的判断规则,[ ] 就是 Object 的实例

因此,instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。所有你会发现基本数据类型 用 instanceof 判断时都会返回 false。

三、constructor

当一个函数 Person 被定义时,JS引擎会为 Person 添加 prototype 原型,然后再在 prototype 上添加一个 constructor 属性,并让其指向 F 的引用。如下所示:
图片
当执行 const p = new Person() 时,Person 被当成了构造函数,p 是 Person 的实例对象,此时 Person 原型上的 constructor 传递到了 p 上,因此 p.constructor === Person

	(100).constructor === Number				// true
	true.constructor === Boolean				// true
	('message').constructor === String			// true
	([]).constructor === Array					// true
	(function() {}).constructor === Function	// true	
	({}).constructor === Object					// true
  1. null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
  2. 需要注意的是,如果创建一个对象来改变它的原型,constructor 就不能用来判断数据类型了。
	function Person() {}
	const p1 = new Person()
	p1.constructor === Person		// true
	Person.prototype = new Array()
	// Person.prototype = { xx: 'yy' } 
	const p2 = new Person()
	p2.constructor === Person  	 	// false
	p2.constructor === Array    	// true
	// p2.constructor === Object
	// 为什么变成了 Object?

	// 因为 prototype 被重新赋值的是一个 { }, { } 是 new Object() 的字面量,因此 new 	Object() 会将 Object 原型上的 constructor 传递给 { },也就是 Object 本身。
	// 因此,在重写对象原型时一般都需要重新给constructor赋值,以保证对象实例的类型不被篡改

四、Object.prototype.toString.call()

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为
[object Xxx] ,其中 Xxx 就是对象的类型。

对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call
/ apply 来调用才能返回正确的类型信息。

	const a = Object.prototype.toString
	a.call(100)				// [object Number]
	a.call(true)			// [object Boolean]
	a.call('message')		// [object String]
	a.call([])				// [object Array]
	a.call({})				// [object Object]
	a.call(function() {})	// [object Function]
	a.call(null)			// [object Null]
	a.call(undefined)		// [object Undefined]
	a.call(Symbol())		// [object Symbol]
	a.call(BigInt(1000000))	// [object BigInt]
	a.call(new Date())		// [object Date]

同样是检测对象obj调用toString方法,obj.toString()的结果和Object.prototype.toString.call(obj)的结果不一样,这是为什么?
这是因为toString为Object的原型方法,而Array,function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串…),而不会去调用Object上原型toString方法(返回对象的具体类型)所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object上原型toString方法。

即使改变它的原型,也还能正确判断。

	function Person() {}
	Person.prototype = new Array()
	Object.prototype.toString.call(Person)			// [object Function]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值