JavaScript数据类型判断
确定一个值是哪种基本类型可以使用
typeof
操作符,而确定一个值是哪种引用类型可以使用instanceof
操作符。
1、typeof
typeof()
表示“获取变量的数据类型”,返回的是小写,语法为:
// 写法1
typeof 变量;
// 写法2
typeof(变量);
typeof 这个运算符的返回结果就是变量的类型。返回结果的类型是是字符串。
返回结果:
typeof 的代码写法 | 返回结果 |
---|---|
typeof 数字 | "number" |
typeof 字符串 | "string" |
typeof 布尔型 | "boolean" |
typeof 对象 | "object" |
typeof 方法 | "function" |
typeof null | "object" |
typeof undefined | "undefined" |
typeof NaN | "number" |
!> ⚠️ 1:为什么 typeof null
的返回值也是 "object"
呢?因为 null 代表的是空对象。
⚠️ 2:typeof NaN
的返回值是 "number"
。NaN是一个特殊的数字,表示Not a Number,非数值。NaN 是一个特殊的数字。Undefined和任何数值计算的结果为 NaN。NaN 与任何值都不相等,包括 NaN 本身。
返回结果举例:
console.log(typeof []); // 空数组的打印结果:object
console.log(typeof {}); // 空对象的打印结果:object
代码解释:这里的空数组[]
、空对象{}
,为啥他们在使用 typeof 时,返回值也是 object
呢?因为这里的 返回结果object
指的是引用数据类型。空数组、空对象都是引用数据类型 Object。
因此,在使用typeof
运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,都会返回"object"
,要想区别内置对象如Array、Date等,单纯使用 typeof 是不行的,JavaScript通过Object.prototype.toString
方法,可以检测对象类型。
小结:
使用 typeof 来判断数据类型,只能区分基本类型,即
“number”,”string”,”undefined”,”boolean”,”object”,“function”
六种。
2、Object.prototype.toString.call()
每个对象都有一个 toString()
方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString()
方法被每个 Object
对象继承。如果此方法在自定义对象中未被覆盖,toString()
返回 “[object type]”,其中 type
是对象的类型。
可以通过 toString()
来获取每个对象的类型。为了每个对象都能通过 Object.prototype.toString()
来检测,需要以 Function.prototype.call()
或者 Function.prototype.apply()
的形式来调用,传递要检查的对象作为第一个参数,称为 thisArg
。
原型链的概念
我们都知道js中的对象都继承自Object
,所以当我们在某个对象上调用一个方法时,会先在该对象上进行查找,如果没找到则会进入对象的原型(也就是.prototype
)进行查找,如果没找到,同样的也会进入对象原型的原型进行查找,直到找到或者进入原型链的顶端Object.prototype
才会停止。
所以,当我们使用arr.toString()
时,不能进行复杂数据类型的判断,因为它调用的是Array.prototype.toString
,虽然Array
也继承自Object
,但js在Array.prototype
上重写了toString
,而我们通过toString.call(arr)
实际上是通过原型链调用了Object.prototype.toString
。
判断对象的类型示例:
console.log(Object.prototype.toString.call("tom"));//[object String]
console.log(Object.prototype.toString.call(17));//[object Number]
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({name: "tom"}));//[object Object]
console.log(Object.prototype.toString.call(function(){}));//[object Function]
console.log(Object.prototype.toString.call([]));//[object Array]
console.log(Object.prototype.toString.call(new Date));//[object Date]
console.log(Object.prototype.toString.call(/\d/));//[object RegExp]
function Person(){};
console.log(Object.prototype.toString.call(new Person));//[object Object]
// 判断原生JSON对象
var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON);
console.log(isNativeJSON);//输出结果为:[object JSON] ,说明JSON是原生的,否则不是;
对于自定义类型,Object.prototype.toString
方法不能准确判断一个实例是否属于某种类型,因此引入instanceof
运算符进行判断。
//自定义类型
function Person(name, age) {
this.name = name;
this.age = age;
}
var person = new Person("Rose", 18);
Object.prototype.toString.call(person); // 打印 "[object Object]"
console.log(person instanceof Person); // 打印 true
参考引用:
3、instanceof
instanceof
运算符用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链。
原理:判断实例对象的proto属性与构造函数的 prototype 是不是用一个引用。如果不是,他会沿着对象的proto向上查找的,直到顶端 Object。
通常来讲,使用 instanceof 就是判断一个实例是否属于某种类型。例如:
// 判断 foo 是否是 Foo 类的实例
function Foo(){};
var foo = new Foo();
console.log(foo instanceof Foo) // 输出 true
更重要的一点是 instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型。例如:
// 判断 foo 是否是 Foo 类的实例 , 并且是否是其父类型的实例
function Aoo(){}
function Foo(){}
Foo.prototype = new Aoo(); // JavaScript 原型继承
var foo = new Foo();
console.log(foo instanceof Foo) // 输出 true
console.log(foo instanceof Aoo) // 输出 true
在多层继承关系中,instanceof 运算符同样适用。
instanceof 复杂用法(JavaScript 原型继承机制)
instanceof检测的是原型,用一段代码模拟一下内部执行过程:
instanceof (A,B) = {
var L = A.__proto__;
var R = B.prototype;
if(L === R) {
//A的内部属性__proto__指向B的原型对象
return true;
}
return false;
}
以下为几个示例:
console.log([] instanceof Array); // true
console.log([] instanceof Object) // true
console.log(Object instanceof Object);//true
console.log(Function instanceof Function);//true
console.log(Function instanceof Object);//true
console.log(Number instanceof Number);//false
console.log(String instanceof String);//false
console.log(Foo instanceof Function);//true
从上边的示例可以发现,虽然 instanceof 能够判断出 [ ] 是Array的实例,但它认为 [ ] 也是Object的实例,从 instanceof 能够判断出 [].__proto__
指向 Array.prototype
,而 Array.prototype.__proto__
又指向了Object.prototype
,最终 Object.prototype.__proto__
指向了null,标志着原型链的结束。因此,[]、Array、Object 就在内部形成了一条原型链。
JavaScript 原型链
因此,==instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。==
在浏览器中,我们的脚本可能需要在多个窗口之间进行交互。多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。这可能会引发一些问题。比如,表达式 [] instanceof window.frames[0].Array
会返回 false
,因为 Array.prototype !== window.frames[0].Array.prototype
,并且数组从前者继承。
当你在你的脚本中开始处理多个 frame 或多个 window 以及通过函数将对象从一个窗口传到另一个窗口时,比如,你可以通过使用Array.isArray(myObj)
或者Object.prototype.toString.call(myObj) === "[object Array]"
来安全的检测传过来的对象是否是一个数组。
支持 Array.isArray()方法的浏览器有 IE9+、 Firefox 4+、 Safari 5+、 Opera 10.5+和 Chrome。
当检测Array实例时, Array.isArray
优于 instanceof
,因为Array.isArray能检测iframes
。
参考引用:
4、constructor
constructor 属性返回对创建此对象的数组函数的引用。
语法:
object.constructor
示例:
function Person(){
this.name = name;
}
var p = new Person('Joe');
console.log(p.constructor === Person); //true
console.log(p.__proto__ === Person.prototype); //true