数据类型概况
在JS里面数据类型可以分成两种:
- 基础数据类型:string,number,boolean,undefined,null和Symbol
- 引用数据类型:Object(其中Object又包括Array,RegExp,Date,Math,Function)
为什么会有基础数据类型和引用数据类型?
这是因为它们两种数据类型存储在不同的内存中,因此上面的数据类型分成两类来存储:
- 基础数据类型存储在栈内存中,被引用或拷贝时,会创建一个完全相等的变量
- 引用数据类型在栈内存里有指向堆内存的内存地址,多个引用可能指向同一个内存地址,从而数据也发生了共享
var a={
name:'张三',
age:'18'
}
var b=a
console.log(a.name) //'张三'
b.name='李四'
console.log(a.name) //'李四'
console.log(b.name) //'李四'
我们改变了b.name之后,a.name也随着发生了改变,这是因为a是引用数据类型,声明的变量b直接等于a,b直接引用a的内存地址
var a={
name:'张三',
age:'18'
}
var b=foo(a)
function foo(data){
data.name:'李四'
data={
name:'王五',
age:19
}
return data
}
console.log(a) //{name:'李四',age:18}
console.log(b) //{name:'王五',age:19}
在这个例子中,我们可以看到a传给了foo函数,在foo函数里我们改变了它的name属性,在函数里面的data.name还是和a.name引用同一个内存地址,因此name属性值被改变了。但是b变量的值等于一个函数的返回值,return返回的是一个新的对象,开辟了一块新的内存地址。
数据类型检测
方法一:typeof
typeof 1 //'number'
typeof '1' //'string'
typeof undefined //'undefined'
typeof true //'boolean'
typeof Symbol() //'symbol'
typeof null //'object'
typeof [] //'object'
typeof {} //'object'
typeof console //'object'
typeof console.log //'function'
typeof Function //'function'
typeof Array //'function'
在以上例子可以看出,基本数据类型使用typeof可以精准的检测出来(null除外),对于引用数据类型不能准确检测出来
方法二:instanceof
我们通过new实例化构造函数,创建一个新的对象,这个新对象继承来构造函数的方法,通过原型链向上可以找到,而instanceof就可以判断出这个对象是不是由之前的构造函数创建出来的对象,这样就可以判断出新对象的数据类型
var Car=function(){}
var car=new Car()
car instanceof Car //true
var a=new String('abc')
a instanceof String //true
var str='abc'
str instanceof String //false
由上面的代码可知,car是通过实例化Car这个构造函数创建出来的对象,因此car能够使用instanceof向上找到自己的构造函数原型Car;a通过new String() 实例化出来的字符串,因此也在String的原型上;但是对于简单数据类型的检测,instanceof 是无法做到的
//手写instanceof
function myInstanceOf(obj,type){
//如果obj不为对象或者为null,则不能检测
if(typeof obj!=='object'||object===null) return false
var proto=Object.getPrototypeOf(obj)
while(true){
if(proto===null) return false
else if(proto===type.prototype) return true
proto=Object.getPrototypeOf(proto)
}
}
myInstanceOf(new String('abc'),String) //true
myInstanceOf(123,Number) //false
方法三:Object.prototype.toSring.call(obj) toSting()是Object原型上的方法,调用方法,返回字符串'[object Xxx]',Xxx就是对象的类型。对于Object对象,直接调用toString()方法,就会返回'[object Object]',但是对于其他类型,需要通过call()方法来调用,才能返回正确信息。
Object.prototype.toString({}) // "[object Object]"
Object.prototype.toString.call(123) // "[object Number]"
Object.prototype.toString.call('') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/123/g) //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"
Object.prototype.toString.call([]) //"[object Array]"
Object.prototype.toString.call(document) //"[object HTMLDocument]"
Object.prototype.toString.call(window) //"[object Window]"
注意typeof检测出来出来的类型,首字母是小写的,而使用toString()方法检测出来的对象类型'Xxx',首字母是大写
那么如何直接取出检测出来的类型?
我们可以直接使用Object.prototype.toString.call(obj).slice(8,-1)可以直接得到。