Skip to content

JavaScript类型检查的完整指南

JavaScript的动态类型是其最强大的特性之一。然而,对于经验不足的开发人员来说,它经常是问题和困惑的根源。因此,类型检查是任何JavaScript开发人员的关键技能。

值类型

在我们深入探讨JavaScript中不同的类型检查方式之前,让我们先看一下我们在JavaScript中可能遇到的不同值类型

类型 描述 示例
undefined 尚未分配值的变量的值。 let x;
null 任何对象值的有意缺失。 const x = null;
boolean 逻辑值,要么是true,要么是false const x = true;
number 数值。 const x = 50;
bigint 具有任意精度的整数。 const x = 9007199254740991n;
string 字符串序列。 const x = 'Hello!';
symbol 可用作对象属性键的唯一值。 const x = Symbol();
object 属性的集合。 const x = { a: 1, b: 2 };
function 可调用的对象。 const x = () => {};

除了最后两种类型,所有其他类型都被视为原始类型。原始类型是不可变的,这意味着它们的值不能被改变。而对象和函数则是可变的,这意味着它们的值可以被改变。

检查原始类型

与对象和函数相比,原始类型通常更容易进行类型检查。这是因为原始类型是不可变的,这意味着它们的值不能被改变。因此,我们可以简单地将一个值的类型与我们要检查的类型进行比较。这就是typeof运算符派上用场的地方。

值是undefined

检查undefined值就像将该值与undefined进行比较一样简单。这与使用typeof运算符得到的结果完全相同。

const isUndefined = val => val === undefined;

isUndefined(undefined); // true

值为null

检查null值只能通过将值与null本身进行比较。这是因为typeof null返回'object',这不是我们想要的。

const isNull = val => val === null;

isNull(null); // true

值为nil

在其他一些语言中,使用nil值来表示缺少值。然而,在JavaScript中,nullundefined用于此目的。因此,检查nil值与检查nullundefined值是相同的。

const isNil = val => val === undefined || val === null;

isNil(null); // true
isNil(undefined); // true
isNil(''); // false

值是布尔类型

布尔值只能是truefalse。检查这两个值相对低效,所以通常更倾向于使用typeof

const isBoolean = val => typeof val === 'boolean';

isBoolean(true); // true
isBoolean(false); // true
isBoolean('true'); // false
isBoolean(null); // false

值是数字类型

数字也可以使用typeof进行类型检查。然而,这也会对NaN返回trueNaN是一个特殊的数值,表示无法产生正常结果的操作的结果。

你可以阅读更多关于NaN以及为什么它可能很棘手,但通常建议使用Number.isNaN()来额外检查NaN

const isNumber = val => typeof val === 'number' && !Number.isNaN(val);

isNumber(1); // true
isNumber('1'); // false
isNumber(NaN); // false

值是大整数类型

BigInt是JavaScript中相对较新的添加。它们是具有任意精度的整数。使用typeof对BigInt进行类型检查。

const isBigInt = val => typeof val === 'bigint';

isBigInt(1n); // true
isBigInt(1); // false

值是字符串

像大多数其他原始类型一样,字符串原始类型可以使用typeof进行类型检查。

const isString = val => typeof val === 'string';

isString('Hello!'); // true
isString(1); // false

值是符号

符号是可以用作对象属性键的唯一值。它们也可以使用typeof进行类型检查。

const isSymbol = val => typeof val === 'symbol';

isSymbol(Symbol('x')); // true
isSymbol('x'); // false

值是原始类型

检查一个值是否是任何原始类型有点棘手。我们不能简单地使用typeof来判断,因为它对null不起作用。

相反,我们可以从值创建一个对象,然后将其与值本身进行比较。如果值是原始类型,对象将不等于值。

const isPrimitive = val => Object(val) !== val;

isPrimitive(null); // true
isPrimitive(undefined); // true
isPrimitive(50); // true
isPrimitive('Hello!'); // true
isPrimitive(false); // true
isPrimitive(Symbol()); // true
isPrimitive([]); // false
isPrimitive({}); // false

检查非原始类型

对象和函数的行为与原始类型略有不同。虽然typeof可以帮助我们一部分,但我们可能还想使用其他方法,特别是对于对象。

值是对象

如前所述,typeof对于null返回'object'。这不是我们想要的,当我们检查对象时。相反,我们可以使用Object构造函数为给定的值创建一个对象包装器。如果值是nullundefined,返回的值将是一个空对象。否则,返回的对象将与输入对象相同。

const isObject = obj => obj === Object(obj);

isObject([1, 2, 3, 4]); // true
isObject([]); // true
isObject(['Hello!']); // true
isObject({ a: 1 }); // true
isObject({}); // true
isObject(true); // false
isObject(null); // false
isObject(undefined); // false

[!TIP]

在JavaScript中,数组也被视为对象。建议使用Array.isArray()检查一个值是否为数组

值是函数

幸运的是,函数并不像对象那样棘手。我们可以简单地使用typeof来检查一个值是否为函数。

const isFunction = val => typeof val === 'function';

isFunction(x => x); // true
isFunction('x'); // false

[!NOTE]

在JavaScript中,也被视为函数。您可能希望使用instanceof运算符来检查一个值是否为类的实例。

值是异步函数

使用async关键字声明的函数被视为异步函数。对于异步函数的类型检查,需要使用Object.prototype.toString()Function.prototype.call()来检查结果是否为'[object AsyncFunction]'

const isAsyncFunction = val =>
  Object.prototype.toString.call(val) === '[object AsyncFunction]';

isAsyncFunction(function() {}); // false
isAsyncFunction(async function() {}); // true

值是生成器函数

生成器函数可以像异步函数一样进行类型检查。它们的预期值是'[object GeneratorFunction]'

const isGeneratorFunction = val =>
  Object.prototype.toString.call(val) === '[object GeneratorFunction]';

isGeneratorFunction(function() {}); // false
isGeneratorFunction(function*() {}); // true

值的类型

如果其他方法都失败了,或者你正在使用类和其他自定义类型,你可能想要获取一个值的类型的字符串表示。可以使用Object.prototype.constructorFunction.prototype.name来实现。

const getType = v =>
  v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name;

getType(undefined); // 'undefined'
getType(null); // 'null'
getType(true); // 'Boolean'
getType(1); // 'Number'
getType(1n); // 'BigInt'
getType('Hello!'); // 'String'
getType(Symbol()); // 'Symbol'
getType([]); // 'Array'
getType({}); // 'Object'
getType(() => {}); // 'Function'
getType(new Set([1, 2, 3])); // 'Set'

检查值的类型

将前面的代码片段反过来,我们也可以检查一个值是否是特定类型。与之前一样,对于undefinednull需要特别注意,因为它们没有constructor属性。

const isOfType = (type, val) =>
  ([undefined, null].includes(val) && val === type) ||
  val.constructor.name === type;

isOfType(undefined, undefined); // true
isOfType(null, null); // true
isOfType('Boolean', true); // true
isOfType('Number', 1); // true
isOfType('BigInt', 1n); // true
isOfType('String', 'Hello!'); // true
isOfType('Symbol', Symbol()); // true
isOfType('Array', []); // true
isOfType('Object', {}); // true
isOfType('Function', () => {}); // true
isOfType('Set', new Set([1, 2, 3])); // true