JavaScript 类型判断

·  阅读 85

这是我参与更文挑战的第 23 天,活动详情查看:更文挑战

目前JavaScript 总共有八种数据类型,其中七种属于基本数据类型,也称为原始类型,分别是numberbigintstringbooleannullundefinedsymbol。还有一种复杂数据类型是object

typeof 运算符

typeof 运算符用于返回参数的类型,有两种使用方式:typeOf xtypeOf(x),这两种使用方式得到的结果是一样的,都以字符串的形式返回数据的类型。

typeof undefined // "undefined"
typeof 0 // "number"
typeof 10n // "bigint"
typeof true // "boolean"
typeof "foo" // "string"
typeof Symbol("id") // "symbol"
typeof alert // "function"

typeof null // "object"
typeof Math // "object"
typeof [] // "object"
复制代码

typeof 运算符可以准确识别 6 种基本类型和function类型,但是无法识别null类型。事实上functionobject类型的子类型,而nullobject类型没有关系,typeof的这个行为错误属于JavaScript语言的早期错误,考虑到兼容性而保留了下来。

根据类型转换相关知识,nullundefined的判断(即判断数据为空时)通常使用非严格相等(==)运算符,如下所示:

let a = null;
let b = undefined;
a == null;  // true
a == undefined; // true
b == null;  // true
b == undefined; // true
复制代码

而在实际项目中,我们常常需要判断数据是否是特殊的对象类型,比如数组、正则表达式、日期等等,就需要使用Object.prototype.toString方法了。

Object.prototype.toString

根据规范20.1.3.6Object.prototype.toString的逻辑如下所示:

  1. If the this value is undefined, return "[object Undefined]".
  2. If the this value is null, return "[object Null]".
  3. Let O be ! ToObject(this value).
  4. Let isArray be ? IsArray(O).
  5. If isArray is true, let builtinTag be "Array".
  6. Else if O has a [[ParameterMap]] internal slot, let builtinTag be "Arguments".
  7. Else if O has a [[Call]] internal method, let builtinTag be "Function".
  8. Else if O has an [[ErrorData]] internal slot, let builtinTag be "Error".
  9. Else if O has a [[BooleanData]] internal slot, let builtinTag be "Boolean".
  10. Else if O has a [[NumberData]] internal slot, let builtinTag be "Number".
  11. Else if O has a [[StringData]] internal slot, let builtinTag be "String".
  12. Else if O has a [[DateValue]] internal slot, let builtinTag be "Date".
  13. Else if O has a [[RegExpMatcher]] internal slot, let builtinTag be "RegExp".
  14. Else, let builtinTag be "Object".
  15. Let tag be ? Get(O, @@toStringTag).
  16. If Type(tag) is not String, set tag to builtinTag.
  17. Return the string-concatenation of "[object ", tag, and "]".

简单来说就是Object.prototype.toString可以判断以下几种类型:

let toString = Object.prototype.toString;

toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]
toString.call([1,2,3]); // [object Array]

function func() {
    console.log(toString.call(arguments)); // [object Arguments]
}
func();
toString.call(func); // [object Function]

toString.call(new Error()); // [object Error]
toString.call(true); // [object Boolean]
toString.call(123); // [object Number]
toString.call('LvLin'); // [object String]
toString.call(new Date()); // [object Date]
toString.call(/LvLin/g);  // [object RegExp]
// 如果不是以上几种类型,就返回 [object Object]
toString.call({}); // [object Object]
复制代码

Object.prototype.toString在遇到所述几种类型时,会返回相应的值 ([object xxx]),如果不是那几种类型,就返回[object Object]

但是看一下下面这个:

let map = new Map()
toString.call(map); // [object Map]
复制代码

为什么不是[object Object]呢?这就需要看规范 15~17 描述的规则,这里稍微进行一下解释:

  1. tag = O[Symbol.toStringTag]
  2. 如果 tag 不是 String 类型(如果对象 O 没定义 Symbol.toStringTag,得到的是 undefined),那tag = builtinTagbuiltinTag 参考自规则 1 ~ 14)
  3. 返回 [object tag]

即如果判断的对象定义了Symbol.toStringTag,并且是字符串类型,就以这个值为结果,否则就让tag = builtinTag,以这个值为结果,最后返回[object tag]

console.log(map[Symbol.toStringTag]); // "Map"

let name = {
    [Symbol.toStringTag]: 'LvLin'
}
console.log(toString.call(name))  // [object LvLin]

name[Symbol.toStringTag] = {};
console.log(toString.call(name)) // [object Object]
复制代码

最后再看几个类型:

toString.call(Math) // [object Math] 
toString.call(JSON) // [object JSON]
toString.call(new Set()) // [object Set]

let a = BigInt(123);
Object.prototype.toString.call(a); // [object BigInt]
a[Symbol.toStringTag]; // "BigInt"
复制代码

总结

当前(2021 年)JavaScript数据类型总共有 8 种,通过使用typeof运算符和Object.prototype.toString方法进行类型判断。

typeof 能够确定numberbigintstringbooleanundefinedsymbolfunction七种类型,其余返回object(包括null)。

Object.prototype.toString方法能够判断更加细致的类型,优先返回的是对象定义的Symbol.toStringTag值,如果该值不是字符串类型,返回相关规则对应的值。可以通过Symbol.toStringTag自定义对象被该方法调用的返回值。

都看到这了,如果文章对你有帮助,点个赞呗~

参考资料

现代 JavaScript 教程——数据类型

JavaScript专题之类型判断(上)

ECMA 规范 20.1.3.6

分类:
前端
分类:
前端
收藏成功!
已添加到「」, 点击更改