Интернет - отличное место для поиска информации, но есть одна крохотная проблема. Вы находитесь на лодке посреди глубокого синего моря. Хотя большинство из нас не решается полностью погрузиться в темноту, нам все же нравится именно то, что мы хотим. (О! Интернет - это глубокое синее море, о котором я говорил).

Как разработчики внешнего интерфейса в большинстве случаев мы не полагаемся на ванильный javascript для всего, что нам нужно. В большинстве случаев мы клянемся в верности нашим хозяевам (фреймворкам) и библиотекам и слепо следуем им, потому что думаем, что они способны на все, иногда проигрывая передовым методам работы с javascript.

Недавно у меня появилась возможность поработать над магистральным приложением, где я понял первостепенную важность выборочного использования встроенных объектов javascript для наших операций независимо от структуры.

Скажем, например, у нас есть массив из n-объектов [{id: 1, name: «one»}, {id: 2, name: «two»}…. ], когда кто-то просит вас найти объект на основе «id», в идеале первым подходом было бы использовать встроенные итерационные методы массива для поиска первого совпадающего элемента? Верно.

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

потеряв дополнительную итерацию O (n) для цикла по массиву и генерации {id: {}, id: {}}, вы получите доступ к Objects.id для прямого и эффективного доступа к желаемому объекту. А для n-числа операций вы сэкономите массу времени, вместо того, чтобы искать по всему массиву.

Итак, с этим введением давайте перейдем к использованию встроенных объектов javascript (массив, объект, набор и карта) на основе операций, для которых мы хотим его использовать.

1. Искать / найти

Давайте посмотрим, как найти конкретный элемент во всех четырех встроенных объектах javascript для разных сценариев использования.

Множество

// array of objects
array.find(object => object.id === 2); // returns object with id 2
//array of numbers starting from "zero"
array.indexOf("one"); // returns 1 as index

Объект

// array of Objects
// eg: [{id: 1, name: "one"},...] can be converted to {1: {name: "one"}, ... }
object[2] // returns the value of key 2 (i.e {name: "two"} 

Примечание. При использовании n-операций для поиска объекта всегда лучше использовать ключ объекта для извлечения элемента, а не поиск по массиву.

Установленный

Наборы не имеют встроенной функции для извлечения или поиска индекса своих элементов, хотя он итерируемый, поэтому в идеале нам пришлось бы преобразовать его в массив перед операцией indexOf / find.

const mySet = new Set(['1', '2', '3']);
[...mySet].indexOf('2') // returns 1
const mySet = new Set([{1: 'one'}, {2: 'two'}, {3: 'three'}]);
[...mySet].find(object => object[2] === 'two'); // returns {2: 'two'}

карта

Карты сами по себе являются специальными объектами, они являются итерациями с конструктором пары ключ-значение, который выглядит как 2D-массив, но действует как объект. Они предлагают большую гибкость в выборе наших ключевых ценностей. Карта может иметь значение ключа, которое может быть строкой, числом, объектом или даже NaN.

var map = new Map([[ 1, 'one' ],[ 2, 'two' ]]);
map.get(1) // returns 'one'

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

2. Сортировать

Операции сортировки могут быть интересными, и в большинстве случаев мы предполагаем, что сортировка по итерируемой сущности работает из коробки. Что ж, так бывает не всегда.

Множество

Сортировка массивов часто неправильно понимается как новичками, так и разработчиками среднего уровня. Поскольку сортировка по умолчанию для массива сортирует массив на основе Unicode, мы не можем ожидать одинакового поведения сортировки для всех типов данных. Следовательно, нам часто нужно передать функцию компаратора в сортировку.

// array of strings in a uniform case without special characters
const arr = [ "sex", "age", "job"];
arr.sort(); //returns ["age", "job", "sex"]
// array of numbers
const arr = [ 30, 4, 29 , 19];
arr.sort((a, b) => a-b); // returns [4, 19, 29, 30]
// array of number strings
const arr = [ "30", "4", "29" , "19" ];
arr.sort((a, b) => a-b); // returns ["4", "19", "29", "30"]
// array of mixed numerics
const arr = [ 30, "4", 29 , "19" ];
arr.sort((a, b) => a-b); // returns ["4", "19", 29, 30]
// array of non-ASCII strings and also strings
const arr = ['réservé', 'cliché', 'adieu'];
arr.sort((a, b) => a.localeCompare(b)); // returns is ['adieu', 'cliché','réservé']
// array of objects
const arr = [
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 }
];
// sort by name string
arr.sort((a,b) => a['name'].localeCompare(b['name']));
// sort by value number
arr.sort((a,b) => a['value']-b['value']);

