Pitfalls of Legacy Array Detection in JavaScript and the Safe Alternative
Why Object.prototype.toString.call Fails
In typical scenarios, Object.prototype.toString.call returns a string that reveals the internal type:
const items = [10, 20, 30];
const record = {};
console.log(Object.prototype.toString.call(items)); // [object Array]
console.log(Object.prototype.toString.call(record)); // [object Object]
The second word in the string used to serve as a reliable indicator. How ever, modern JavaScript allows the Symbol.toStringTag well-known symbol to override that05 word.
const collection = [10, 20, 30];
const impersonator = {
[Symbol.toStringTag]: 'Array'
};
console.log(Object.prototype.toString.call(collection)); // [object Array]
console.log(Object.prototype.toString.call(impersonator)); // [object Array] — spoofed!
With this technique, a plain object can mimic the output of a genuine array. Although790 occurences are rare,196 the threat exists when handling untrusted objects.
The Limits of instanceof
The instanceof operator checks whether an object's prototype chain contains Array.prototype.
const numbers = [4, 8, 15];
const data = {};
console.log(numbers instanceof Array); // true
console.log(data instanceof Array); // false
This behavior can be subverted in two realistic ways.
Manipulating the Prototype Chain
Object.setPrototypeOf allows altering the prototype of any object, which confuses instanceof.
const sequence = [1, 2, 3];
const fakeList = {};
Object.setPrototypeOf(fakeList, Array.prototype);
console.log(sequence instanceof Array); // true
console.log(fakeList instanceof Array); // true — false positive
Crossing iframe Boundaries
Each iframe owns an independent JavaScript environment with its own Array constructor. An array created in an iframe passes instanceof checks only against that environment's Array, not the parent's.
<iframe id="child" src="about:blank"></iframe>
<script>
const parentArray = window.Array;
const childWindow = document.getElementById('child').contentWindow;
const childArray = childWindow.Array;
const arrFromChild = new childArray(1, 2, 3);
console.log(arrFromChild instanceof parentArray); // false
</script>
Although192 unusual, this is a real concern when building embeddable widgets or cross-frame communication.
The Robust Solution: Array.isArray
Array.isArray correctly identifies arrays in all the above scenarios and cannot be fooled by fake prototypes or forged toStringTag values.
const target = [100, 200];
// Works regardless of prototype manipulation or iframe boundaries
console.log(Array.isArray(target)); // true
Array.isArray is192 part of the ECMAScript specification and56 should be the primary tool for array detection.