JavaScript数据类型的判定

js数据类型

基本类型

因为我们可以操作保存在变量中的实际的值,所以这些类型是按值访问的

  • String
  • Number
  • Boolean
  • Null
  • Undefined

引用类型

引用类型的值是保存在内存中的对象
在操作对象时,事实上是在操作对象的引用,而不是实际的对象
因此可以说引用类型的值是按引用访问(地址指针)

  • Object

# Undefined 类型
Undefined 类型只有一个值——undefined
值得注意的是:包含 undefined 值的变量与尚未定义的变量还是不一样的,如下

var message; // 声明时默认取得了 undefined 值
// 下面这个变量没有声明
// var age;
alert(message); // "undefined"
alert(age); // 报错

但如果对 age(未声明变量) 使用 typeof 的话,也会返回 undefined

# Null 类型
类似 Undefined,Null 类型也是只有一个值——null。
null表示一个空对象指针,因此当使用 typeof null 时,会返回“object”
事实上,undefined 是派生自 null 值得,因此有如下判断时返回 true

alert(null == undefined); // true

只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存 null 值。
这样做不仅可以体现 null 作为空对象指针的惯例,而且有助于进一步区分 null 和 undefined。

typeof 操作符

typeof 可以检测原始值类型,也就是基本类型。

alert( typeof "abc" === "string" ); // true
alert( typeof 123 === "number" ); // true
alert( typeof true === "boolean" ); // true
alert( typeof undefined === "undefined" ); // true
alert( typeof null === "null" ); // true

但是,但基本类型,在相同值的情况下,如果是利用构造函数来定义的话,typeof 返回的结果都只会是 object

alert( typeof new String("abc") ); // "object"
alert( typeof new Number(123) ); // "object"
alert( typeof new boolean(true) ); // "object"

因此,typeof 具有局限性。

typeof 只有一个实际的应用——检测一个对象是否已经定义或者是否已经赋值。而不是检查对象的类型。

instanceof 区别引用类型

对于引用类型的数据,单纯使用 typeof 是无法达到目的的。所以,要用 instanceof 操作符来区别数组、函数和对象

// 对象
(a instanceof Object) && !(a instanceof Array) && !(a instanceof Function)
// 函数
(a instanceof Object) && (a instanceof Function)
// 数组
(a instanceof Object) && (a instanceof Array)

但 instanceof 也有它严重的局限性:不能跨帧使用。

假设一个浏览器帧A(frame A)里的一个对象被传入到帧B(frame B)中,两个帧中都定义了 Person 构造函数,如果来自帧A 的对象是帧A 中Person的实例,则有:

personA instanceof frameAPerson   //true
personA instanceof frameBPerson   //false

因为每个帧都有 Person 的拷贝,它被认为是该帧中的Person的拷贝实例,尽管两个定义是一样的。
同样的问题也出现在其他两个非常重要的内置类型中:数组和函数,所以检测这两个内置类型一般不用 instanceof。
而且 instanceof 对于对象的整个原型链都能检测到,例如:

var now = new Date();
 
now instanceof Date;    //true
now instanceof Object;  //true

因此,用 instanceof 检测某一对象是否属于特定类型并非最佳。

仅仅用来比较来自同一个 JavaScript 上下文的自定义对象。正如 typeof 一样,避免其他的用途。

使用内置对象的 class 属性来判断

使用 Object.prototype.toString.call() 来判断

[[Class]]是一个内部属性,所有的对象(原生对象和宿主对象)都拥有该属性,通过该属性的值可以用来判断一个原生对象属于哪种内置类型,而这个属性只能通过Object.prototype.toString 方法来访问

在 ES5 中,对于 toString() 方法被调用时,执行的步骤如下:

  1. 如果this的值为undefined,则返回”[object Undefined]”
  2. 如果this的值为null,则返回”[object Null]”
  3. 让O成为调用ToObject(this)的结果
  4. 让class成为O的内部属性[[Class]]的值
  5. 返回三个字符串”[object “, class, 以及 “]”连接后的新字符串

所以判断变量类型的方法可以如下:

// 直接传入待判定变量和匹配类型
// 返回布尔值
function isType(data, type) {
return Object.prototype.toString.call(data).slice(8,-1) === type ? true : false;
}
// 直接传入某个变量
// 返回该变量的类型
function getType(data) {
return Object.prototype.toString.call(data).slice(8,-1);
}