JavaScript数据类型判断
# JavaScript数据类型判断
# Javascript中的数据类型介绍
JS中的数据类型基本可以分为以下几类:
- 基本数据类型
(Boolean, Number, String, undefined, BigInt, Symbol, Null )
- 复杂数据类型
(Object)
有的初学JS的人可能会有疑问了:数组Array呢,它不包含在这些类型里面吗?
答案是Array是复杂类型Object的一种,它使用整数作为键属性和长度属性之间关联的常规对象。
那基本类型和特殊类型有什么区别呢?
答案是基本数据类型的值都是不可变的。什么意思呢?也就是说所有对基本数据类型的赋值都是值拷贝,是返回了一个新值,而原值并没有被改变;而复杂数据类型,也就是Object类型,是定义为内存中可以被标识符引用的一块区域,所以复杂类型的赋值都是引用拷贝,也就是深拷贝;关于深拷贝和浅拷贝的问题,我会在其他章节中去写一写。
# 数据类型的判断方法
目前JavaScript中对数据类型的判断有以下一些方法:
//基本数据类型
let bool = true
let num = 1
let str = 'abc'
let und = undefined
let nul = null
let bigint = 9007199254740991n
let symbol1 = Symbol('symbol')
//复杂数据类型
let arr = [1,2,3]
let obj = {name:'obj'}
let fun = function(){console.log('I am a function')}
2
3
4
5
6
7
8
9
10
11
12
# typeof 方法
console.log('//基本数据类型')
console.log(typeof bool); //boolean
console.log(typeof num);//number
console.log(typeof str);//string
console.log(typeof und);//undefined
console.log(typeof nul);//object
console.log(typeof bigint);//bigint
console.log(typeof symbol1);//symbol
console.log('//复杂数据类型')
console.log(typeof arr);//object
console.log(typeof obj);//object
console.log(typeof fun);//function
2
3
4
5
6
7
8
9
10
11
12
可以看到,typeof方法是有局限性的:
- 对于基本数据类型,null会被检测为object,其他类型可以被检测出;
- 对于复杂数据类型,数组Array和对象Object会统一检测为object,无法区分;
- 对于function函数,会检测出为function;
# instanceof 方法
console.log('//基本数据类型')
console.log(bool instanceof Boolean);// false
console.log(num instanceof Number);// false
console.log(str instanceof String);// false
console.log(und instanceof Object);// false
console.log(nul instanceof Object);// false
console.log(bigint instanceof BigInt);// false
console.log(symbol1 instanceof Symbol);// false
console.log('//复杂数据类型')
console.log(arr instanceof Array);// true
console.log(obj instanceof Object);// true
console.log(fun instanceof Function);// true
2
3
4
5
6
7
8
9
10
11
12
可以看到,instanceof方法的优缺点如下:
- 对于基本数据类型,如果不是用New声明的则测不出来;对于null类型,会被检测为Object
- 对于复杂数据类型,可以区分出Array,Object,Function
# constructor方法
console.log('//基本数据类型')
console.log(bool.constructor === Boolean);// true
console.log(num.constructor === Number);// true
console.log(str.constructor === String);// true
console.log(bigint.constructor === BigInt);//true
console.log(symbol1.constructor === Symbol);//true
console.log('//复杂数据类型')
console.log(arr.constructor === Array);// true
console.log(obj.constructor === Object);// true
console.log(fun.constructor === Function);// true
2
3
4
5
6
7
8
9
10
对于constructor方法,优缺点如下:
- 对于undefined,null这两个基本数据类型,使用constructor方法会报错
- 因为constructor方法其实是对实例对象的构造函数的引用,所以对于手动创建构造函数的类型,此方法是不可用的;除此之外,基本数据类型的constructor属性的值也是可以改变的;
# Object.prototype.toString.call方法(推荐方法)
首先上测试结果
console.log('//基本数据类型')
console.log(Object.prototype.toString.call(bool));//[object Boolean]
console.log(Object.prototype.toString.call(num));//[object Number]
console.log(Object.prototype.toString.call(str));//[object String]
console.log(Object.prototype.toString.call(und));//[object Undefined]
console.log(Object.prototype.toString.call(nul));//[object Null]
console.log(Object.prototype.toString.call(bigint));//[object BigInt]
console.log(Object.prototype.toString.call(symbol1));//[object Symbol]
console.log('//复杂数据类型')
console.log(Object.prototype.toString.call(arr));//[object Array]
console.log(Object.prototype.toString.call(obj));//[object Object]
console.log(Object.prototype.toString.call(fun));//[object Function]
2
3
4
5
6
7
8
9
10
11
12
可以看到,Object.prototype.toString.call
方法对无论基本数据类型还是复杂数据类型,都能够完美测出;事实上,这得益于Object的原生toString
方法。在<<Javascript高级程序设计>>中,是这么定义Object的原生toString
方法的:在任何值上调用 Object 原生的 toString
方法,都会返回一个 [object NativeConstructorName]
格式的字符串。每个类在内部都有一个 [[Class]]
属性,这个属性中就指定了上述字符串中的构造函数名。
值得注意的是,由于此方法返回的是NativeConstructorName
格式的字符串,所以对于非原生的构造函数,调用此方法依然会检测出[object Object]
,如下代码所示。(这里我理解所有手动构造的构造函数,本质类型依然是Object),这也保证了我们对所有数据类型调用此方法都能得出正确的判断;
function Test(name){
this.name = name;
}
let test1 = new Test("will.wei");
console.log(Object.prototype.toString.call(test1));//[object Function]
2
3
4
5
# 手写类型判断方法typeof()
基于上面的分析总结,我们可以手写一个比较完美的数据类型判断方法,使得其更加完美:
function typeOf(param){
return Object.prototype.toString.call(param).match(/\s+(\w+)/)[1]
}
2
3