Lập trình · 21/10/2026

JavaScript Array.length: Resizing Can Delete Your Data

Assigning length to limit a list can remove the tail of the source array. Array.length is writable, not merely a count to read. Establish who shares the array and whether the goal is data mutation or partial presentation before changing it.

JavaScript Array.length: đổi độ dài có thể xóa dữ liệu

Assigning length to limit a list can remove the tail of the source array. Array.length is writable, not merely a count to read. Establish who shares the array and whether the goal is data mutation or partial presentation before changing it.

1. Shrinking length mutates the same array

const rows = ['A', 'B', 'C', 'D'];
const shared = rows;
rows.length = 2;
console.log(JSON.stringify(rows)); // ["A","B"]
console.log(JSON.stringify(shared)); // ["A","B"]
rows.length = 4;
console.log(Object.hasOwn(rows, 2)); // false

These are ordinary arrays with deletable elements. C and D disappear after truncation; growing length again does not restore them. shared observes the change because it references the same array.

A table's presentation limit should not discard source data still needed elsewhere. A const binding does not prevent mutation of the referenced array.

2. Growing length does not create records

const rows = ['A'];
rows.length = 3;
let calls = 0;
rows.map(value => {
  calls += 1;
  return value;
});
console.log(rows.length); // 3
console.log(calls); // 1
console.log(Object.hasOwn(rows, 1)); // false

The example has length 3 but only one present element for map to visit. New positions are empty slots. See MDN Array.length for length changes and sparse arrays.

Create explicit placeholder values if the UI requires three placeholder records. Do not interpret length as evidence that three records were loaded and validated.

3. Assignment is not input validation

const rows = ['A', 'B', 'C'];
rows.length = '2';
console.log(JSON.stringify(rows)); // ["A","B"]
try {
  rows.length = 1.5;
} catch (error) {
  console.log(error instanceof RangeError); // true
}
console.log(rows.length); // 2

The numeric string truncates this array, while a fractional length is rejected. Trying an assignment and checking for exceptions is therefore insufficient validation for an application's pagination parameter.

Define conversion and business limits at the input boundary. Reporting invalid data before mutation avoids accidentally truncating the source.

4. Take a prefix without mutating the source array

function takeFirst(items, limit) {
  if (!Array.isArray(items)) throw new TypeError('items must be an array');
  if (!Number.isInteger(limit) || limit < 0 || limit > 1000) {
    throw new RangeError('limit must be an integer from 0 to 1000');
  }
  return items.slice(0, limit);
}
const rows = [{ id: 'A' }, { id: 'B' }, { id: 'C' }];
const visible = takeFirst(rows, 2);
console.log(visible.length); // 2
console.log(rows.length); // 3
console.log(visible[0] === rows[0]); // true

The maximum of 1000 is this helper's example policy, not an Array limit. Zero produces an empty array; a limit above the existing count takes at most the available prefix. Individual record schemas remain unchecked.

slice creates a new array with a shallow copy; see MDN slice. The final comparison demonstrates shared object references. Mutating visible[0].id can still affect rows[0]. Sparse input also remains sparse.

5. Review data ownership and shared references

  • Is the goal mutation or a separate presentation list?
  • Who else references the same source array?
  • Are added positions empty slots or actual values?
  • Is the limit validated against the product contract?
  • Do tests inspect source arrays and nested objects?

All eight bilingual blocks ran with Node.js, alongside boundary-limit, invalid-input and source-preservation checks. Real UI and API integration were not tested.

Discussion

Comments 0

Sign in to comment

You need an account to join the discussion and reply to other readers.

Sign inRegister

No comments yet. Be the first to share your thoughts.