JavaScript类型判断:typeof与Object.prototype.toString详解

作者:纸飞机时间:2026-10-27 16:41:00浏览:646

本文详解JavaScript中两种主流类型判断方法。首先分析typeof的局限性,指出其对Object、Array等返回object的问题。随后深入讲解Object.prototype.toString.call()的原理,结合ES3与ES5规范对比[[Class]]内部属性的变化,展示如何准确区分Array、Function、Date等复杂类型,并提供最佳实践建议。

typeof 类型判断及其局限性

typeof(param) 用于返回参数 param 的数据类型字符串。

这是 JavaScript 语言内置的全局函数,也是开发者最常用的类型检测手段。其优势在于语法简洁、易于记忆;但主要缺陷在于无法准确区分 object、null、array、regexp 以及自定义对象,这些类型通常都会返回 "object"。

以下代码展示了 typeof 对不同变量的检测结果。

代码如下:

var str='str';
var arr=['1','2'];
var num=1;
var bool=true;
var obj={name:'test'};
var nullObj=null;
var undefinedObj=undefined;
var reg=/reg/;
function fn(){
 alert('this is a function');
}
function User(name){
 this.name=name;
}
var user=new User('user');
console.log(typeof(str));
console.log(typeof(arr));
console.log(typeof(num));
console.log(typeof(bool));
console.log(typeof(obj));
console.log(typeof(nullObj));
console.log(typeof(undefinedObj));
console.log(typeof(reg));
console.log(typeof(fn));
console.log(typeof(user));

运行上述代码后,控制台输出结果如下。


代码如下:

string
object
number
boolean
object
object
undefined
object
function
object

2、Object.prototype.toString().call(param) 返回 param 的类型(字符串格式为 [object class])。

Object.prototype.toString 原理与规范演进

该方法能够覆盖绝大多数基础类型的判断,jQuery 库中封装的类型判断逻辑也基于此方法。部分读者可能对后续内容感到困惑,下面我们将逐步拆解其原理。

1)call(param) 函数机制

在 JavaScript 中,a.fun().call(b) 的含义是让对象 b 临时替代对象 a 执行 a 的 fun 函数。通过以下示例进行说明:

代码如下:

function Class1()
{ 
this.name = "class1";
this.showNam = function() 
 { 
 alert(this.name); 
 } 
}
function Class2() 
{ 
 this.name = "class2"; 
}
var c1 = new Class1(); 
var c2 = new Class2();
c1.showNam.call(c2);

运行结果输出 "class2" 而非 "class1",这体现了方法借用或类似继承的效果。


因此,Object.prototype.toString().call(param) 的本质是将 param 作为 this 执行 toString 方法。为什么不直接写 param.prototype.toString()?这是因为普通对象可能没有 prototype 属性或该方法被重写,下面通过第 2 点详细解释。

2)Object.prototype.toString() 的作用

Object 是所有 JavaScript 对象的基类,提供了所有对象通用的功能。根据官方文档(如 Script56.chm),Object 是一个概念性的祖先,所有 JS 对象都是 Object 的实例,但不同对象会重写自己的方法。prototype 属性返回原型的引用,允许动态向原型添加方法和属性。以下是一个简单示例:

代码如下:

function class(){
this.name = "class";
this.showName = function(){
alert(this.name);
  }
}
var obj = new class();
obj.showName();
class.prototype.showNameContact = function(){
alert("prototype test"+this.name);
}
obj.showNameContact();

上述代码分别输出 "class" 和 "prototype test class"。构造函数 class() 内部并未定义 showNameContact,但通过 prototype 动态添加后,new 出的实例即可调用。因此,Object.prototype.toString() 指的是执行 Object 基类中的 toString 方法。

那么toString()是干嘛的呢?很多js手册中对toString()函数是这样定义的: toString() 方法可把一个逻辑值转换为字符串,并返回结果,语法为:booleanObject.toString()。刚才我说了,js中的对象都是继承的Object,这些对象都自定义的有函数或者重构了Object的部分函数,而且它们都对toString()函数进行了重写。所以我们不能想1中直接写param.prototype.toString()这样就执行的是param自己重写后的toString()函数了。

接下来进入核心部分:toString() 的具体作用及其返回值机制。

在 ES3 规范中,Object.prototype.toString 方法的执行步骤如下:

Object.prototype.toString()

当调用 toString 方法时,执行以下步骤:

1. 获取 this 对象的 [[Class]] 内部属性的值。

2. 将字符串 "[object "、第一步的结果 Result(1) 以及 "]" 连接成新字符串。

3. 返回第二步生成的字符串 Result(2)。

ES3 规范未明确列出 [[class]] 的所有可能值,但统计原生对象的 [[Class]] 内部属性值共有 10 种:"Array", "Boolean", "Date", "Error", "Function", "Math", "Number", "Object", "RegExp", "String"。因此,Object.prototype.toString() 的输出格式为 [object Array]、[object Boolean] 等。

在 ES5.1 规范中,定义更加详细,Object.prototype.toString 方法和 [[Class]] 内部属性的定义有所变化,具体规范如下:

Object.prototype.toString ( ) 当调用 toString 方法时,执行以下步骤:

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

与 ES3 相比,ES5.1 增加了第 1、2、3 步。其中第 1、2 步属于新增规则,较为特殊,因为 "Undefined" 和 "Null" 并非 [[class]] 属性的标准值。经统计,可返回的类型包括 "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", "String"。相比 ES3,新增了两种类型:arguments 对象的 [[Class]] 变为 "Arguments"(此前为 "Object"),以及新增的全局对象 JSON,其 [[Class]] 值为 "JSON"。

最后提醒,Object.prototype.toString().call(param) 返回的 [object class] 中 class 部分首字母大写,如 "JSON" 全大写。为避免大小写敏感问题,建议在判断时将结果转换为小写,即使用 Object.prototype.toString().call(param).toLowerCase()。

作者最新文章