如何区分 JavaScript 中的 Object 和 Array

388 阅读3分钟

在 JavaScript 里,Object 和 Array 都是十分常用的数据类型。不过,在某些情形下,你需要精确判断一个变量究竟是 Object 还是 Array。接下来,我们会详细介绍几种区分它们的方法,同时探讨每种方法的优缺点。

方法一:使用 Array.isArray() 方法

原理

Array.isArray() 是 JavaScript 原生提供的方法,其用途是判断一个值是否为数组。它的语法十分简单:Array.isArray(obj),这里的 obj 就是要检测的对象。要是 obj 是数组,该方法会返回 true,反之则返回 false

const arr = [1, 2, 3];
const obj = { a: 1, b: 2 };

console.log(Array.isArray(arr)); // true
console.log(Array.isArray(obj)); // false

优缺点

  • 优点:简洁高效,是原生方法,性能表现良好。
  • 缺点:没有明显缺点,是判断数组的首选方法。

方法二:使用 instanceof 操作符

原理

instanceof 操作符用于检测构造函数的 prototype 属性是否存在于某个实例对象的原型链上。使用方式为 obj instanceof Array,若 obj 的原型链里包含 Array.prototype,就会返回 true,这意味着 obj 是数组;反之则返回 false

const arr = [1, 2, 3];
const obj = { a: 1, b: 2 };

console.log(arr instanceof Array); // true
console.log(obj instanceof Array); // false

优缺点

  • 优点:语法直观,易于理解。
  • 缺点:在跨 iframe 的场景中会出现问题。由于不同 iframe 有各自的执行上下文和全局对象,不同 iframe 中的 Array 构造函数是不一样的,所以这种方式可能会返回错误结果。
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
</head>

<body>
    <iframe id="myIframe"></iframe>
    <script>
        const iframe = document.getElementById('myIframe');
        iframe.onload = function () {
            const arrInIframe = iframe.contentWindow.Array(1, 2, 3);
            console.log(arrInIframe instanceof Array); 
        };
    </script>
</body>

</html>

在上述代码中,由于 arrInIframe 是在 iframe 中创建的,它的 Array 构造函数和主窗口的 Array 构造函数不同,所以 instanceof 判断可能会出错。

方法三:使用 Object.prototype.toString.call() 方法

原理

这是一种比较可靠的跨环境判断方式。该方法会返回一个表示对象类型的字符串。通过 Object.prototype.toString.call(obj) 能够获取 obj 的内部类型标签。对于数组,该方法会返回 [object Array],而对于普通对象则返回 [object Object]。所以可以通过比较返回的字符串来判断对象是否为数组,即 Object.prototype.toString.call(obj) === '[object Array]'

const arr = [1, 2, 3];
const obj = { a: 1, b: 2 };

console.log(Object.prototype.toString.call(arr) === '[object Array]'); 
console.log(Object.prototype.toString.call(obj) === '[object Array]'); 

优缺点

  • 优点:不受跨 iframe 等复杂环境的影响,能准确判断对象类型。
  • 缺点:代码相对复杂,没有 Array.isArray() 简洁。

方法四:检查 constructor 属性

原理

在 JavaScript 中,每个对象都有一个 constructor 属性,这个属性指向创建该对象的构造函数。

对于数组来说,由 Array 构造函数创建的数组对象,其 constructor 属性会指向 Array 构造函数本身。所以可以通过检查对象的 constructor 属性是否等于 Array 来判断该对象是否为数组。如果 arr.constructor === Array 的结果为 true,则表明 arr 是由 Array 构造函数创建的,即 arr 是数组;反之,如果结果为 false,则 arr 不是数组。

const arr = [1, 2, 3];
const obj = { a: 1, b: 2 };

console.log(arr.constructor === Array); 
console.log(obj.constructor === Array); 

优缺点

  • 优点:简单直接。

  • 缺点:对象的 constructor 属性可以被手动修改,一旦原型被篡改,这种判断方式就可能不准确。

const arr = [1, 2, 3];
arr.constructor = Object;
console.log(arr.constructor === Array); 

在上述代码中,手动修改了 arr 的 constructor 属性,导致判断结果出错。

总结

  • 若要判断一个对象是否为数组,优先推荐使用 Array.isArray() 方法,因为它简洁高效且没有明显缺点。
  • 在不涉及跨 iframe 场景时,instanceof 操作符也是一个不错的选择,其语法直观易懂。
  • 若需要在跨 iframe 等复杂环境中判断对象类型,Object.prototype.toString.call() 方法更为可靠。
  • 不建议使用检查 constructor 属性的方法,因为它容易受到原型篡改的影响。