Skip to content

检测数组

一个经典的 ECMAScript 问题是判断一个对象是不是数组。以下是三种检测数组的方法。

Object.prototype.toString谨慎使用

js
const arr = [1, 2, 3, 4, 5];
const obj = {};
const isArray = Object.prototype.toString.call(arr).slice(8, -1);
const isObj = Object.prototype.toString.call(obj).slice(8, -1);
console.log(isArray); // Array
console.log(isObj); // Object

使用 Object 原型上的 toString 方法,会返回一个[object Array]格式的字符串。然后可以使用上面代码中的方式,通过比较isArray==='Array'来判断是否是数组。

注意

该方法使用的时候需要注意,在某些场景下可能会返回错误的信息。 例如:

js
const obj = {
  [Symbol.toStringTag]: "Array",
};
const isObj = Object.prototype.toString.call(obj).slice(8, -1);
console.log(isObj); // Array  ❌Error

上述代码中的isObj返回的是Array。原因就在于手动修改了Object.prototype.toString返回的字符串:由[object Object]改为了[object Array],导致了错误
这个值可以被修改成任意字符串,如下:

js
const obj = {
  [Symbol.toStringTag]: "abc",
};
const isObj = Object.prototype.toString.call(obj);
console.log(isObj); // [object abc]

instanceof谨慎使用

通过判断一个对象的原型链上有没有 Array 的原型。

js
const arr = [1, 2, 3, 4, 5];
const obj = {};
arr instanceof Array; // true
obj instanceof Array; // false

而且针对第一种方法中,修改了 Object.prototype.toString 字符串的场景也不会造成误判。

js
const obj = {
  [Symbol.toStringTag]: "Array",
};
obj instanceof Array; // false

继承关系也可以准确判断。

js
class A extends Array {}
const a = new A();
a instanceof Array; // true

注意

使用 instanceof 的问题有两个。

  1. 使用Object.setPrototypeOf()方法修改了对象的原型。这样就会导致错误。
js
const obj = {}; // 一个对象字面量
Object.setPrototypeOf(obj, Array.prototype);
obj instanceof Array; // true  ❌Error
  1. 假定只有一个全局执行上下文。如果网页里有多个框架,则可能涉及两个不同的全局执行上下文,因此就会有两个不同版本的 Array 构造函数。如果要把数组从一个框架传给另一个框架,则这个数组的构造函数将有别于在第二个框架内本地创建的数组。
html
<iframe src="" frameborder="0"></iframe>
<script>
  const Array1 = window.Array;
  const iframe = document.querySelector("iframe");
  const Array2 = iframe.contentWindow.Array;
  console.log(Array1 === Array2); // false
  const arr2 = new Array2();
  arr2 instanceof Array; // false  ❌Error
</script>

Array.isArray()推荐使用

ECMAScript 提供了Array.isArray()方法。这个方法的目的就是确定一个值是否为数组,而不用管它是在哪个全局执行上下文中创建的。

html
<iframe src="" frameborder="0"></iframe>
<script>
  const arr = [1, 2, 3, 4, 5];
  const obj = {};
  Object.setPrototypeOf(obj, Array.prototype);
  const iframe = document.querySelector("iframe");
  const Array2 = iframe.contentWindow.Array;
  const arr2 = new Array2();
  Array.isArray(arr); // true
  Array.isArray(obj); // false
  Array.isArray(arr2); // true
</script>