Как определить между элементами массива undefined и пустыми слотами?

Предположим, что я пользовательский разработчик script, и у меня нет контроля над встроенным javascript. Страница создает массивы со случайными длинами, заполняя их случайными значениями (включая фальшивые, например undefined). Не каждому элементу присваивается значение, поэтому могут быть пустые слоты.

Упрощенный пример (консоль Firefox):

var arr = new Array(3);
arr[0] = null;
arr[1] = undefined;
console.log(arr);               \\ Array [ null, undefined, <1 empty slot> ]
console.log(arr[1]);            \\ undefined
console.log(arr[2]);            \\ undefined
console.log(arr[1] === arr[2]); \\ true
console.log(typeof arr[1]);     \\ undefined
console.log(typeof arr[2]);     \\ undefined

Как мы видим, Firefox отображает undefined и пустые слоты по-разному, тогда как для javascript они кажутся одинаковыми.

Теперь предположим, что я хочу очистить такой массив, удалив все пустые слоты, но оставив элементы undefined неповрежденными. Как это сделать?

Ответ 1

Вы можете использовать оператор in, чтобы проверить, имеет ли массив ключ. Он вернет false для пустых слотов, но верно для слотов со значениями, включая значение undefined:

var arr = new Array(3);
arr[0] = null;
arr[1] = undefined;

1 in arr; // true
2 in arr; // false

Обратите внимание, что вы не можете различать пустые слоты и слоты за концом массива, используя это, но если вы знаете длину массива, то вы уже знаете, что 3 не является его частью, поэтому вам не нужно тестировать 3 in arr.

Вы также можете отфильтровать пустые слоты следующим образом:

arr = arr.filter( function ( _, i ) { return i in arr } );

Ответ 2

Вы можете использовать Array#forEach, который пропускает разреженные элементы.

var arr = new Array(3);
arr[0] = null;
arr[1] = undefined;
console.log(arr); 

var withoutSparse = [];

arr.forEach(function (a, i) {
    console.log(i);
    withoutSparse.push(a);
});
console.log(withoutSparse);
.as-console-wrapper { max-height: 100% !important; top: 0; }