Примечание. Я обычно предпочитаю использовать localeCompare для сортировки строк, поскольку они предлагают большую гибкость в управлении чувствительностью к регистру, акцентом, а также дают нам возможность учитывать язык во время сортировки.

Объект

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

// object with numeric/numeric-string keys are sorted
const obj = { 30: 'dad', '4': 'kid', 19: 'teen', '100': 'grams'};
console.log(obj) // returns {4: "kid", 19: "teen", 30: "dad", 100: "grams"} with sorted keys
// object with key-values as alpha-strings are not sorted
const obj = { "b": "two", "a": "one", "c": "three" };
console.log(obj) // returns {b: "two", a: "one", c: "three"}
// object with numeric, numeric-string and alpha keys are partially sorted. (i.e only numeric keys are sorted)
const obj = { b: "one", 4: "kid", "30": "dad", 9: "son", a: "two" };
console.log(obj) // returns {4: "kid", 9: "son", 30: "dad", b: "one", a: "two"}

Установленный

Наборы не имеют встроенной функции сортировки, однако самый простой способ отсортировать набор - это преобразовать его в массив и реализовать метод сортировки массива. Поскольку set является итерируемым объектом, мы можем построить собственный алгоритм сортировки по нашему выбору.

// set to array and array sort 
const set = new Set(['b', 'a', 'c']);
[...set].sort(); // returns ['a', 'b', 'c'] which is an array
// alternatively we can use entries to sort a set and create a new sorted set. The iterator gives us the ['a', 'a'] when spread over an array.
const set = new Set(['b', 'a', 'c']);
const sortedSet = new Set([...set.entries()].map((entry) => entry[0]).sort());

Примечание. Имейте в виду, что метод сортировки является массивом, и вам придется использовать компаратор соответствующим образом, чтобы получить желаемую сортировку.

карта

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

// entries spread over an array can be sorted like an array
const map = new Map([["c", 'three'],["a", 'one'], ["b", 'two']]);
const sortedMap = new Map([...map.entries()].sort()) // returns sorted Map(3) {"a" => "one", "b" => "three", "c" => "two"}

Примечание. При сортировке карты важно знать, что двумерный массив с карты сортируется на основе первого элемента в каждом подмассиве. Здесь сортировка основана на строках «a», «b» и «c». Если бы это были числа, вам пришлось бы использовать компаратор.

3. Включает или имеет

Одна из наиболее важных функций итерируемых объектов - это проверка наличия желаемого элемента. Почти все встроенные стандартные и повторяемые объекты javascript имеют собственную реализацию для достижения этой цели. Давайте посмотрим на них ниже.

Множество

// we are considering a linear array only
const arr = [1, 2, 3];
arr.includes(1); // returns true
arr.includes('1'); // returns false as types do not match

Объект

// we are going to consider only the keys
const obj = { a: 1, b: 2, c: 3, 1: 'one' };
obj.hasOwnProperty('a'); // returns true
obj.hasOwnProperty('1'); // returns true because no type check
obj.hasOwnProperty(1); // returns true

Установленный

Set имеет удобную функцию «has», которая может быть более эффективной при доступе к значениям по сравнению с массивом.

const set = new Set([1, 2, 3, 4, 5]);
set.has(4); // returns true
set.has('4'); // returns false because of mismatch in type

карта

Карта также имеет встроенную функцию «имеет».

const map = new Map([[3, 'three'],["a", 'one'], ["b", 'two']]);
map.has('a'); // returns true
map.has(3); // returns true
map.has('3'); // returns false because types don't match

Примечание. По сравнению с функцией includes массива, функции hasOwnProperty объекта и has Set / Map, похоже, работают примерно с O (1) в разных тестах, явно более эффективный с точки зрения больших наборов данных.

