参考
Object.prototype.toString.call() 为什么有用?
JavaScript 的数据类型及其检测
一、js
类型
1. 分类
基本数据类型和引用数据类型
2. 基本数据类型
- Number
- Boolean
- Undefined
- Null
- String
- Symbol
特点:
① 存放在栈区:原始数据类型直接存储在栈中的简单数据段,其占据空间小、大小固定,属于被频繁使用的数据。
② 值的比较:==
只进行值的比较,在比较时会进行数据类型的隐式转换。===
不仅进行值的比较,还要进行数据类型的比较。
console.log(1==true)//true
console.log(1===true)//false
3. 引用数据类型
- 统称为
Object
,主要包括对象、数组和函数
特点
① 同时保存在栈内存和堆内存中:引用数据类型存储在堆中的对象有占据空间大、大小不固定的特点。如果存储在栈中,将会影响程序运行的性能。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
② 比较是引用的比较:当比较两个引用变量时,无论是==
还是===
,都比较的是两个变量的引用是否一致。(这里注意:当比较引用中的基本数据类型值时,==
仍为值比较,===
为带数据类型的值比较)
let obj1 ={
a:{
b:3
}
}
let obj2 = {
a:{
b:3
}
}
console.log(obj1.a.b==obj2.a.b)//true
console.log(obj1.a==obj2.a)//false
二、js
检查数据类型
1. typeof
typeof
返回一个表示数据类型的字符串,返回结果包括:string
、number
、boolean
、symbol
、undefined
、function
、object
。typeof
无法检测出null
和array
的类型,检测出来这两个都是object
。
typeof Symbol(); // symbol 有效
typeof ''; // string 有效
typeof 1; // number 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof new Function(); // function 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效
2. instanceof
instanceof
来判断A
是否是B
的实例:A instanceof B
instanceof
运算符来测试一个对象在其原型链中是否存在一个构造函数的prototype
属性。(A instanceof B
中,对象为A,构造函数为B)- 通过
instanceof
检测null
和undefined
都不是对象类型
[] instanceof Array // true
{} instanceof Object // true
new Date() instanceof Date // true
new RegExp() instanceof RegExp // true
Array.isArray([]); // true
instanceof
的三大弊端
① 对于基本数据类型来说,字面量方式创建出来的结果和实例方式创建出来的是有区别的。从严格意义上来讲,只有实例创建出来的结果才是标准的对象数据类型值,也是标准的 Number 这个类的一个实例;对于字面量方式创建出来的结果是基本的数据类型值,不是严谨的实例,但是由于 JS 的松散特点,导致了其可以使用 Number.prototype 上提供的方法。
console.log(1 instance of Number)//false
console.log(new Number(1) instanceof Number)//true
② 只要在当前实例的原型链上,我们用其检测出来的结果都是true
。但在类的原型继承中,我们最后检测出来的结果未必准确。
③ 对于特殊的数据类型null
和undefined
。他们所属的类是Null
和Undefined
。但是浏览器把这两个类保护起来了,不允许我们在外部访问
3. 严格运算符===
只能用于判断基本数据类型数据。
let aaaa = null;
let bbbb = null;
console.log(aaaa===bbbb)//true
let aaaa = undefined;
let bbbb = undefined;
console.log(aaaa===bbbb)//true
4. constructor
constructor
可以检测当前对象的直属类,而不能检测原型链上的所有。它还可以处理基本数据类型的检测
let arr = new Array();
console.log(arr.constructor===Array)//true
console.log(arr.constructor===Object)//false
console.log((1).constructor === Number)//true
console.log(reg.constructor=== RegExp);//true
弊端
① null
和undefined
是无效的对象,因此不会有constructor
存在的。
② 函数的constructor
不稳定,主要是类的原型重写时,在重写的过程中可能会把之前的constructor
覆盖掉,这样检测出来的结果是不准确的。
5. Object.prototype.toString.call()
Object
原型链上的toString
方法不是用来转换成字符串的。它的作用是返回当前方法执行的主体(方法中的this
)所属类的详细信息,即[object Object]
,其中第一个object
代表当前实例是对象数据类型的(这个是固定不变的),第二个object
代表的当前this
所属类的名称。- 所有类都是继承于
Object
类,故在创建所有类的实例时,理应来说可以调用到Object
原型对象的toString
方法。而除了Object
类的实例以外,其余的类调用toString
方法都是将其本身输出,这是因为所有类在继承Object
类时重写了toString
方法,故在调用时,调用的都是重写过后的toString
方法,而非Object
原型对象上的toString
方法。当把所有类上的重写后的toString
方法删除后,在通过该类实例调用toString
方法时,调用的便是Object
原型对象上的方法了(见例2)- 一般只有实例可以调用
toString
方法,但我们在实践中发现,1/true/"111"
也可以调用toString
方法,这是因为在调用该方法时,会将原始值包装成对象后再进行调用
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( newError()) ; // [object Error]
Object.prototype.toString.call( document) ; // [object HTMLDocument]
Object.prototype.toString.call( window) ; //[object global] window是全局对象global的引用
//例2
// 定义一个数组
var arr = [1, 2, 3]
// 数组原型上是否具有 toString() 方法
console.log(Array.prototype.hasOwnProperty('toString')) //true
// 数组直接使用自身的 toString() 方法
console.log(arr.toString()) // '1,2,3'
// delete操作符删除数组原型上的 toString()
delete Array.prototype.toString
// 删除后,数组原型上是否还具有 toString() 方法
console.log(Array.prototype.hasOwnProperty('toString')) //false
// 删除后的数组再次使用 toString() 时,会向上层访问这个方法,即 Object 的 toString()
console.log(arr.toString()) // '[object Array]'