引言
javascript中有七种原始数据类型和几种引用数据类型,本文将清楚地介绍四种用于类型判断的方法,分别是typeof
、instanceof
、object.prototype.tostring.call()
、array.isarray()
,并介绍其使用方法和判定原理。
typeof
- 可以准确判断除
null
之外的所有原始类型,null
会被判定成object function
类型可以被准确判断为function
,而其他所有引用类型都会被判定为object
let s = '123' // string let n = 123 // number let f = true // boolean let u = undefined // undefined let nu = null // null let sy = symbol(123) // symbol let big = 1234n // bigint let obj = {} let arr = [] let fn = function() {} let date = new date() console.log(typeof s); // string typeof后面有无括号都行 console.log(typeof n); // number console.log(typeof f); // boolean console.log(typeof u); // undefined console.log(typeof(sy)); // symbol console.log(typeof(big)); // bigint console.log(typeof(nu)); // object console.log(typeof(obj)); // object console.log(typeof(arr)); // object console.log(typeof(date)); // object console.log(typeof(fn)); // function
判定原理
typeof是通过将值转换为二进制之后,判断其前三位是否为0:都是0则为object,反之则为原始类型。因为原始类型转二进制,前三位一定不都是0;反之引用类型被转换成二进制前三位一定都是0。
null
是原始类型却被判定为object
就是因为它在机器中是用一长串0来表示的,可以把这看作是一个史诗级的bug。
所以用typeof
判断接收到的值是否为一个对象时,还要注意排除null的情况:
function isobject() { if(typeof(o) === 'object' && o !== null){ return true } return false }
你丢一个值给typeof
,它会告诉你这个字值是什么类型,但是它无法准确告诉你这是一个array
或是date
,若想要如此精确地知道一个对象类型,可以用instanceof
告诉你是否为某种特定的类型
instanceof
只能精确地判断引用类型,不能判断原始类型
console.log(obj instanceof object);// true console.log(arr instanceof array);// true console.log(fn instanceof function);// true console.log(date instanceof date);// true console.log(s instanceof string);// false console.log(n instanceof number);// false console.log(arr instanceof object);// true
判定原理
instanceof
既能把数组判定成array
,又能把数组判定成object
,究其原因是原型链的作用————顺着数组实例 arr 的隐式原型一直找到了 object 的构造函数,看下面的代码:
arr.__proto__ = array.prototype array.prototype.__proto__ = object.prototype
所以我们就知道了,instanceof
能准确判断出一个对象是否为某种类型,就是依靠对象的原型链来查找的,一层又一层地判断直到找到null
为止。
手写instanceof
根据这个原理,我们可以手写出一个instanceof
:
function myinstanceof(l, r) { while(l != null) { if(l.__proto__ === r.prototype){ return true; } l = l.__proto__; } return false; } console.log(myinstanceof([], array)) // true console.log(myinstanceof({}, object)) // true
object.prototype.tostring.call()
可以判断任何数据类型
在浏览器上执行这三段代码,会得到'[object object]'
,'[object array]'
,'[object number]'
var a = {} object.prototype.tostring.call(a) var a = {} object.prototype.tostring.call(a) var a = 123 object.prototype.tostring.call(a)
原型上的tostring的内部逻辑
调用object.prototype.tostring
的时候执行会以下步骤:
- 如果此值是
undefined
类型,则返回‘[object undefined]’
- 如果此值是
null
类型,则返回‘[object null]’
- 将 o 作为
toobject(this)
的执行结果。tostring
执行过程中会调用一个toobject
方法,执行一个类似包装类的过程,我们访问不了这个方法,是js自己用的 - 定义一个
class
作为内部属性[[class]]
的值。tostring可以读取到这个值并把这个值暴露出来让我们看得见 - 返回由
"[object"
和class
和"]"
组成的字符串
为什么结合call就能准确判断值类型了呢?
① object.prototype.tostring(xxx)
往括号中不管传递什么返回结果都是'[object object]'
,因为根据上面五个步骤来看,它内部会自动执行toobject()
方法,xxx
会被执行一个类似包装类的过程然后转变成一个对象。所以单独一个object.prototype.tostring(xxx)
不能用来判定值的类型
② 首先了解call方法的核心原理就是:比如foo.call(obj)
,利用隐式绑定的规则,让obj对象拥有foo这个函数的引用,从而让foo函数的this指向obj,执行完foo函数内部逻辑后,再将foo函数的引用从obj上删除掉。手搓一个call的源码就是这样的:
// call方法只允许被函数调用,所以它应该是放在function构造函数的显式原型上的 function.prototype.mycall = function(context) { // 判断调用我的那个哥们是不是函数体 if (typeof this !== 'function') { return new typeerror(this+ 'is not a function') } // this(函数)里面的this => context对象 const fn = symbol('key') // 定义一个独一无二的fn,防止使用该源码时与其他fn产生冲突 context[fn] = this // 让对象拥有该函数 context={symbol('key'): foo} context[fn]() // 触发隐式绑定 delete context[fn] }
③ 所以object.prototype.tostring.call(xxx)
就相当于 xxx.tostring()
,把tostring()方法放在了xxx对象上调用,这样就能精准给出xxx的对象类型
tostring方法有几个版本:
{}.tostring() 得到由"[object" 和 class 和 "]" 组成的字符串
[].tostring() 数组的tostring方法重写了对象上的tostring方法,返回由数组内部元素以逗号拼接的字符串
xx.tostring() 返回字符串字面量,比如
let fn = function(){}; console.log( fn.tostring() ) // "function () {}"
array.isarray(x)
只能判断是否是数组,若传进去的x是数组,返回true,否则返回false
总结
typeof:原始类型除了null都能准确判断,引用类型除了function能准确判断其他都不能。依靠值转为二进制后前三位是否为0来判断
instanceof:只能把引用类型丢给它准确判断。顺着对象的隐式原型链向上比对,与构造函数的显式原型相等返回true,否则false
object.prototype.tostring.call():可以准确判断任何类型。要了解对象原型的tostring()内部逻辑和call()的核心原理,二者结合才有精准判定的效果
array.isarray():是数组则返回true,不是则返回false。判定范围最狭窄
以上就是js类型判断的四种方法详解的详细内容,更多关于js类型判断的资料请关注代码网其它相关文章!
发表评论