js中对数据类型的总结及判断数据类型的各种方法及优缺点

js 中的数据类型

js 中只有六种原始数据类型和一个Object:

  • Boolean
  • Null
  • Undefined
  • Number
  • String
  • Symbol (ECMAScript 6 新定义)
  • Object

大家认真记清这个描述,不要到时候把 Array、Date 都当成 js 的数据类型就尴尬了。那可能会有人问,那 Array 和 Date 算什么呢,他们都属于 Object,看下面分类:

Object 分类

Object 分为本地对象内置对象宿主对象三种

本地对象

定义:独立于宿主环境的 ECMAScript 实现提供的对象。简单的说就是 ECMA 定义的类。他们包括:

1
2
3
4
Object   Function   Array   String
Boolean Number Date RegExp
Error EvalError RangeError ReferenceError
SyntaxError TypeError URIError

所以 Array 和 Date 都属于对象类型,它们是本地对象。


疑问:

1.有人可能会问,为什么 String 也是 Object 类型,上面不是说了是原始类型吗?
答:原始类型中有字符串 String 不错,它只是表达了一种数据类型,但数据类型也有自己的类定义啊,是吧,上面的 String 说的就是它的类型定义,是个对象,所以当然也是引用类型了。其他同理。
看下面 demo

1
2
3
4
5
6
7
8
9
var str1 = "hello";
var str2 = new String("hello");
typeof str1; //string
typeof str2; //object

//如果想获取str2的字符串,可以通过str2.toString()

str1 instanceof String; //false
str2 instanceof String; //true

内置对象

定义:“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已经被实例化了。
内置对象只有两个GlobalMath,他们其实也是本地对象,根据定义每个内置对象都是本地对象。

宿主对象

所有非本地对象都是宿主对象,即由 ECMAScript 实现的宿主环境提供的对象。所有BOMDOM对象都是宿主对象。


typeof

最常见的判断方法:typeof,它的官方解释

typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
简单理解就是typeof是判断的是原始类型(值类型),但函数返回的是function,null 返回的也是object

1
2
3
typeof Undefined; //'undefined'
var num;
typeof num; //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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var str1="hello";
var str2=new String("hello");
var arr=[1,2,3];
function person(){}
function man(){}
man.prototype=new person();
var m1=new person();
var m2=new man();

str1 instanceof String //false
str2 instanceof String //true
arr instanceof Array //true
arr instanceof window.frames[0].Array //false
m1 instanceof person //true
m2 instanceof man //true
m2 intanceof person //true

优缺点列表

优点 缺点
判断对象的具体类型 只能判断对象,对原始类型不能判断
多全局对象时返回不正确

多全局对象解释

简单来说:多全局对象就是跨窗口或跨 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
alert(c.constructor === Array) ----------> true
alert(d.constructor === Date) -----------> true
alert(e.constructor === Function) -------> true
注意: constructor 在类继承时会出错
eg:
function A(){};
function B(){};
A.prototype = new B(); //A继承自B
var aObj = new A();
alert(aobj.constructor === B) -----------> true;
alert(aobj.constructor === A) -----------> false;
instanceof方法不会出现该问题,对象直接继承和间接继承的都会报true
alert(aobj instanceof B) ----------------> true;
alert(aobj instanceof B) ----------------> true;
言归正传,解决construtor的问题通常是让对象的constructor手动指向自己:
aobj.constructor = A; //将自己的类赋值给对象的constructor属性
alert(aobj.constructor === A) -----------> true;
alert(aobj.constructor === B) -----------> false; //基类不会报true了;

缺点:继承的对象判断时,不准确。感觉鸡肋。

最靠谱的方法: Object.prototype.toString.call(obj)

  • 这种方法不存在多全局环境和 Array、null 返回 object 的情况,
  • 原始类型和原始类型对应的引用类型声明的变量都能返回正确的值
  • 但是这个方法对自定义类型无效,自定义类型返回的都是Object,所以自定义时还是使用instanceof
1
2
3
4
5
6
7
8
9
10
11
var str1 = "hello";
var str2 = new String("hello");
var arr = [1, 2, 3];
function Man() {}
var man = new Man();
Object.prototype.toString.call(str1); //[object String]
Object.prototype.toString.call(str2); //[object String]
Object.prototype.toString.call(arr); //[object Array]
Object.prototype.toString.call(man); //[object Object]
Object.prototype.toString.call(null); //[object Null]
Object.prototype.toString.call(/test/); //[object RegExp]
优点 缺点
不存在多全局环境问题 只能判断本地对象和宿主对象
原始类型无论是字面量语法声明还是通过对应的引用类型声明都能正确判断 自定义类型都返回[object Object]

jquery.type()

就是对 prototype 的封装。源码附上:

1
2
3
4
5
type: function( obj ) {
return obj == null ?
String( obj ) :
class2type[ toString.call(obj) ] || "object";
},

对数组的判断

1
2
3
4
5
6
var arr = [1, 2, 3];
typeof arr; //object 分辨不出类型
arr instanceof Array; //true //受多全局环境影响
Object.prototype.toString.call(arr); //[object Array] //推荐
Array.isArray(arr); //true //推荐
$.type(arr); //array //推荐

终极解决方法

使用Object.prototype.toString().call()

1
2
var arr = [];
Object.prototype.toString().call(arr);
文章作者: wenmu
文章链接: http://blog.wangpengpeng.site/2020/02/28/js%E4%B8%AD%E5%AF%B9%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%80%BB%E7%BB%93%E5%8F%8A%E5%88%A4%E6%96%AD%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%90%84%E7%A7%8D%E6%96%B9%E6%B3%95%E5%8F%8A%E4%BC%98%E7%BC%BA%E7%82%B9/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 温木的博客
微信打赏