js 中的数据类型
js 中只有六种
原始数据类型和一个Object
:
- Boolean
- Null
- Undefined
- Number
- String
- Symbol (ECMAScript 6 新定义)
- Object
大家认真记清这个描述,不要到时候把 Array、Date 都当成 js 的数据类型就尴尬了。那可能会有人问,那 Array 和 Date 算什么呢,他们都属于 Object,看下面分类:
Object 分类
Object 分为本地对象、内置对象和宿主对象三种
本地对象
定义:独立于宿主环境的 ECMAScript 实现提供的对象。简单的说就是 ECMA 定义的类。他们包括:
1 | Object Function Array String |
所以 Array 和 Date 都属于对象类型,它们是本地对象。
疑问:
1.有人可能会问,为什么 String 也是 Object 类型,上面不是说了是原始类型吗?
答:原始类型中有字符串 String 不错,它只是表达了一种数据类型,但数据类型也有自己的类定义啊,是吧,上面的 String 说的就是它的类型定义,是个对象,所以当然也是引用类型了。其他同理。
看下面 demo
1 | var str1 = "hello"; |
内置对象
定义:“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已经被实例化了。
内置对象只有两个Global
和Math
,他们其实也是本地对象,根据定义每个内置对象都是本地对象。
宿主对象
所有非本地对象都是宿主对象,即由 ECMAScript 实现的宿主环境提供的对象。所有
BOM
和DOM
对象都是宿主对象。
typeof
最常见的判断方法:typeof,它的官方解释:
typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
简单理解就是typeof
是判断的是原始类型(值类型),但函数返回的是function
,null 返回的也是object
1 | typeof Undefined; //'undefined' |
typeof 各类型返回结果列表
类型 | 结果 |
---|---|
Undefined | “undefined” |
Null | “object” |
Boolean | “boolean” |
Number | “number” |
String | “string” |
Symbol (ECMAScript 6 新增) | “symbol” |
宿主对象(由 JS 环境提供) | Implementation-dependent |
函数对象([[Call]] 在 ECMA-262 条款中实现了) | “function” |
任何其他对象 | “object” |
为什么 typeof null 是 object
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签也成为了 0,typeof null 就错误的返回了”object”。
typeof 优缺点列表
优点 | 缺点 |
---|---|
判断原始类型比较方便 | null 返回的是 object |
方法返回的是 function | |
所有的引用类型都返回 object,Array、Date 等不能准确定位 |
instanceof
定义:“instanceof 运算符用来测试一个对象(第一个参数)在其原型链中是否存在一个构造函数(第二个参数)的 prototype 属性。”
简单理解就是:instanceof 是判断两个对象“最近”prototype 是否一样。
另外,instanceof 是判断对象是否属于某一类型,而不是获取的对象的类型。
1 | var str1="hello"; |
优缺点列表
优点 | 缺点 |
---|---|
判断对象的具体类型 | 只能判断对象,对原始类型不能判断 |
多全局对象时返回不正确 |
多全局对象解释
简单来说:多全局对象就是跨窗口或跨 frame 操作。
全局环境
在浏览器中,我们的脚本可能需要在多个窗口之间进行交互。多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。
这可能会引发一些问题。
比如,表达式 [] instanceof window.frames[0].Array 会返回 false,因为 Array.prototype !== window.frames[0].Array.prototype,因此你必须使用 Array.isArray(myObj) 或者 Object.prototype.toString.call(myObj) === “[object Array]”来判断 myObj 是否是数组。
根据对象的 constructor 判断
1 | alert(c.constructor === Array) ----------> true |
缺点:继承的对象判断时,不准确。感觉鸡肋。
最靠谱的方法: Object.prototype.toString.call(obj)
- 这种方法不存在多全局环境和 Array、null 返回 object 的情况,
- 原始类型和原始类型对应的引用类型声明的变量都能返回正确的值
- 但是这个方法对自定义类型无效,自定义类型返回的都是
Object
,所以自定义时还是使用instanceof
。
1 | var str1 = "hello"; |
优点 | 缺点 |
---|---|
不存在多全局环境问题 | 只能判断本地对象和宿主对象 |
原始类型无论是字面量语法声明还是通过对应的引用类型声明都能正确判断 | 自定义类型都返回[object Object] |
jquery.type()
就是对 prototype 的封装。源码附上:
1 | type: function( obj ) { |
对数组的判断
1 | var arr = [1, 2, 3]; |
终极解决方法
使用Object.prototype.toString().call()
1 | var arr = []; |