JavaScript 中的变量类型判断方法及其应用

156 阅读4分钟

JavaScript 在变量声明时无需指定类型,但我们在使用时肯定免不了要判断变量的类型,比如实现一个加法函数 add(a, b),变量是数字还是字符串,最后的结果就很不一样,因此我们经常要做的是对输入数据进行合法性校验,不合法直接抛出错误,对于编写健壮的代码至关重要。

1、typeof 操作符

typeof是JavaScript中用于获取变量类型的操作符,它返回一个表示变量类型的字符串,返回值包括:

"undefined"、"string"、"boolean"、"number"、"bigint"、"symbol"、"object" 、 "function"。

let undefinedVar;
let stringVar = "Hello, World!";
let booleanVar = true;
let numberVar = 42;
let bigintVar = 1234567890123456789012345678901234567890n;
let symbolVar = Symbol("example");
let objectVar = { key: "value" };
let functionVar = function() { console.log("This is a function"); };

// 使用 typeof 操作符获取变量类型
console.log(typeof undefinedVar);  // 输出: "undefined"
console.log(typeof stringVar);     // 输出: "string"
console.log(typeof booleanVar);    // 输出: "boolean"
console.log(typeof numberVar);     // 输出: "number"
console.log(typeof bigintVar);     // 输出: "bigint"
console.log(typeof symbolVar);     // 输出: "symbol"
console.log(typeof objectVar);     // 输出: "object"
console.log(typeof functionVar);   // 输出: "function"

//typeof null 返回 "object"
let nullVar = null;
console.log(typeof nullVar);   

但是空类型 null 用 typeof 判断不出来,据说这是 JavaScript 当年的设计者引入的一个 Bug,由于兼容性的考虑一代代传承了下来。

但我们可以不使用 typeof来简单地判断 null:

let a =null;
console.log(a===null)//true

简单总结一下,typeof 可以准确判断除null之外的原始类型,也可以判断引用类型中的function,但无法判断对象和数组等其他引用类型。

2、instanceof 操作符

instanceof是通过原型链的查找来判断的,只能判断引用类型,它的工作原理是检查对象的原型链,看是否能找到指定构造函数的prototype。但是它不能准确判断基本数据类型,因为基本数据类型的变量不是对象,也没有原型链。

function MyObject(value) {
  this.value = value;
}

let obj1 = new MyObject(10);
let obj2 = {};
let arr = [1, 2, 3];
let num = 42;
let str = "Hello, World!";
let bool = true;
let nullValue = null;
let undefinedValue;

console.log(obj1 instanceof MyObject); // 输出: true,因为 obj1 是 MyObject 的实例
console.log(obj2 instanceof Object);   // 输出: true
console.log(arr instanceof Array);     // 输出: true
console.log(obj1 instanceof Array);    // 输出: false

// 尝试使用 instanceof 判断基本数据类型(会失败)
console.log(num instanceof Number);    // 输出: false
console.log(str instanceof String);    // 输出: false
console.log(bool instanceof Boolean);  // 输出: false

3、Object.prototype.toString.call 方法

Object.prototype.toString.call 方法返回一个对象的详细类型信息,不仅可以判断基本数据类型,还可以准确地判断复杂对象类型。

let num = 42;
let str = "Hello, World!";
let bool = true;
let arr = [1, 2, 3];
let obj = { key: "value" };
let func = function() {};
let nullValue = null;
let undefinedValue;
let date = new Date();
let regExp = /regex/;
let sym = Symbol("symbol");

console.log(Object.prototype.toString.call(num)); // 输出: [object Number]
console.log(Object.prototype.toString.call(str)); // 输出: [object String]
console.log(Object.prototype.toString.call(bool));// 输出: [object Boolean]
console.log(Object.prototype.toString.call(arr)); // 输出: [object Array]
console.log(Object.prototype.toString.call(obj)); // 输出: [object Object]
console.log(Object.prototype.toString.call(func)); // 输出: [object Function]
console.log(Object.prototype.toString.call(nullValue)); // 输出: [object Null]
console.log(Object.prototype.toString.call(undefinedValue));// 输出: [object Undefined]
console.log(Object.prototype.toString.call(date));// 输出: [object Date]
console.log(Object.prototype.toString.call(regExp));// 输出: [object RegExp]
console.log(Object.prototype.toString.call(sym)); // 输出: [object Symbol]

4、Array.isArray 方法

Array.isArray() 是专门用来判断是否为数组的方法,不会受到原型链的影响。

const normalArray = [1, 2, 3];
console.log(Array.isArray(normalArray)); // 输出: true

// 创建一个类数组对象(拥有 length 属性和索引属性,但不是数组)
const arrayLikeObject = {
  0: 'a',
  1: 'b',
  length: 2
};
console.log(Array.isArray(arrayLikeObject)); // 输出: false

// 创建一个数组的实例,但修改了它的原型链
const arrayWithModifiedPrototype = [];
arrayWithModifiedPrototype.__proto__ = {}; 
console.log(Array.isArray(arrayWithModifiedPrototype)); // 输出: true

// 通过 Object.create() 创建一个对象,其原型链指向 Array.prototype
const objectWithArrayPrototype = Object.create(Array.prototype);
objectWithArrayPrototype[0] = 'x'; // 可以添加索引属性,但这仍然不是真正的数组
console.log(Array.isArray(objectWithArrayPrototype)); // 输出: false
// 尽管这个对象的原型链指向 Array.prototype,Array.isArray() 仍然能正确识别它不是真正的数组实例

5、总结

在 JavaScript 编程中,确保类型判断的准确性对于编写稳定可靠的代码至关重要。不同的类型判断方法各有其独到之处,适用于不同的场景:

  • typeof 操作符主要用于检测 JavaScript 中的基本数据类型,如字符串、数字、布尔值、undefinedfunction 以及 ES6 引入的 symbol 类型。
  • instanceof 关键字则用于判断一个对象是否由某个特定的构造函数创建,即验证对象是否为该构造函数的实例。
  • Object.prototype.toString.call 方法因其广泛的适用性而受到青睐。它能够返回一个表示对象内部 [[Class]] 属性的字符串,从而揭示对象的真实类型。这种通用性使得它在处理各种复杂类型判断时尤为有效。
  • Array.isArray 函数则是专为数组类型判断而设计的。它能够准确判断一个对象是否为数组,且不受对象原型链的影响,确保判断的准确性和可靠性。

因此,在 JavaScript 编程中,开发者应根据具体需求选择合适的类型判断方法,以确保代码的稳定性和可靠性。