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

JavaScript Array Deletion: Why delete Does Not Reduce length

A row is deleted with delete rows[1], but the counter still shows three elements. delete removes an indexed property without shifting later entries or reducing length. Removing a row from a continuous list requires a different operation.

delete phần tử mảng JavaScript: vì sao length không giảm?

A row is deleted with delete rows[1], but the counter still shows three elements. delete removes an indexed property without shifting later entries or reducing length. Removing a row from a continuous list requires a different operation.

1. delete leaves a hole

const rows = ['A', 'B', 'C'];
delete rows[1];
console.log(rows.length); // 3
console.log(Object.hasOwn(rows, 1)); // false
console.log(rows[2]); // C
console.log(rows[1]); // undefined

The example demonstrates that C remains at index 2. Reading index 1 yields undefined in this ordinary array, but the property is absent. A sparse array's length does not count assigned slots. A disappearing rendered row alone does not prove the underlying list has the intended shape.

2. Assigning undefined keeps the element

const absent = ['A', 'B'];
delete absent[1];
const explicit = ['A', 'B'];
explicit[1] = undefined;
console.log(Object.hasOwn(absent, 1)); // false
console.log(Object.hasOwn(explicit, 1)); // true
let visits = 0;
absent.forEach(() => visits++);
console.log(visits); // 1
visits = 0;
explicit.forEach(() => visits++);
console.log(visits); // 2

The arrays share a length and return undefined at the last index, yet invoke different numbers of callbacks. These examples assume no inherited indexed properties. Test structure and traversal behavior as well as retrieved values.

3. splice shifts entries and mutates the source

const rows = ['A', 'B', 'C'];
const alias = rows;
const removed = rows.splice(1, 1);
console.log(JSON.stringify(rows)); // ["A","C"]
console.log(JSON.stringify(removed)); // ["B"]
console.log(alias.length); // 2

splice returns the removed entries. The original rows contains the remainder, and alias observes its new length. Assigning the return value does not retrieve the remaining list. Guard a findIndex result of -1 before splicing; a negative index can remove an unintended trailing element.

4. Build a new list after checking the index

This helper targets ordinary arrays and requires an integer within bounds. It rejects -1, fractions and numeric strings. The returned array is new, while objects inside retain their original identities.

function withoutIndex(rows, index) {
  if (!Array.isArray(rows)) throw new TypeError('Array required');
  if (!Number.isInteger(index) || index < 0 || index >= rows.length) {
    throw new RangeError('Index outside array');
  }
  return rows.slice(0, index).concat(rows.slice(index + 1));
}
const original = [{ id: 'a' }, { id: 'b' }, { id: 'c' }];
const next = withoutIndex(original, 1);
console.log(next.map(row => row.id).join(',')); // a,c
console.log(original.length); // 3
console.log(next === original); // false
console.log(next[0] === original[0]); // true

The helper does not validate or repair preexisting holes elsewhere. Validate density separately if required. Independent edits to retained objects need copies at the relevant layers.

5. Test removal against its intended outcome

  • Does length decrease and the next entry shift?
  • Should the source change or remain intact?
  • Does the return value represent removed entries or the remainder?
  • Is a missing-match index rejected?
  • Are retained objects still shared?

All eight bilingual code blocks ran with Node.js, alongside first, middle, last and invalid-index checks. UI components were not tested. References: MDN delete and MDN Array.splice.

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.