文章目录
-
- [1. typeof 操作符](#1. typeof 操作符)
-
- [typeof null 为什么是 object](#typeof null 为什么是 object)
- [2. `instanceof` 操作符](#2.
instanceof
操作符) - [3. `Object.prototype.toString.call()`(最准确的)](#3.
Object.prototype.toString.call()
(最准确的)) - [4. Array.isArray()](#4. Array.isArray())
- [5. `constructor` 属性](#5.
constructor
属性) - 总结
在JavaScript中,有多种方法可以用来检测数据类型。每种方法都有其特定的用途和局限性。下面是几种常用的类型检测方法及其特点:
1. typeof 操作符
typeof
可以用来检测基本数据类型(除了null
和undefined
之间的区分)。
- 优点:简单易用。
- 缺点:无法准确区分
null
,数组
,对象
,都会返回"object"
。其他判断都正确
js
console.log(typeof ½); // "number"
console.log(typeof 'str'); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object"
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function(){}); // "function"
typeof null 为什么是 object
在最初的 JS 实现中,typeof
操作符的设计目的是返回一个字符串,指示未经计算的操作数的类型。然而,在处理null
时,由于null
最初被设计为表示"无对象",因此将其类型视为 "object"
。这个决定导致了typeof null
返回 "object"
解决办法
- 使用严格相等运算符(
===
)
js
if (value === null) {
console.log("这是一个 null");
}
- 使用
Object.prototype.toString.call()
这是最准确的方法,可以明确地区分 null 与其他类型。
js
if (Object.prototype.toString.call(value) === "[object Null]") {
console.log("这是一个 null");
}
- 自定义类型检查
写一个函数用来检测
js
function getType(value) {
if (value === null) {
return "null";
}
return typeof value;
}
console.log(getType(null)); // "null"
console.log(getType(42)); // "number"
console.log(getType("hello")); // "string"
2. instanceof
操作符
instanceof
用来检查一个对象在其原型链中是否存在一个构造函数的prototype
属性
- 优点:可以用来区分不同的引用类型。
- 缺点:不能用来检测基础类型。跨iframe使用时可能会出现问题。
js
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log(function(){} instanceof Function); // true
3. Object.prototype.toString.call()
(最准确的)
这是最可靠的一种类型检测方法,可以准确地区分所有类型,包括基础类型和引用类型。
使用Object
对象的原型方法toString
方法来判断
优点:非常准确,支持所有类型。
缺点:语法稍微复杂一点。
- 基本类型
js
console.log(Object.prototype.toString.call(1)); // "[object Number]"
console.log(Object.prototype.toString.call('str')); // "[object String]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(BigInt(123456789012345678901234567890n))); // "[object BigInt]"
- 引用类型
js
console.log(Object.prototype.toString.call({})); // "[object Object]"
console.log(Object.prototype.toString.call([])); // "[object Array]"
console.log(Object.prototype.toString.call(function() {})); // "[object Function]"
console.log(Object.prototype.toString.call(new Date())); // "[object Date]"
console.log(Object.prototype.toString.call(new RegExp("abc"))); // "[object RegExp]"
console.log(Object.prototype.toString.call(new Map())); // "[object Map]"
console.log(Object.prototype.toString.call(new Set())); // "[object Set]"
console.log(Object.prototype.toString.call(new WeakMap())); // "[object WeakMap]"
console.log(Object.prototype.toString.call(new WeakSet())); // "[object WeakSet]"
console.log(Object.prototype.toString.call(new Error())); // "[object Error]"
- 特殊对象
js
console.log(Object.prototype.toString.call(Math)); // "[object Math]"
console.log(Object.prototype.toString.call(JSON)); // "[object JSON]"
console.log(Object.prototype.toString.call(Promise.resolve())); // "[object Promise]"
- 自定义检测方法 -便捷使用
js
function getType(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
console.log(getType(42)); // "number"
console.log(getType("Hello, World!")); // "string"
console.log(getType(true)); // "boolean"
console.log(getType(undefined)); // "undefined"
console.log(getType(null)); // "null"
console.log(getType(Symbol("symbol"))); // "symbol"
console.log(getType({})); // "object"
console.log(getType([])); // "array"
console.log(getType(function() {})); // "function"
console.log(getType(new Date())); // "date"
console.log(getType(new RegExp("abc"))); // "regexp"
console.log(getType(new Map())); // "map"
console.log(getType(Promise.resolve())); // "promise"
4. Array.isArray()
专门用于检测是否为数组。
优点:简单明了,专用于数组检测。
缺点:只能用于数组。
js
console.log(Array.isArray([])); // true
console.log(Array.isArray({})); // false
5. constructor
属性
通过检查对象的constructor
属性来确定其构造函数。
优点:可以用于大多数引用类型。
缺点:constructor
对象访问它的构造函数,如果创建一个对象改变它的原型,则可能不准确。对于基础类型无效。
js
console.log((2).constructor == Number); //true
console.log((true).constructor == Boolean); //true
console.log(("string").constructor == String); //true
console.log(([]).constructor === Array); // true
console.log(({}).constructor === Object); // true
console.log((function(){}).constructor === Function); // true
// 改变原型之后
function Fn(){}
Fn.prototype = new Array();
var f= new Fn();
console.log(f.constructor === Fn);//false
console.log(f.constructor === Array);//true
总结
- 对于基础类型,推荐使用 typeof 或 Object.prototype.toString.call()。
- 对于引用类型,尤其是需要区分具体类型时,Object.prototype.toString.call() 是最佳选择。
- 如果只需要判断是否为数组,Array.isArray() 是最直接的方法。
- instanceof 在某些情况下也很有用,特别是当你需要检查对象是否是由特定构造函数创建的时候。