详解typeof与instanceOf

本文探讨了JavaScript中typeof和instanceof操作符的区别,讲述了如何正确获取数据类型,包括typeof的常见结果、null的特殊情况,以及instanceof在检测构造函数原型的应用。重点介绍了如何通过toString方法和getDataType函数获取准确的数据类型信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

typeof

typeof 操作符返回一个字符串,表示未经计算的操作数的类型。

语法: typeof 运算符后接操作数:
typeof operand
typeof(operand)

参数:
operand:一个表示对象或原始值的表达式,其类型将被返回。

下表总结了 typeof 可能的返回值。

类型结果
Undefined“undefined”
Null“object” (见下文)
Boolean“boolean”
Number“number”
BigInt(ECMAScript 2020 新增)“bigint”
String“string”
Symbol (ECMAScript 2015 新增)“symbol”
宿主对象(由 JS 环境提供)取决于具体实现
Function 对象 (按照 ECMA-262 规范实现 [[Call]])“function”
其他任何对象“object”

typeof null

// JavaScript 诞生以来便如此
typeof null === 'object';

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 "object"

使用 new 操作符

// 除 Function 外的所有构造函数的类型都是 'object'
var str = new String('String');
var num = new Number(100);

typeof str; // 返回 'object'
typeof num; // 返回 'object'

var func = new Function();

typeof func; // 返回 'function'

正则表达式
对正则表达式字面量的类型判断在某些浏览器中不符合标准:

typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1
typeof /s/ === 'object'; // Firefox 5+ , 符合 ECMAScript 5.1

错误
在 ECMAScript 2015 之前,typeof 总能保证对任何所给的操作数返回一个字符串。即便是没有声明的标识符,typeof 也能返回 'undefined'。使用 typeof 永远不会抛出错误。

if(typeof a!="undefined"){}

但在加入了块级作用域的 letconst 之后,在其被声明之前对块中的 letconst 变量使用 typeof 会抛出一个 ReferenceError。块作用域变量在块的头部处于“暂存死区”,直至其被初始化,在这期间,访问变量将会引发错误。

typeof undeclaredVariable === 'undefined';

typeof newLetVariable; // ReferenceError
typeof newConstVariable; // ReferenceError
typeof newClass; // ReferenceError

let newLetVariable;
const newConstVariable = 'hello';
class newClass{};

typeof 各类数据 结果

ValueClassType
“foo”Stringstring
new String(“foo”)Stringobject
1.2Numbernumber
new Number(1.2)Numberobject
trueBooleanboolean
new Boolean(true)Booleanobject
new Date()Dateobject
new Error()Errorobject
[1,2,3]Arrayobject
new Array(1, 2, 3)Arrayobject
new Function("")Functionfunction
/abc/gRegExpobject (function in Nitro/V8)
new RegExp(“meow”)RegExpobject (function in Nitro/V8)
{}Objectobject
new Object()Objectobject
nullNullobject
undefinedUndefinedundefined
BigInt(123)Bigintbigint
Symbol()Symbolsymbol

上面表格中,Type 一列表示 typeof 操作符的运算结果。可以看到,这个值在大多数情况下都返回 “object”。

Class 一列表示对象的内部属性 [[Class]] 的值。

JavaScript 标准文档中定义: [[Class]] 的值只可能是下面字符串中的一个: Arguments, Array, Boolean, Date, Error, Function, JSON, Math, Number, Object, RegExp, String,Symbol,Bigint

结论:
typeof几乎不可能得到它们想要的结果。

instanceof

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

语法: object instanceof constructor
参数: object(某个实例对象)constructor(某个构造函数)
描述: instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。

instanceof 只有在比较自定义的对象时才有意义。 如果用来比较内置类型,将会和 typeof 操作符 一样用处不大。

比较自定义对象

function Foo() {}
function Bar() {}
Bar.prototype = new Foo();
new Bar() instanceof Bar; // true, new Bar().__proto__ === Bar.prototype
new Bar() instanceof Foo; // true, new Bar().__proto__.__proto__ === Foo.prototype

// 如果仅仅设置 Bar.prototype 为函数 Foo 本身,而不是 Foo 构造函数的一个实例
Bar.prototype = Foo;
new Bar() instanceof Foo; // false, new Bar().__proto__.__proto__ !== Foo.prototype

instanceof 比较内置类型

new String('foo') instanceof String; // true, new String('foo').__proto__ === String.prototype
new String('foo') instanceof Object; // true, new String('foo').__proto__.__proto__ === Object.prototype
'foo' instanceof String; // false, 'foo'不为对象
'foo' instanceof Object; // false,'foo'不为对象

有一点需要注意,instanceof 用来比较属于不同 JavaScript 上下文的对象(比如,浏览器中不同的文档结构)时将会出错, 因为它们的构造函数不会是同一个对象。

// 定义构造函数
function C(){}
function D(){}

var o = new C();


o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype


o instanceof D; // false,因为 D.prototype 不在 o 的原型链上

o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true
C.prototype instanceof Object // true,同上

C.prototype = {};
var o2 = new C();

o2 instanceof C; // true

o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上.

D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为 C.prototype 现在在 o3 的原型链上

需要注意的是,如果表达式 obj instanceof Foo 返回 true,则并不意味着该表达式会永远返回 true,因为 Foo.prototype 属性的值有可能会改变,改变之后的值很有可能不存在于 obj 的原型链上,这时原表达式的值就会成为 false。另外一种情况下,原表达式的值也会改变,就是改变对象 obj 的原型链的情况,虽然在目前的ES规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的 _proto_ 伪属性,是可以实现的。比如执行 obj._proto_ = {} 之后,obj instanceof Foo 就会返回 false 了。

正确获取数据类型

JavaScript 标准文档只给出了一种获取上文 [[Class]] 值的方法,那就是使用 Object.prototype.toString

Object.prototype.toString 返回一种标准格式字符串,

Object.prototype.toString.call([])  // "[object Array]"
Object.prototype.toString.call({})  // "[object Object]"
Object.prototype.toString.call(2)  // "[object Number]"

所以可以通过 slice 截取指定位置的字符串,如下所示:

Object.prototype.toString.call([]).slice(8, -1); // Array

上面例子中,Object.prototype.toString 方法被调用,this 被设置为了需要获取 [[Class]] 值的对象。

为了更加明确地检查类型,将typeof 在生产级代码中使用的包装器如下:

/**
 * @param data 必填 需要获取类型的数据
 * @param { boolean } isGetfullClass 选填 是否获取完整数据类型结构
 **/
function getDataType(data, isGetfullClass) {
	
  // get toPrototypeString() of data (handles all types)
  // Early JS environments return '[object Object]' for null, so it's best to directly check for it.
  if (isGetfullClass) {
      return (data === null) ? '[object Null]' : Object.prototype.toString.call(data);
  }
  if (data == null) { return (data + '').toLowerCase(); } // implicit toString() conversion

  var deepType = Object.prototype.toString.call(data).slice(8,-1).toLowerCase();
  if (deepType === 'generatorfunction') { return 'function' }

  // Prevent overspecificity (for example, [object HTMLDivElement], etc).
  // Account for functionish Regexp (Android <=2.3), functionish <object> element (Chrome <=57, Firefox <=52), etc.
  // String.prototype.match is universally supported.

  return deepType.match(/^(arguments|array|bigint|boolean|date|error|function|json|math|number|generator|regexp|symbol|object)$/) ? deepType :
     (typeof data === 'object' || typeof data === 'function') ? 'object' : typeof data;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

定栓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值