4. Удаление дубликатов

Прямого способа удаления дубликатов в коллекции не существует, учитывая, что массив или объект являются линейными, мы можем использовать некоторые встроенные методы для удаления дубликатов.

Множество

Есть много онлайн-методов для удаления дубликатов из массива. Вот и накрывает этот поток tackoverflow. Однако в ES6 давайте рассмотрим самые простые способы удаления дубликатов из массива.

// considering a linear array Set gives us the answer we need.
const arr = [1, 2, 2, 4, 5, 5];
[...new Set(arr)]; // returns [1, 2, 4, 5]
// however set doesn't remove duplicates from array of objects
const arr = [{a:1},{b:2},{a:1}];
[...new Set(arr)]; // returns [{a:1},{b:2},{a:1}]
// hence we can use ES6 filter and map functions to achieve the same
arr.filter((obj, index) => { 
  return arr.map(obj => obj['a']).indexOf(obj['a']) === index;    
}); // removes duplicate based on the key 'a'

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

Объект

Объекты не допускают дублирования значений ключа, старые значения перезаписываются новыми значениями.

const obj = { b: "one", a: "two", a: "three" };
console.log(obj); // returns {b: "one", a: "three"}

Установить

Наборы по своей сути не допускают дублирования значений, когда им передается линейный итеративный объект, такой как массив, но когда им передается массив объектов, они допускают дублирование объектов.

// a linear array iterable
const set = new Set([1, 2, 2, 4, 5, 5]);
console.log(set); // returns Set {1, 2, 4, 5}
// array of objects
const set = new Set([{a:1},{b:2},{a:1}]);
console.log(set); // returns Set {{a:1},{b:2},{a:1}} with duplicate objects

карта

Карты также не допускают дублирования ключей во время создания.

const map = new Map([[3, 'three'], [2, 'two'], [2, 'four']]);
console.log(map); // returns {3 => "three", 2 => "four"} 

5. Удалить

Множество

У массива нет встроенного метода для удаления его элементов. Однако для этого мы можем использовать несколько методов. Splice, indexOf или фильтр.

// I personally prefer this method.
const arr = [ 'a', 'b', 'c' ];
arr.filter(e => e !== 'c'); // returns [ 'a', 'b' ] removing 'c'

Объект

У объектов нет встроенного метода удаления, но согласно документации мы можем использовать ключевое слово delete для удаления ключа. Однако это широко не приветствуется в сообществе javascript, и даже библиотеки, такие как подчеркивание и lodash, используют другой метод.

// The infamous delete method
const obj = { b: "one", a: "two" };
delete obj.a; // deletes a and returns true

Установленный

Set предлагает встроенный метод удаления, упрощающий нашу жизнь

const set = new Set([1, 2, 4, 5]);
set.delete(4); // deletes 4 and returns true
set.delete('5'); // returns false as types do not match

карта

Карта имеет собственный встроенный метод удаления для удаления ключей из заданного объекта карты.

const map = new Map([[3, 'three'], [2, 'two']);
map.delete(3); // deletes [3, 'three'] and returns true.
map.delete('2'); // returns false as types do not match

6. Длина и размер

// arrays have a built-in property for length which is different from collection size.
['1', '2', '3'].length // returns 3
// objects have no built-in property to check length or size, so we need to resort to using keys array to check length.
Object.keys({ b: 'one', a: 'two', c: 'three' }).length // returns 3
// set has a size property built-in
new Set([{a:1},{b:2},{a:1}]).size // returns 3
// map has a size property built-in
new Map([[3, 'three'],['a', 'one'], ['b', 'two']]).size // returns 3

Заключение

Это некоторые из ключевых указателей, которые следует помнить при выборе стандартных встроенных объектов по вашему выбору. Хотя javascript предлагает нам гибкость использования более чем одного встроенного объекта, всегда лучше выбрать тот, который лучше всего подходит. Не стесняйтесь оставлять свои комментарии ниже.

✉️ Подпишитесь на рассылку еженедельно Email Blast 🐦 Подпишитесь на CodeBurst на Twitter , просмотрите 🗺️ План развития веб-разработчиков на 2018 год и 🕸️ Изучите веб-разработку с полным стеком .