Loop iteration should not be skipped after removing an element with Array.prototype.splice()

  • SKIPPED_ITERATION_AFTER_SPLICE
  • Code Quality
  • Medium
  • No tags

This rule applies when an element is removed using Array.prototype.splice() inside a loop and the element right after the removed one is skipped in the next iteration.

Array.prototype.splice() shifts the remaining elements after removing an element. For example, arr.splice(i, 1) shifts the element at i + 1 to i. If i is a loop counter, the shifted element will be skipped in the next iteration when the counter is incremented to i + 1.

This problem can be fixed by applying one of the following according to the intention of the element removal:

  • If removing all elements satisfying certain criteria was intended, decrement the loop index variable after doing splice() to avoid the skipping. See Example 1 below.
  • If removing only one element was intended, put break to terminate the loop once the intended element is removed. See Example 2 below.

Noncompliant Code Example

View with compliant examples side by side
// Example 1
function splitParts(str) {
    let parts = str.split(' ');
    for (let i = 0; i < parts.length; i++) {
        // Empty strings may occur if there exist consecutive spaces.
        if (parts[i] === '') {
            // SKIPPED_ITERATION_AFTER_SPLICE alarm.
            // Some empty strings are not removed if 3 or more consecutive spaces existed.
            parts.splice(i, 1);
        }
    }
    return parts;
}

// Example 2
function removeItem(arr, id) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i].id === id) {
            // SKIPPED_ITERATION_AFTER_SPLICE alarm
            arr.splice(i, 1);
        }
    }
}

Compliant Code Example

View with noncompliant examples side by side
// Example 1
function splitParts(str) {
    let parts = str.split(' ');
    for (let i = 0; i < parts.length; i++) {
        // Empty strings may occur if there exist consecutive spaces.
        if (parts[i] === '') {
            parts.splice(i, 1);
            i--;
        }
    }
    return parts;
}

// Example 2
function removeItem(arr, id) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i].id === id) {
            arr.splice(i, 1);
            break;
        }
    }
}

Version

This rule was introduced in DeepScan 1.48.0.

See

Was this documentation helpful?