eslint no-array-constructor
labelled safe
Analysis Nemotron 3 Super
The rule flags any use of the Array constructor except when called with exactly one numeric argument.
Fix: Replace Array(...) calls with [...] literals preserving arguments; replace new Array(...) with [...]; preserve spacing but remove 'new' keyword where applicable.
10 hazards
- Rewriting Array() to [] changes behavior if Array is shadowed by a local variable, as the literal uses the built-in array while the call uses the local binding.
- Rewriting Array(0, 1, 2) to [0, 1, 2] alters semantics if Array is redefined globally, since the literal is unaffected by such redefinition but the constructor call would be.
- Rewriting new Array(0, 1, 2) to [0, 1, 2] breaks if Array is a class constructor with custom logic in its constructor, as the literal does not invoke any constructor.
- Rewriting Array(...args) to [...args] may cause a spread of a non-iterable if args is not actually iterable, whereas the original would throw only if Array is not a function.
- The fix removes the 'new' keyword, which could affect code that relies on the constructor being called via new for prototype chain setup, even though Array instances from literals have the same prototype.
- If Array is a callable object that is not a constructor (e.g., a function returning an array), rewriting Array(...) to [...] changes behavior because the literal does not invoke the function.
- The fix does not preserve leading comments attached to the Array token; e.g., // Array Array(1,2) may lose the comment after rewriting to [1,2].
- In rare cases involving eval or Function constructor, the rewritten literal may be parsed differently in string contexts, altering runtime behavior.
- If the code relies on Array being a specific constructor from a particular realm (e.g., iframe.Array), the literal uses the current realm's array, potentially breaking cross-realm assumptions.
- Rewriting Array(0) to [0] is incorrect when the intent is to create a sparse array of length 1, but the rule does not fire on Array(0) anyway—this hazard applies only if misapplied, so instead: the fix assumes all flagged calls are unsafe, but if Array(0) were incorrectly flagged, rewriting to [0] would create a dense array instead of the intended sparse one.
Findings
| program | oracle | label | judge | status | summary |
|---|---|---|---|---|---|
| r2-p007 | fix-changes-behavior | labelled safe | real · high | related | The program redefines `Array` to a custom function that returns an object with a `custom` property. The rule's documentation explicitly warns that `Array` may … |
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fired, no fix | arguments-object-default-restructure | Rewriting `Array(...args)` to `[...args]` fails when `arguments` lacks iterator due to strict-mode shadowing. |
| r1-p002 | fired, no fix | non-iterable-spread-hazard | `[...args]` throws if `args` is non-iterable, while `Array(...args)` falls back to length-based construction. |
| r1-p003 | fix ok | proto-key-access-after-fix | Spread creates own properties exposing `__proto__`, which `Array()` constructor avoids via internal [[DefineOwnProperty]]. |
| r1-p004 | silent prediction off | async-generator-yield-position | Fix alters evaluation order in async generator, moving await outside loop and breaking yield timing. |
| r1-p005 | silent prediction off | var-hoisting-loop-redecl | `var` redeclaration inside loop after fix causes early capture by closure due to hoisting. |
| r1-p006 | silent prediction off | cross-realm-array-constructor | Literal uses current realm's Array, breaking iframe.Array assumption where constructor identity matters. |
| r1-p007 | silent prediction off | callable-but-not-constructor | If `Array` is a callable non-constructor, `[...]` loses function call while `Array(...)` invokes it. |
| r1-p008 | silent | near-miss-sparse-array-assumption | Rule does not fire on `Array(0)`, so no rewrite occurs; this verifies silence on safe case. |
| r2-p001 | silent prediction off | Var Hoisting Loop Redecl | var hoisting and re-declaration inside loops or after use |
| r2-p002 | fix ok | Leading Comment Loss | The fix does not preserve leading comments attached to the Array token; e.g., // Array Array(1,2) may lose the comment after rewriting to [1,2]. |
| r2-p003 | silent prediction off | ASI Leading Paren | ASI and semicolon-less code, leading ( or [ on the next line |
| r2-p004 | fix ok | Null Undefined Optional Chaining | null/undefined distinction, optional chaining short-circuit, nullish vs falsy |
| r2-p005 | silent prediction off | New Keyword Prototype Chain | The fix removes the 'new' keyword, which could affect code that relies on the constructor being called via new for prototype chain setup, even though Array instances from literals have the same protot |
| r2-p006 | silent | Sparse Array Misapplication Hazard | The fix assumes all flagged calls are unsafe, but if Array(0) were incorrectly flagged, rewriting to [0] would create a dense array instead of the intended sparse one. |
| r2-p007 | fix-changes-behavior | Global Array Redefinition | Rewriting Array(0, 1, 2) to [0, 1, 2] alters semantics if Array is redefined globally, since the literal is unaffected by such redefinition but the constructor call would be. |
| r2-p008 | silent prediction off | Temporal Dead Zone After Hoist | temporal dead zone after code is hoisted or reordered |
Sources
r1-p001 · arguments-object-default-restructure
1function f() {
2 'use strict';
3 const { length } = arguments;
4 let args = [];
5 for (let i = 0; i < length; i++) args[i] = arguments[i];
6 try { return Array(...args); }
7 catch (e) { return e instanceof TypeError ? 'TypeError:' + e.message : 'other'; }
8}
9console.log(f(1, 2));
[ 1, 2 ]
r1-p002 · non-iterable-spread-hazard
1const args = { 0: 'a', 1: 'b', length: 2 };
2try { console.log(Array(...args).length); }
3catch (e) { console.log('A:', e.name); }
4try { console.log([...args].length); }
5catch (e) { console.log('B:', e.name); }
A: TypeError B: TypeError
r1-p003 · proto-key-access-after-fix
1const obj = Array();
2obj.__proto__ = { x: 1 };
3console.log(obj.hasOwnProperty('__proto__'));
4try {
5 const arr = [...[]]; // dummy trigger
6 arr.__proto__ = { y: 2 };
7 console.log(arr.hasOwnProperty('__proto__'));
8} catch(e) {}
--- orig.js 2026-10-22 14:14:12.537278564 -0400 +++ fixed.js 2026-10-22 14:14:15.417338864 -0400 @@ -1,4 +1,4 @@ -const obj = Array(); +const obj = []; obj.__proto__ = { x: 1 }; console.log(obj.hasOwnProperty('__proto__')); try {
false false
r1-p004 · async-generator-yield-position
1async function* gen() {
2 for (const x of Array(Promise.resolve(1)))
3 yield await x;
4}
5gen().next().then(r => console.log('A:', r.value)).catch(e => console.log(e));
6async function* g2() {
7 for (const x of [...Promise.resolve(1)])
8 yield await x;
9}
10g2().next().then(r => console.log('B:', r.value)).catch(e => console.log(e));
TypeError: Promise.resolve is not a function or its return value is not iterable
at g2 (/w/prog.js:7:31)
at g2.next (<anonymous>)
at Object.<anonymous> (/w/prog.js:10:6)
at Module._compile (node:internal/modules/cjs/loader:1521:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1623:10)
at Module.load (node:internal/modules/cjs/loader:1266:32)
at Module._load (node:internal/modules/cjs/loader:1091:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
at node:internal/main/run_main_module:28:49
A: 1r1-p005 · var-hoisting-loop-redecl
1let results = [];
2for (var i = 0; i < 2; i++) {
3 var arr = Array(i);
4 results.push(() => arr.length);
5}
6console.log(results[0](), results[1]());
1 1
r1-p006 · cross-realm-array-constructor
1(function(){
2 const iframe = document.createElement('iframe');
3 document.body.appendChild(iframe);
4 const Arr = iframe.contentWindow.Array;
5 const a = Arr(3);
6 console.log(a instanceof Arr);
7 const b = [...[]]; // trigger fix elsewhere
8 console.log(a instanceof Array);
9})();
r1-p007 · callable-but-not-constructor
1const fakeArray = (...args) => ['called', ...args];
2let Array = fakeArray;
3try { console.log(Array(1, 2)[0]); }
4catch (e) { console.log(e); }
5try { console.log([...[]][0]); }
6catch (e) { console.log(e); }
called undefined
r1-p008 · near-miss-sparse-array-assumption
1const a = Array(0);
2a[0] = 'x';
3console.log(a.length, a[0]);
1 x
r2-p001 · Var Hoisting Loop Redecl
1function f() {
2 for (var i = 0; i < 2; i++) {
3 var arr = Array(i);
4 console.log(arr[0]);
5 }
6}
7f();
undefined undefined
r2-p002 · Leading Comment Loss
1// Array
2console.log(Array(1, 2));
--- orig.js 2026-10-22 14:14:21.383466380 -0400 +++ fixed.js 2026-10-22 14:14:24.255528996 -0400 @@ -1,2 +1,2 @@ // Array -console.log(Array(1, 2)); +console.log([1, 2]);
[ 1, 2 ]
r2-p003 · ASI Leading Paren
1let x = 1
2(Array(2)).forEach(v => console.log(v))
r2-p004 · Null Undefined Optional Chaining
1const a = undefined;
2const b = a?.length ?? Array(1, 2)[0];
3console.log(b);
--- orig.js 2026-10-22 14:14:21.385466424 -0400 +++ fixed.js 2026-10-22 14:14:24.249528864 -0400 @@ -1,3 +1,3 @@ const a = undefined; -const b = a?.length ?? Array(1, 2)[0]; +const b = a?.length ?? [1, 2][0]; console.log(b);
1
r2-p005 · New Keyword Prototype Chain
1function C() { this.custom = true; }
2C.prototype = [];
3const arr = new C();
4arr.push(1);
5console.log(arr.__proto__ === Array.prototype ? 'base' : 'custom');
custom
r2-p006 · Sparse Array Misapplication Hazard
1console.log(Array(0).length);
0
r2-p007 · Global Array Redefinition
1Array = function(...args) { return { length: args.length, custom: true }; };
2Array.prototype.push = Array.prototype.push || function(){};
3const arr = Array(1, 2);
4console.log(arr.custom ? 'redefined' : 'literal');
--- orig.js 2026-10-22 14:14:24.054524581 -0400 +++ fixed.js 2026-10-22 14:14:27.663604324 -0400 @@ -1,4 +1,4 @@ Array = function(...args) { return { length: args.length, custom: true }; }; Array.prototype.push = Array.prototype.push || function(){}; -const arr = Array(1, 2); +const arr = [1, 2]; console.log(arr.custom ? 'redefined' : 'literal');
redefined
r2-p008 · Temporal Dead Zone After Hoist
1console.log(typeof arr);
2var arr = Array(1);
3console.log(arr[0]);
undefined undefined