JavaScript_类型
JavaScript 是一种动态类型语言,变量没有静态类型,但值有类型。理解 JavaScript 的类型系统及其判断方式是编写高质量代码的基础。
一、JavaScript 数据类型分类
1. 基本类型(Primitive Types)
- 数值(Number):包括整数和浮点数,如
42
、3.14
- 字符串(String):文本值,如
"hello"
- 布尔值(Boolean):
true
或false
- 空值(Null):只有一个值
null
,表示有意为空 - 未定义(Undefined):变量声明但未赋值时的默认值
- 符号(Symbol):ES6 新增,唯一且不可变的值
- 大整数(BigInt):ES2020 新增,用于表示任意大的整数
2. 引用类型(Reference Types)
- 对象(Object):最基本的引用类型
- 数组(Array):有序的数据集合
- 函数(Function):可执行的代码块
- 日期(Date):处理日期和时间
- 正则表达式(RegExp):处理文本模式匹配
- 其他内置对象:如 Map、Set、WeakMap、WeakSet 等
二、类型判断方法
1. typeof 操作符
- 适用场景:基本类型(除
null
)和函数 - 局限性:无法区分对象、数组、日期等引用类型
typeof 42; // "number"
typeof 'hello'; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof Symbol(); // "symbol"
typeof 123n; // "bigint"
typeof function () {}; // "function"
// 特殊情况
typeof null; // "object"(历史遗留问题)
typeof []; // "object"
typeof new Date(); // "object"
typeof /abc/; // "object"
2. instanceof 操作符
- 适用场景:判断对象是否是某个构造函数的实例
- 局限性:无法判断基本类型,且受原型链影响
[] instanceof Array; // true
[] instanceof Object; // true(数组继承自 Object)
new Date() instanceof Date; // true
new Date() instanceof Object; // true
// 基本类型使用 instanceof 无效
'hello' instanceof String; // false(基本类型不是对象)
new String('hello') instanceof String; // true(包装对象)
3. Object.prototype.toString.call()
- 适用场景:精确判断所有内置类型
- 返回格式:
[object Type]
,其中Type
是具体类型
Object.prototype.toString.call(42); // "[object Number]"
Object.prototype.toString.call('hello'); // "[object String]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(Symbol()); // "[object Symbol]"
Object.prototype.toString.call(123n); // "[object BigInt]"
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call({}); // "[object Object]"
Object.prototype.toString.call(new Date()); // "[object Date]"
Object.prototype.toString.call(function () {}); // "[object Function]"
Object.prototype.toString.call(/abc/); // "[object RegExp]"
Object.prototype.toString.call(new Map()); // "[object Map]"
4. Array.isArray()
- 适用场景:专门判断是否为数组
- 等价于:
Object.prototype.toString.call(value) === '[object Array]'
Array.isArray([]); // true
Array.isArray({}); // false
Array.isArray(new Array()); // true
5. 自定义类型检查函数
- 适用场景:封装常用类型判断逻辑
function isNumber(value) {
return typeof value === 'number' && !isNaN(value);
}
function isString(value) {
return typeof value === 'string';
}
function isNull(value) {
return value === null;
}
function isUndefined(value) {
return value === undefined;
}
function isNullOrUndefined(value) {
return value === null || value === undefined;
}
function isObject(value) {
return value !== null && typeof value === 'object';
}
function isPlainObject(value) {
return Object.prototype.toString.call(value) === '[object Object]';
}
6. ES6+ 新增方法
- Number.isNaN():判断是否为
NaN
(比全局isNaN
更严格) - Number.isFinite():判断是否为有限数
- Number.isInteger():判断是否为整数
- String.prototype.isPrototypeOf():判断是否为字符串原型
Number.isNaN(NaN); // true
Number.isNaN('NaN'); // false(全局 isNaN 会返回 true)
Number.isFinite(42); // true
Number.isFinite(Infinity); // false
Number.isInteger(42); // true
Number.isInteger(3.14); // false
三、类型判断的注意事项
1. 包装对象与基本类型
typeof new String('hello'); // "object"
typeof 'hello'; // "string"
// 推荐使用基本类型进行比较
'hello' === 'hello'; // true
new String('hello') === new String('hello'); // false(不同对象引用)
2. 跨窗口/iframe 对象
instanceof
在跨窗口环境中可能失效,因为每个窗口有自己的构造函数- 推荐使用
Array.isArray()
或Object.prototype.toString.call()
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const array = iframe.contentWindow.Array;
const arr = new array();
arr instanceof Array; // false(不同窗口的 Array 构造函数)
Array.isArray(arr); // true
Object.prototype.toString.call(arr); // "[object Array]"
3. 类数组对象
- 类数组对象有
length
属性但没有数组方法 - 常见类数组:
arguments
、DOM 节点列表
function test() {
console.log(Array.isArray(arguments)); // false
console.log(Object.prototype.toString.call(arguments)); // "[object Arguments]"
}
四、面试高频问题
JavaScript 有哪些数据类型?
答:JavaScript 分为基本类型(Number、String、Boolean、Null、Undefined、Symbol、BigInt)和引用类型(Object、Array、Function 等)。如何准确判断一个变量是否为数组?
答:推荐使用Array.isArray()
或Object.prototype.toString.call(value) === '[object Array]'
。避免使用typeof
,因为它对数组返回"object"
。typeof null 为什么返回 "object"?
答:这是 JavaScript 语言的历史遗留问题。早期 JavaScript 内部用标记位表示类型,null
的标记位与对象相同,导致误判。instanceof 和 Object.prototype.toString.call() 的区别是什么?
答:instanceof
检查对象是否是某个构造函数的实例,受原型链影响Object.prototype.toString.call()
返回对象的内部类型标签,更精确- 跨窗口环境中,
instanceof
可能失效,而Object.prototype.toString.call()
依然可靠
如何判断一个值是 NaN?
答:使用Number.isNaN()
而不是全局isNaN()
。Number.isNaN()
只对真正的NaN
返回true
,而全局isNaN()
会将无法转换为数字的值(如字符串)也视为NaN
。
五、实用工具函数
以下是一个综合的类型判断工具库示例:
const TypeUtils = {
isNumber(value) {
return typeof value === 'number' && !isNaN(value);
},
isString(value) {
return typeof value === 'string';
},
isBoolean(value) {
return typeof value === 'boolean';
},
isNull(value) {
return value === null;
},
isUndefined(value) {
return value === undefined;
},
isNullOrUndefined(value) {
return value === null || value === undefined;
},
isObject(value) {
return value !== null && typeof value === 'object';
},
isPlainObject(value) {
return Object.prototype.toString.call(value) === '[object Object]';
},
isArray(value) {
return Array.isArray(value);
},
isFunction(value) {
return typeof value === 'function';
},
isDate(value) {
return Object.prototype.toString.call(value) === '[object Date]';
},
isRegExp(value) {
return Object.prototype.toString.call(value) === '[object RegExp]';
},
isSymbol(value) {
return typeof value === 'symbol';
},
isBigInt(value) {
return typeof value === 'bigint';
},
isNaN(value) {
return Number.isNaN(value);
},
isFinite(value) {
return Number.isFinite(value);
},
isInteger(value) {
return Number.isInteger(value);
},
isEmpty(value) {
if (this.isNullOrUndefined(value)) return true;
if (this.isArray(value) || this.isString(value)) return value.length === 0;
if (this.isPlainObject(value)) return Object.keys(value).length === 0;
return false;
},
};
总结
JavaScript 的类型系统既灵活又复杂,掌握正确的类型判断方法至关重要。在实际开发中,推荐根据场景选择合适的判断方式:
- 基本类型判断:优先使用
typeof
- 数组判断:使用
Array.isArray()
- 精确类型判断:使用
Object.prototype.toString.call()
- 自定义类型:使用
instanceof
或类的静态方法
避免常见的类型判断陷阱,如 typeof null
的误判、包装对象与基本类型的混淆,以及跨窗口环境下的 instanceof
失效问题。通过合理运用类型判断技术,可以编写出更健壮、更安全的 JavaScript 代码。