先提个问:JavaScript中有多少种数据类型?emmm,有人说这还不简单啊,不就是Number类型,String类型,Boolean类型,object类型······说着说着就不知道自己说了哪些。
其实JavaScript中的数据类型主要分为两大类
第一种就是原始数据类型
原始数据类型又分为7种,最后两种很少用,所以我们只记住前面五种就可以了。
Number:表示整数和浮点数,例如 42, 3.14。
String:字符串类型,例如 "Hello, World!"。
Boolean:布尔类型,只有 true 和 false 两个值。
Undefined:这个类型表示一个变量被定义了但是并没有被赋值
Null:表示一个刻意的空值或者缺少值,代表变量或者对象属性被设置为“无值”或者“空”的状态。
Symbol(ES6 新增):符号类型,是唯一且不可变的值,常用于对象的键,以避免键名的冲突。
BigInt(ES10 新增):可以安全地存储、操作大整数,超过 Number.MAX_SAFE_INTEGER 的整数。
第二种是引用数据类型
引用数据类型我们常用的就是object,Function,Array,Date,还有我们常用于字符串匹配的正则(RegExp)。在es6中又新增了一些,但是我个人感觉有点多了,那些新加引用数据类型的我们更多的是平时的使用,例如es6中新增的Class,Promise,Error等。
Object:对象类型,可以包含多个键值对,如 let obj = {a:1,b:2}
Function:函数本身也是一种对象,可以作为值来传递和赋值。let foo = function(){}
Array:数组,用于存储有序的元素集合。let arr = [1,2,3,4]
Date:通常用于处理日期和时间。
RegExp:正则表达式对象,用于匹配字符串中的模式。
这些类型之所以被称为引用类型,是因为这些数据类型的数据当量很大,但是调用栈的空间又很小,不便于存储这些数据类型,于是便把它们存放在堆结构中国。当我们给它们赋值给变量或者作为参数传递给函数时,实际上传递的是这些数据结构在内存中的引用(地址)。
将JavaScript中的数据类型大致分为原始数据类型和引用数据类型,然后再记原始数据类型有哪些,引用数据类型有哪些,是不是就不容易讲着讲着就讲混了!!!
如何能判断各种数据类型呢?
我们常用的typeof方法来判断一个数据的类型
我相信typeof是很多大佬经常用的一种判断数据类型的方法,我也经常使用typeof这种方法来判断数据的类型,但是后来我才知道,原来typeof判断的数据类型并不准确!请看下面示例:
console.log(typeof 42);
console.log(typeof "Hello");
console.log(typeof true);
console.log(typeof undefined);
console.log(typeof null);
console.log(typeof {});
console.log(typeof []);
console.log(typeof function(){});
正确的结果应该是number,string,boolean,undefined,null,object,array,function
但是实际的结果是什么呢?
嗯哼,初看前面几条貌似都是对的,可是一到后面,null怎么就变成了object呢,数组的类型也是object。聊到这里就不得不了解一下计算机底层的东西了。
在我们都知道计算机是以二进制来存储数据的,当要判断一个数据的数据类型时,计算机又会将数据转成二进制再来判断它的数据类型,而NUll转换为二进制就是000000000,而复杂的数据类型转成二进制后前三位都是0,而typeof判断数据类型就只看它的前三位,如果前三位全是0的话,那么就返回object。这也就解释了为什么会判断object,array,以及null的时候会给出object的结果了。所以不光是我认为,所有人都认为将null判断为object是JavaScript中的一个小BUG。
那为什么函数就能够正确的判断出他是function呢?因为typeof对函数的这种特例处理确保了它能准确地区分出函数类型。
所以,通过上面的结果,我们可以总结出这样一句话来介绍typeof的作用:
typeof 可以准确判断出null以外的原始类型,而不能判断出function外的引用类型
那怎么判断引用数据类型呢?
在js中还有一个方法用来判断一个数据是否为引用数据类型,即instanceof,如果是引用数据类型则返回true,否则返回false。这个方法只能用来判断引用数据类型,不能判断原始数据类型,如果判断原始数据类型,只会返回false。
instanceof判断一个数据是否为引用数据类型是通过原型链的查找来判断
学过原型的大佬们都知道,一个实例对象的隐式原型等于他构造函数的显示原型。我们想判断一个数组是否为原始数据类型,就可以使用arr instanceof Array,这样就可以判断他是不是个数组类型,但是这样说也有点不够准确!!!
为什么这样说呢?因为大家看看这个这行代码!console.log(arr instanceof Object);,这时打印出来也是true。???这就是我们前面说的instanceof判断的原理,因为它是将这个数据的隐式原型
与构造函数的显示原型相比较。如果不相同再往上去找,直到找到object为止,如果还没找到就返回false。而arr.__proto__ = Array.prototype,
Array.prototype.__proto__ = Object.prototype最后还是找到了,所以就返回true。
了解了instanceof的原理之后是不是觉得可以自己手搓一个instanceof
根据上面介绍的instanceof原理, 我们可以自己手搓一个myInstanceof,实现类似的效果。就是不断地比较隐式原型和构造函数的显示原型。
function myInstanceof(L,R) {
while(L !== null){
if(L.__proto__ === R.prototype){
return true
}
L = L.__proto__
}
return false
}
var arr = []
console.log(myInstanceof(arr, Array));// true
有没有一种近乎完美的办法可以判断所有的数据类型?
还真有一种完美的办法,它能够准确地识别并返回几乎所有的JavaScript数据类型的名称。这包括但不限于普通的对象(Object)、数组(Array)、函数(Function)、正则表达式(RegExp)、日期(Date)等。它就是 Object.prototype.toString()
我们首先先看一下它的效果:
Object.prototype.toString()是通过直接访问对象的内部[[Class]]属性,提供了最准确的类型信息。通过.call()方法确保方法作用于正确的对象,它能够返回如"[object Array]"这样精确的类型字符串。这种方法克服了typeof的局限性,能够准确区分所有内置类型,包括数组、正则表达式等。
因此,我们可以将Object.prototype.toString()方法的实现原理总结为五步:
- 如果 toString() 接受的值是 undefined则返回 [object Undefined]
- 如果 toString() 接受的值是 null则返回[object Null]
- 调用 ToObject(x) 将x转为对象,此时得到的对象内部一定拥有一个属性:[[Class]],该属性[[Class]]的值就是x的类型。
- 设,class 是[[Class]]的值
- 返回由
"[","object ", "class", 和 "]"拼接组成的字符串,即字符串"[object class]"
懒鬼觉得老是这样写还是太麻烦了
我们还可以手动的给他封装一下,用一个type函数给他封装一下
function type(x) {
return Object.prototype.toString.call(x).slice(8, -1);
}
console.log(type(5));
console.log(type("hello"));
这样就可以直接使用type判断数据的类型了,而且这样还可以返回我们想要的结果。
总结
我们在这里主要聊了下JavaScript中的数据类型,以及如何判断JavaScript中的数据类型。,通过一步步的深入,最后得到了我们想要得到的最优结果。其实JavaScript中有个方法 Array.isArray()能够判断是否为数组,但是也就仅仅只能判断是否为数组,得到的结果是ture or false。