Как получить элементы массива внутри метода расширения массива в JavaScript
Что проверяют
Понимаете ли вы, как работает this в методах прототипа и чем опасно расширение встроенных объектов. Следом обычно спрашивают, почему так не принято делать в прикладном коде и какая есть альтернатива.
Как отвечать
Метод из Array.prototype вызывается как arr.method(), поэтому внутри массив доступен через this: элементы это this[0] и this[i], длина this.length, можно звать и встроенные методы, this.filter(...) или this.at(-1).
Object.defineProperty(Array.prototype, 'last', {
value: function () {
return this.length ? this[this.length - 1] : undefined;
},
writable: true,
configurable: true,
});Что стоит проговорить:
- обычная функция, не стрелка: у стрелки нет своего
this, она увидит внешний контекст; definePropertyвместо присваивания: послеArray.prototype.last = fnметод становится перечисляемым и вылезает в каждомfor...inпо массиву. У дескриптораenumerableпо умолчаниюfalse;- без лишних мутаций:
filterиmapвозвращают новый массив, от своего метода ждут того же; - типизация: в TypeScript глобальный интерфейс дополняют через
declare global { interface Array<T> { last(): T | undefined } }.
Альтернатива без правки глобального прототипа это подкласс class Stack extends Array, где this тоже сам массив. Учтите, что map и filter на подклассе через Symbol.species создают новый экземпляр подкласса и передают конструктору число, поэтому конструктор с другой сигнатурой это ломает. В большинстве проектов честнее всего обычная функция last(arr).
Где спотыкаются
Пишут метод стрелкой, а потом не понимают, почему this.length падает или возвращает не то.
Молчат о рисках. Расширение встроенных прототипов конфликтует с будущими стандартами: из-за старых библиотек, которые так делали, в язык вошли flat вместо flatten и includes вместо contains. Такой же патч внутри сторонней зависимости может сломать ваше приложение.
Путают this с аргументом и пишут метод, который принимает массив параметром, хотя вызывается на самом массиве. Тогда расширение прототипа теряет всякий смысл.