js数据类型及类型判断
# 数据类型及类型判断
JavaScript中有8种数据类型:数字(Number)、字符串(String)、布尔值(Boolean)、undefined、null、对象(Object)、Symbol、BigInt。其中对象类型包括:数组(Array)、函数(Function),和两个特殊对象:正则(RegExp)和日期(Date)。Symbol代表独一无二的值,BigInt用于表示大整数,它们都是ES6新增的数据类型。
# typeof
typeof
返回一个表示数据类型的字符串,返回结果包括:number、string、boolean、object、undefined、function。typeof
可以对基本类型number、string 、boolean、undefined做出准确的判断(null除外,typeof
null===“object”,这是由于历史的原因,在js最初版本000开头代表着对象,而null表示全为0,所以错误的将它判断为Object);而对于引用类型,除了function之外返回的都是object。但当我们需要知道某个对象的具体类型时,typeof
就显得有些力不从心了。
typeof 1; // number 有效
typeof ‘ ’;//string 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof null; //object 无效
typeof new Function(); // function 有效
typeof [] ; //object 无效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效
2
3
4
5
6
7
8
9
10
# instanceof
当我们需要知道某个对象的具体类型时,可以用运算符 instanceof
,instanceof
操作符判断左操作数对象的原型链上是否有右边这个构造函数的prototype属性,也就是说指定对象是否是某个构造函数的实例,最后返回布尔值。 检测的我们用一段伪代码来模拟instanceof
内部执行过程。
function instan(a, b){
var L=a.__proto__;
var R=b.prototype;
if(L==R){
//a的__proto__指向b的原型对象
return true;
}
return false;
}
2
3
4
5
6
7
8
9
从上述过程可以看出,当 A 的 __proto__
指向 B 的 prototype
时,就认为A就是B的实例,我们再来看几个例子:
[] instanceof Array; //true
[] instanceof Object; //true
new Date() instanceof Date;//true
new Date() instanceof Object;//true
function Person(){};
new Person() instanceof Person;//true
new Person() instanceof Object;//true
2
3
4
5
6
7
instanceof
判断出[]时Array
的实例,同时它也认为[]是Object
的实例,这是因为instanceof
判断出[].__proto__
指向Array.prototype
,而Array.prototype.__proto__
又指向Object.prototype
,Object.prototype.__proto__
指向null,标志着原型链结束。[]、Array、Object三者的关系如下图所示:
注意:instanceof
运算符只能用于对象,不适用原始类型的值。
'hello' instanceof String // false
null instanceof Object // false
undefined instanceof Object // false
2
3
# constructor
constructor
属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的。
var f = new F();
f.constructor === F;// true
2
但是 constructor
属性易变,不可信赖,这个主要体现在自定义对象上,当开发者重写prototype
后,原有的constructor
会丢失。
function F() {}
F.prototype = {
_name: 'Eric',
};
var f = new F();
f.constructor === F; // false
2
3
4
5
6
因此,为了规范,在重写对象原型时一般都需要重新给constructor
赋值,以保证实例对象的类型不被改写。
function F() {}
F.prototype = {
constructor: F,
_name: 'Eric',
};
var f = new F();
f.constructor === F; // true
2
3
4
5
6
7
# Object.prototype.toString
toString
是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上所有对象的类型都可以通过这个方法获取到。
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object Window]
2
3
4
5
6
7
8
9
10
11
12
需要注意的是,必须通过Object.prototype.toString.call
来获取,而不能直接new Date().toString()
, 从原型链的角度讲,所有对象的原型链最终都指向了Object, 按照JS变量查找规则,其他对象应该也可以直接访问到Object的toString方法,而事实上,大部分的对象都实现了自身的toString方法,这样就可能会导致Object的toString被终止查找,因此要用call来强制执行Object的toString方法。