Skip to Content

面试导航 - 程序员面试题库大全 | 前端后端面试真题 | 面试

Javascript类型判断

在 JavaScript 中,有 7 种内置类型,分别是:

  • 空值 (null)
  • 未定义 (undefined)
  • 布尔值 (boolean)
  • 数字 (number)
  • 字符串 (string)
  • 对象 (object)
  • 符号 (symbol)

严格来说,JavaScript 有 6 种原始类型(值类型):

  • 空值 (null)
  • 未定义 (undefined)
  • 布尔值 (boolean)
  • 数字 (number)
  • 字符串 (string)
  • 符号 (symbol)

此外,还有一个特殊的原始类型:

  • 任意精度整数 (BigInt),用于表示大于 Number 范围的整数。

这些原始类型是不可变的,而 Object 类型是复杂类型,可以包含多个值。

什么是 typeof

typeof 是 JavaScript 中的一个运算符,用来检查一个变量的类型。它会返回一个字符串,表示给定值的类型。

接下来我们使用 typeof 运算符来查看值的类型,它返回的是类型的字符串值。有意思的是,这七种类型和它们的字符串值并不一一对应:

console.log(typeof 777); // number console.log(typeof 3.14); // number console.log(typeof 0); // number console.log(typeof Infinity); // number console.log(typeof Number('moment')); // number console.log(typeof 77n); // bigint console.log(typeof '1'); // string console.log(typeof typeof 1); // string typeof 返回一个字符串 console.log(typeof String(777)); // string console.log(typeof true); // boolean console.log(typeof false); // boolean console.log(typeof Boolean(5)); // boolean // Boolean() 会基于参数是真值还是虚值进行转换 typeof !!1 === 'boolean'; // 两次调用 !(逻辑非)运算符相当于 Boolean() console.log(typeof Symbol()); // symbol console.log(typeof Symbol('foo')); // symbol console.log(typeof Symbol.iterator); // symbol console.log(typeof { a: 1 }); // object console.log(typeof [1, 2, 4]); // object console.log(typeof new Date()); // object console.log(typeof /regex/); // object console.log(typeof null); // object console.log(typeof function () {}); // function console.log(typeof class T {}); // function

你可能注意到 null 类型比较特殊,typeof null==='object',正确的返回应该是'null',但是这个 bug 由来已久,在JavaScript中已经存在了将近二十年,也许永远不会修复。

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

console.log(typeof function () {}); // function

在上面的代码中,输出结果为 'function',说明 function 也是JavaScript 的一个内置类型。然而规范里,它实际上是 object 的一个 子类型。具体来说,函数是 可调用对象,它有一个内部属性 [[call]] ,该属性使其可以被调用。

function f() {} console.log(f.__proto__.constructor === Function); // true console.log(f.__proto__.__proto__.constructor === Object); // true // 函数不仅是对象,还可以拥有属性 console.log(f.name); // f console.log(f.arguments); // 因为没有传参数,所以是一个 null

通过原型的方法去判别,函数确实是 Object 的子类。

再来看看数组,JavaScript支持数组,数组也是对象,确切涞水,它也是 object 的一个 子类型,数组的元素按数字顺序来进行索引,其 length 属性是元素的个数。

const foo = []; console.log(foo.__proto__.constructor === Array); // true console.log(foo.__proto__.__proto__.constructor === Object); // true

new 操作符

  • 所有使用  new  调用的构造函数都将返回非基本类型,返回的不是object 类型,就是  function。大多数返回对象,但值得注意的例外是  Function,它返回一个函数。
const str = new String('777'); const num = new Number(777); const func = new Function(); console.log(typeof str); // object console.log(typeof num); // object console.log(typeof func); // function

undefined 和 undeclared

  • 变量在未持有值的时候为 undefined。此时 typeof 返回 undefined:
var a; console.log(tyoeof a); // undefined

大多数的开发者倾向于将 undefined 等同于 undeclared(未声明),但在 JavaScript中它们完全是两回事。在作用域中声明但是还没有赋值的变量,是 undefined。相反,还没有在作用域中声明过的变量,是undeclared 的。

在上列中, bar is not defined容易让人误以为是 bar is undefined。但是 undefinedis undefined 是两码事,但是 typeof 处理 undeclared 返回的结果竟然是 undefined,例如:

