4种JavaScript数据类型判断的方法

空值(null) 未定义(undefined) 布尔值(boolean) 数字(number) 字符串(string) 对象 (object) 符号(symbol, ES6中新增) 大整数(BigInt, ES2020 引入) 
1、typeof
console.log(typeof ""); // stringconsole.log(typeof 1 ); // numberconsole.log(typeof NaN ); // numberconsole.log(typeof true); // booleanconsole.log(typeof undefined); // undefinedconsole.log(typeof function(){}); // functionconsole.log(typeof isNaN); // functionconsole.log(typeof Symbol()); // symbolconsole.log(typeof 123n); // bigintconsole.log(typeof []); // objectconsole.log(typeof {}); // objectconsole.log(typeof null); // objectconsole.log(typeof new Date()); // objectconsole.log(typeof new RegExp()); // object
2、instanceof
instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 需特别注意:instanceof 检测的是原型
即instanceof 用来比较一个对象是否为某一个构造函数的实例。instanceof可以准确的判断复杂数据类型,但是不能正确判断基本数据类型。
console.log(12 instanceof Number); // falseconsole.log('22' instanceof String); // falseconsole.log(true instanceof Boolean); // falseconsole.log(null instanceof Object); // falseconsole.log(undefined instanceof Object); // falseconsole.log(function a() {} instanceof Function); // trueconsole.log([] instanceof Array); // trueconsole.log({a: 1} instanceof Object); // trueconsole.log(new Date() instanceof Date); // true
补充:
instanceof 的原理:主要的实现原理就是只要右边变量的 prototype在左边变量的原型链上即可。
因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果存在返回true 否则返回false
function new_instance_of(leftVaule, rightVaule) {let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值while (true) {if (leftVaule === null) {return false;}if (leftVaule === rightProto) {return true;}leftVaule = leftVaule.__proto__}}
注意:instanceof 运算时会递归查找leftVaule的原型链,即leftVaule.__proto__.__proto__.__proto__.__proto__... 直到找到了或者找到顶层为止。
一句话理解其运算规则:instanceof 检测左侧的 __proto__ 原型链上,是否存在右侧的 prototype 原型。
3、constructor
JavaScript中,每个对象都有一个constructor属性,可以得知某个实例对象,到底是哪一个构造函数产生的, constructor属性表示原型对象与构造函数之间的关联关系。
当一个函数F被定义时,JS引擎会为F添加prototype原型,然后在prototype上添加一个constructor属性,并让其指向F的引用,F利用原型对象的constructor属性引用了自身,当F作为构造函数创建对象时,原型上的constructor属性被遗传到了新创建的对象上,从原型链角度讲,构造函数F就是新对象的类型。这样做的意义是,让对象诞生以后,就具有可追溯的数据类型。
通过typeof运算符来判断它是原始的值还是对象。如果是对象,就可以使用constructor属性来判断其类型。
如判断数组的函数:
function isArray(data){return typeof data == "object" && data.constructor == Array;}isArray([]) // true
注意:null 和 undefined 是没有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
console.log('22'.constructor === String) // trueconsole.log(true.constructor === Boolean) // trueconsole.log([].constructor === Array) // trueconsole.log(document.constructor === HTMLDocument) // trueconsole.log(window.constructor === Window) // trueconsole.log(new Number(22).constructor === Number) // trueconsole.log(new Function().constructor === Function) // trueconsole.log(new Date().constructor === Date) // trueconsole.log(new RegExp().constructor === RegExp) // trueconsole.log(new Error().constructor === Error) // true
2、如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错。所以,修改原型对象时,一般要同时修改constructor属性的指向。
function Rectangle(width, height){this.width = width;this.height = height;this.getArea = function(){return '矩形的面积为' + (width * height);}}var rect1 = new Rectangle(40, 20);var rect2 = new Rectangle(50, 20);var rect3 = new Rectangle(60, 20);console.log(rect1.getArea());console.log(rect2.getArea());console.log(rect3.getArea());
如上代码,每次实例化出一个对象,都会添加getArea方法,是三个对象共有且不变的,因此将getArea放在构造函数中就会在创建对象时被多次添加,浪费内存!
因此我们将getArea添加到原型对象上就减少了多次添加,实例化对象会沿着原型链查找到此属性
实现了共享属性:
function Rectangle(width, height){this.width = width;this.height = height;}// 直接替换原型对象,但是要记得添加上构造函数属性Rectangle.prototype = {constructor: Rectangle,getArea: function(){return '矩形的面积为' + (this.width * this.height);}}// 修改特性Object.defineProperties(Rectangle.prototype, {constructor: {enumerable: false,configurable: false,writable: false},getArea: {enumerable: false,configurable: false,writable: false}})var rect1 = new Rectangle(40, 20);var rect2 = new Rectangle(50, 20);var rect3 = new Rectangle(60, 20);console.log(rect1.getArea());console.log(rect2.getArea());console.log(rect3.getArea());
很多情况下,我们可以使用instanceof运算符或对象的constructor属性来检测对象是否为数组。
如很多JS框架就是使用这两种方法来判断对象是否为数组类型。 但是检测在跨框架(cross-frame)页面中的数组时,会失败。
原因就是在不同框架(iframe)中创建的数组不会相互共享其prototype属性。例如:
<script>window.onload=function(){var iframe_arr=new window.frames[0].Array;console.log(iframe_arr instanceof Array); // falseconsole.log(iframe_arr.constructor == Array); // false}</script>
4、Object.prototype.toString.call()
Object.prototype.toString(o)是 Object 的原型方法,
获取对象o的class属性。这是一个内部属性,
连接字符串:[object + 结果(1)],格式为 [object Xxx] ,其中 Xxx 就是对象的类型。
对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
console.log(Object.prototype.toString.call(1)) // [object Number]console.log(Object.prototype.toString.call(1n)) // [object BigInt]console.log(Object.prototype.toString.call('123')) // [object String]console.log(Object.prototype.toString.call(true)) // [object Boolean]console.log(Object.prototype.toString.call(undefined)) // [object Undefined]console.log(Object.prototype.toString.call(null)) // [object Null]console.log(Object.prototype.toString.call({})) // [object Object]console.log(Object.prototype.toString.call([])) // [object Array]console.log(Object.prototype.toString.call(function a() {})) // [object Function]console.log(Object.prototype.toString.call(Symbol())) // [object Symbol]console.log(Object.prototype.toString.call(Math)) // [object Math]console.log(Object.prototype.toString.call(JSON)) // [object JSON]console.log(Object.prototype.toString.call(new Date())) // [object Date]console.log(Object.prototype.toString.call(new RegExp())) // [object RegExp]console.log(Object.prototype.toString.call(new Error)) // [object Error]console.log(Object.prototype.toString.call(window) // [object Window]console.log(Object.prototype.toString.call(document)) // [object HTMLDocument]
封装一个准确判断数据类型的函数
function __getType(object){return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];};
可以解决上面的跨框架问题。
<script>window.onload=function(){var iframe_arr=new window.frames[0].Array;console.log(Object.prototype.toString.call(iframe_arr))) // "[object Array]"}</script>
本文完~
学习更多技能
请点击下方公众号
![]()

