Кастомные методы для массивов в JS

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Вступление


Всем доброго времени суток. Я думаю, вы заметили, что в массивах в JS довольно много хороших встроенных методов. Однако, зачастую, даже их не хватает. Например: мне бы хотелось проверять массивы на пересечение. Конечно, я могу писать так:

checkIntersections(arr1, arr2)

но гораздо удобнее было бы писать вот так:

arr1.checkIntersections(arr2)

Особенно это касается ситуаций, когда функция должна изменять массив, например удалять повторяющиеся элементы. В таком случае нам вообще придется записывать что-то вроде этого:

arr1 = deleteDuplicates(arr1);

Мне такая запись вообще не нравится. Она плохо читаема и не логична. Нужно сделать deleteDuplicates — встроенным методом массива. Но как нам добавить свой метод? Ведь, как многие считают, массив — это неизменяемая часть языка, наподобие операторов. К счастью это не так.

Исследуем массивы


Чтобы понять, как нам взаимодействовать с массивами. Мы для начала должны понять, что из себя представляет сам массив. Для этого давайте выведем его в консоль:

let arr = ["I", "love", "JS"]; 

console.log(arr);

Вот, что мы увидим:



Как видите, консоль показывает нам, что это массив с 3-я элементами. Но также мы видим, что рядом с ним есть кнопка раскрытия (треугольник). Если мы нажмем на нее, то увидим следующее:



Ничего не напоминает? Это же объект! Мы видим, что его свойствами являются числовые ключи и length. Поэтому мы и записываем: array[0]. Мы обращаемся к свойству объекта array с именем 0. Квадратные скобки нужны, поскольку это имя этого свойства представлено числом. А что это за «Array(3)»? Это строка показывает, экземпляром какого объекта является массив, то есть, с помощью какого класса он создан. Значит, все массивы — это экземпляры класса Array. Обладая этими знаниями, давайте попробуем записать какой-нибудь свой метод.

Добавляем новый метод


Давайте сделаем метод, который будет проверять, есть ли в нашем массиве элемент переданный аргументом. Для этого в цикле переберем все элементы нашего массива и вернем true при обнаружении совпадения. Если по завершении цикла совпадение не будет обнаружено — вернем false. Назовем этот метод checkElement. Итак, чтобы добавить его к массиву, обратимся к свойству prototype класса Array.

Array.prototype.checkElement = function(e) {
	
};

Теперь пройдемся циклом по всем элементам. Сделать это очень просто:

for (var i = 0; i < this.length; i++) {
	this[i];
}

Теперь, на каждом шаге цикла будем выполнять проверку на совпадение переданного элемента с элементом текущей итерации.

if (this[i] === e) {
    return true;
}

И наконец, если по завершении цикла совпадений не было обнаружено, вернем false. Вот, что мы получим в итоге.

Array.prototype.checkElement = function(e) {
	for (var i = 0; i < this.length; i++) {
		if (this[i] === e) {
			return true;
		}
	}
	return false;
};

Давайте проверим его в действии.

console.log(arr.checkElement("I"));
console.log(arr.checkElement("not"));

Все работает, но если бы все было так просто, было бы подозрительно.

Исправляем появившуюся ошибку


Давайте попробуем сделать следующее: переберем наш массив с помощью цикла for… in.

for (let i in arr) {
    console.log(i);
}

Как видите, произошел косяк: JS стал видит наш новый метод в этом цикле. Разумеется, при использовании такого цикла в коде, это может привести к ошибке. Но почему JS видит наш метод, но не видит например метод push? Давайте вновь обратимся к консоли и выведем все методы нашего массива. Вот так:

console.log(arr.__proto__);

Вот, что мы увидим:



Как видите: встроенный методы отобразились более тусклым текстом чем наш метод. Это означает, что эти методы обладают особым свойством, которое делает их невидимыми для цикла for… in. Но что это за свойство? Если мы прочитаем документацию о технологии Object.defineProperty на MDN (вот она), то заметим там параметр enumerable. Как мы можем узнать, если его значение установить как false, цикл for… in не будет видеть свойство с этим параметром. Давайте так и сделаем, а чтобы не писать миллион одинаковых инструкций, применим ее ко всем методам.
Вот так:

Object.keys(Array.prototype).forEach(method => {
	Object.defineProperty(Array.prototype, method, {
		enumerable: false,
	});
});

Здесь мы получаем массив ключей нашего объекта Array.prototype и, с помощью Object.defineProperty, делаем их невидимыми для цикла for… in. Давайте проверим теперь.

console.log(arr.checkElement("I"));
		
for (let i in arr) {
	console.log(i);
}

Прекрасно! Все работает так, как мы и ожидали.

Итог


Итак, вот код, который у нас получился.

Array.prototype.checkElement = function(e) {
	for (var i = 0; i < this.length; i++) {
		if (this[i] === e) {
			return true;
		}
	}
	return false;
};

Object.keys(Array.prototype).forEach(method => {
	Object.defineProperty(Array.prototype, method, {
		enumerable: false,
	});
});

Как видите, ничего сложного, но может очень сильно облегчить жизнь. Кроме того, можно добавлять кучу других методов под свои нужды.

Я думаю, таким же методом можно изменять и другие технологии в JS. Главное — понять как они устроены.
Источник: https://habr.com/ru/post/521934/


Интересные статьи

Интересные статьи

Это обычные, не кастомные SSD Мне часто приходится иметь дело с разного рода носителями информации, как чисто пользовательскими, так и корпоративными. Соответственно, нужно быть в к...
Часто от программистов PHP можно услышать: «О нет! Только не „Битрикс“!». Многие специалисты не хотят связываться фреймворком, считают его некрасивым и неудобным. Однако вакансий ...
Приветствую всех членов сообщества! А отдельно — преподавателей и собственников технических кружков: именно вам, уважаемые коллеги, адресована моя статья. Меня зовут Владимир Мозговой. Я являю...
Источник: xkcd Линейная регрессия является одним из базовых алгоритмов для многих областей, связанных с анализом данных. Причина этому очевидна. Это очень простой и понятный алгоритм, что сп...
В Челябинске проходят митапы системных администраторов Sysadminka, и на последнем из них я делал доклад о нашем решении для работы приложений на 1С-Битрикс в Kubernetes. Битрикс, Kubernetes, Сep...