var foo; console.log(typeof foo); // undefined console.log(typeof bar); // undefined

它们两个原样返回 "undefined",并且 typeof bar 并没有报错,这是因为 typeof 有一个特殊的安全防范机制。

内部属性 [[class]]

在前面的例子中,使用 typeof 进行判断,无论是 nullObjectArray等类型,都返回的是 "object",那么是否有一种机制可以判断它具体为什么类型的值呢?答案是有的。

所有 typeof 返回值为 object 的对象(如数组)都包含一个内部属性 [[class]],我们可以把它看作一个内部的分类,而非传统的面向对象意义上的类。这个属性无法直接访问,一般通过 Object.prototype.toString(...) 来查看。例如:

console.log(Object.prototype.toString.call([1, 2, 3])); // [object Array] console.log(Object.prototype.toString.call(1)); // [object Number] console.log(Object.prototype.toString.call('moment')); //[object String] console.log(Object.prototype.toString.call(true)); //[object Boolean] console.log(Object.prototype.toString.call(null)); // [object Null] console.log(Object.prototype.toString.call(undefined)); // [object Undefined] console.log(Object.prototype.toString.call(function f() {})); // [object Function] console.log(Object.prototype.toString.call(class C {})); // [object Function] console.log(Object.prototype.toString.call(new Date())); // [object Date] console.log(Object.prototype.toString.call(Symbol())); // [object Symbol] console.log(Object.prototype.toString.call(new Boolean(1))); // [object Boolean] console.log(Object.prototype.toString.call(new RegExp())); // [object RegExp]

上例中,数组内部[[class]]属性值是 Array,正则表达式的值是 RegExp。多数情况下,对象的内部 [[class]] 属性和创建该对象的内建原生构造函数相对应,但并不是所有的情况都是这样,例如一些基本类型,例如 nullundefined,虽然 Null()undefined() 这样的原生构造函数并不存在,但是内部 [[class]] 属性值仍然是 NullUndefined

其他基本类型,例如 字符串、数值和布尔值 的情况有所不同,由于基本类型值没有 .length.toString() 这样的属性和方法,需要通过封装对象才能访问,此时 JavaScript 会自动为基本类型封装为一个对象,例如 var foo = 'moment';,实际上进行的是 var foo =new String('moment'); ,使其变成一个对象,让其拥有自己的属性和方法,如果想要得到封装对象中的基本类型值,可以使用 valueOf() 函数,例如:

var foo = new String('moment'); console.log(foo); // [String: 'moment'] console.log(foo.valueOf()); // moment console.log(typeof foo.valueOf()); // string

手写 typeof

typeof  是非常有用的,但它不像需要的那样万能。例如,typeof []  是  "object",以及  typeof new Date()typeof /abc/  等。

为了明确地检查类型, mdn 上提供了一个自定义的 type(value) 函数,它主要模仿  typeof  的行为,但对于非基本类型(即对象和函数),它在可能的情况下返回更详细的类型名。

function type(value) { // 如果传入的值是 null ,则返回 null if (value === null) { return 'null'; } const baseType = typeof value; // 如果是基本类型 if (!['object', 'function'].includes(baseType)) { return baseType; } // Symbol.toStringTag 通常指定对象类的“display name” const tag = value[Symbol.toStringTag]; if (typeof tag === 'string') { return tag; } // 如果他是一个函数,其源代码以 class 关键字开头的 if (baseType === 'function' && Function.prototype.toString.call(value).startsWith('class')) { return 'class'; } // 构造函数的名称;例如 `Array`、`GeneratorFunction`、`Number`、`String`、`Boolean` 或 `MyCustomClass` const className = value.constructor.name; if (typeof className === 'string' && className !== '') { return className; } // 没有合适的方法来获取值的类型,直接返回 return baseType; }

参考文献

总结

typeof 运算符用于检查变量的类型,返回一个表示数据类型的字符串。对于基本类型(如 numberstring 等),返回值明确,但对于对象类型(如 null、数组、正则表达式等),typeof 都返回 "object",这导致一些特殊情况。为了解决这种模糊判断问题,可以通过 Object.prototype.toString.call() 来精确判断对象的实际类型。此外,typeof 无法判断数组、null 和类等,需要额外的处理。

最后更新于:
Copyright © 2025Moment版权所有粤ICP备2025376666