Массивы. Все способы перебора массива в JavaScript
Массивы — это один из самых часто используемых видов переменных, которые позволяют хранить множество последовательных значений в “одном месте”. Однако когда речь идёт о JavaScript-е, то тут есть куда капнуть.
В этой статье мы рассмотрим тройку малоизвестных техник, которые можно применить при работе с массивами.
1. Добавление пользовательских свойств к массивам
Если вы воспользуетесь поиском для того чтобы найти определение массива в рамках языка JavaScript, то в большинстве источников будет утверждаться что данный тип значения переменной представляется в виде объекта.
Вообще говоря, множество вещей с которыми мы сталкиваемся в JavaScript-е представляет собой объекты. Справедливо будет отметить, что в языке так же присутствую и “примитивные” типы данных, но их значения так или иначе используются в свойствах внутри объектов.
2. Доступ к элементам массива в рамках цикла
Поскольку индексы массивов могут принимать только положительные значения, начало отсчёта начинается с нуля. Впоследствии мы можем использовать данный индекс для доступа к элементу массива на данной итерации цикла.
В ECMAScript6 был представлен способ прокрутки массива без использования индексов, а через новый цикл for…of .
Цикл for...of предназначен для прохода по элементам массива, не затрагивая при этом индекс элемента.
Var ary = ["orange","apple","lychee"]; for (let item of ary){ console.log(item); } // "orange", "apple", "lychee" Для сравнения: вывод индексов элементов в цикле for. var ary = ["orange","apple","lychee"]; for (var item = 0; item < ary.length; item++){ console.log(item); } // 0, 1, 2
3. Количество элементов — не размерность массива
Когда речь идёт о размерности массива, то обычно мы думаем, что подразумевается количество хранящихся в нём элементов. На деле это не совсем так — свойство length рассчитывается в зависимости от максимального индекса элемента.
Свойство length очень неоднозначно. Чтобы в этом убедиться достаточно взглянуть на следующие манипуляции:
Var ary = ; ary.length = 3; console.log(ary.length); // 3 ary = "abcd"; console.log(ary.length); // 6
В последнем примере было достаточно поставить элемент на пятую позицию, в результате чего длина массива стала равна 6. Если вы думаете, что индексы от 0 до 4 создадутся автоматически, то будете неправы. Это можно проверить, используя оператор in .
Var ary = ; ary.length = 3; console.log(ary.length); // 3 ary = "abcd"; console.log(ary.length); // 6 console.log(0 in ary); // false
В данном случае будет справедливо назвать массив ary "разрежённым".
Так же мы можем манипулировать свойством length для того чтобы обрезать массивы. В примере, представленном ниже, демонстрируется “потеря” элемента под индексом 5, путём уменьшения значения свойства length массива ary .
Var ary = ; ary.length = 3; console.log(ary.length); // 3 ary = "abcd"; console.log(ary.length); // 6 ary.length = 2; console.log(ary.length); // 2 console.log(ary); // undefined
Массивы – широко используемый тип данных в языках программирования, который служит для одновременного хранения множества значений. Однако, из-за специфичности некоторых моментов языка JavaScript, массивы обладают некоторым функционалом, о котором часто недоговаривают. В этом посте я рассмотрю три менее известных, но все же важных функций JavaScript массивов, о существовании которых вы могли не догадываться…
Перед началом, хочу отметить, что данный текст является логическим продолжением похожего поста — , поэтому переходите по ссылочке и читайте 🙂
Добавление пользовательских свойств в массивы
Если вы когда-нибудь искали в интернете полное определение массивов в JavaScript , то вы скорее всего найдете источники, где пишется, что массивы в JavaScript являются объектами и как бы странно это не звучало, но это правда.
Фактически, почти все, с чем мы имеем дело в JavaScript, является объектом . По сути есть два типа данных в JavaScript – примитивы и объекты , но примитивы всегда оборачиваются внутри объектов.
Цикл через элементы массива
После прочтения этого подзаголовка вы вероятно, подумали – «Ничего нового – это я уже знаю» и вы будете отчасти правы, ведь любой, даже новичок сможет пройти циклом по элементам массива, но на самом деле это все довольно абстрактно и цикл пройдет по индексам массива.
Поскольку индексы массива состоят только из неотрицательных целых чисел, в цикле мы «итерируем» целое значение, как правило, начиная с нуля и заканчивая числом, которое означает размер массива, а затем используем «итерированное» значение для доступа к элементу массива с заданным индексом.
Однако, в ECMAScript6 , есть способ с помощью которого можно пробежаться по значениям массива не задумываясь об индексах и сделать это можно с помощью for…of цикла.
В массиве for…of цикл будет перебирать элементы массива в порядке индексов, другими словами вам больше не нужно будет заботиться об итерации по индексам и получении существующего значения массива по заданному индексу . Цикл for…of идеально подойдет, если вы хотите просто циклично тупо вывести элементы массива и начать работать с ними. Например:
JavaScript
var arr = ["яблоко","банан","апельсин"]; for (let item of arr){ console.log(item); } // "яблоко","банан","апельсин"
Для сравнения давайте теперь посмотрим на стандартный цикл перебора массива без явного указания индекса значения.
JavaScript
var arr = ["яблоко","банан","апельсин"]; for (var item = 0; item < arr.length; item++){ console.log(item); } // 0, 1, 2
Число элементов не показывает истинный размер массива
Как правило, когда мы говорим о размере массива, мы думаем, что это – либо число имеющее значение, которое массив содержит, или размер, который мы дали массиву вручную. Однако, в действительности размер массива зависит от самого большого существующего индекса в нем.
Length — (я знаю, что это вообще называется длина, но я очень привык называть — размер, поэтому заранее простите если кого-то ввел в заблуждение) — очень гибкое свойство. Фиксировали ли вы уже размер массива заранее или нет, если вы продолжаете добавлять значения к массиву , его размер соответственно продолжает увеличиваться. Например:
JavaScript
var arr = ; arr.length = 3; console.log(arr.length); // 3 arr = "abcd"; console.log(arr.length); // 6
var arr = ; arr . length = 3 ; // 3 arr [ 5 ] = "abcd" ; console . log (arr . length ) ; // 6 |
В примере выше, вы видите, что я дал массиву только одно значение по индексу 5, и его размер стал 6. Теперь, если вы думаете, что, добавляя значение по индексу 5, массив создал индексы от 0 до 4 автоматически, тогда вы глубоко ошибаетесь. Нет действительно никаких существующих индексов от 0 до 4 в этом массиве. Вы можете проверить это используя in оператор.
JavaScript
var arr = ; arr.length = 3; console.log(arr.length); // 3 arr = "abcd"; console.log(arr.length); // 6 console.log(0 in arr); // false
var arr = ; arr . length = 3 ; console . log (arr . length ) ; // 3 arr [ 5 ] = "abcd" ; console . log (arr . length ) ; |
JavaScript спроектирован на основе простой парадигмы. В основе концепции лежат простые объекты. Объект - это набор свойств, и каждое свойство состоит из имени и значения, ассоциированного с этим именем. Значением свойства может быть функция, которую можно назвать методом объекта. В дополнение к встроенным в браузер объектам, вы можете определить свои собственные объекты. Эта глава описывает как пользоваться объектами, свойствами, функциями и методами, а также как создавать свои собственные объекты.
Обзор объектов
Объекты в JavaScript, как и во многих других языках программирования, похожи на объекты реальной жизни. Концепцию объектов JavaScript легче понять, проводя паралелли с реально существующими в жизни объектами.
В JavaScript объект - это самостоятельная единица, имеющая свойства и определенный тип. Сравним, например, с чашкой. У чашки есть цвет, форма, вес, материал, из которого она сделана, и т.д. Точно так же, объекты JavaScript имеют свойства, которые определяют их характеристики.
Объекты и свойства
В JavaScript объект имеет свойства, ассоциированные с ним. Свойство объекта можно понимать как переменную, закрепленную за объектом. Свойства объекта в сущности являются теми же самыми переменными JavaScript, за тем исключением, что они закреплены за объектом. Свойства объекта определяют его характеристики. Получить доступ к свойству объекта можно с помощью точечной записи:
ObjectName.propertyName
Как и все переменные JavaScript, имя объекта (которое тоже может быть переменной) и имя свойства являются чуствительными к регистру. Вы можете определить свойство указав его значение. Например, давайте создадим объект myCar и определим его свойства make , model , и year следующим образом:
Var myCar = new Object(); myCar.make = "Ford"; myCar.model = "Mustang"; myCar.year = 1969;
Неопределенные свойства объекта являются undefined (а не null).
MyCar. color; // undefined
Свойства объектов JavaScript также могут быть доступны или заданы с использованием скобочной записи (более подробно см. ). Объекты иногда называются ассоциативными массивами , поскольку каждое свойство связано со строковым значением, которое можно использовать для доступа к нему. Так, например, вы можете получить доступ к свойствам объекта myCar следующим образом:
MyCar["make"] = "Ford"; myCar["model"] = "Mustang"; myCar["year"] = 1969;
Имена свойств объекта могут быть строками JavaScript, или тем, что может быть сконвертировано в строку, включая пустую строку. Как бы то ни было, доступ к любому имени свойства, которое содержит невалидный JavaScript идентификатор (например, имя свойства содержит в себе пробел и тире или начинается с цифры), может быть получен с использованием квадратных скобок. Этот способ записи также полезен, когда имена свойств должны быть динамически определены (когда имя свойства не определено до момента исполнения). Примеры далее:
Var myObj = new Object(), str = "myString", rand = Math.random(), obj = new Object(); myObj.type = "Dot syntax"; myObj["date created"] = "String with space"; myObj = "String value"; myObj = "Random Number"; myObj = "Object"; myObj[""] = "Even an empty string"; console.log(myObj);
Обратите внимание, что все ключи с квадратными скобками преобразуются в тип String, поскольку объекты в JavaScript могут иметь в качестве ключа только тип String. Например, в приведенном выше коде, когда ключ obj добавляется в myObj , JavaScript вызывает метод obj.toString () и использует эту результирующую строку в качестве нового ключа.
Вы также можете получить доступ к свойствам, используя значение строки, которое хранится в переменной:
Var propertyName = "make"; myCar = "Ford"; propertyName = "model"; myCar = "Mustang";
Вы можете пользоваться квадратными скобками в конструкции for...in чтобы выполнить итерацию всех свойств объекта, для которых она разрешена. Чтобы показать как это работает, следующая функция показывает все свойства объекта, когда вы передаете в нее сам объект и его имя как аргументы функции:
Function showProps(obj, objName) { var result = ""; for (var i in obj) { if (obj.hasOwnProperty(i)) { result += objName + "." + i + " = " + obj[i] + "\n"; } } return result; }
Так что если вызвать эту функцию вот так showProps(myCar, "myCar"), то получим результат:
MyCar.make = Ford myCar.model = Mustang myCar.year = 1969
Перечисление всех свойств объекта
Использование функции конструктора
Другой способ создать объект в два шага описан ниже:
- Определите тип объекта, написав функцию-конструктор. Название такой функции, как правило, начинается с заглавной буквы.
- Создайте экземпляр объекта с помощью ключевого слова new .
Чтобы определить тип объекта создайте функцию, которая определяет тип объекта, его имя, свойства и методы. Например предположим, что вы хотите создать тип объекта для описания машин. Вы хотите, чтобы объект этого типа назывался car , и вы хотите, чтобы у него были свойства make, model, и year. Чтобы сделать это, напишите следующую функцию:
Function Car(make, model, year) { this.make = make; this.model = model; this.year = year; }
Заметьте, что используется this чтобы присвоить значения (переданные как аргументы функции) свойствам объекта.
Теперь вы можете создать объект, называемый mycar , следующим образом:
Var mycar = new Car("Eagle", "Talon TSi", 1993);
Эта инструкция создает объект типа Car с ссылкой mycar и присваивает определенные значения его свойствам. Значением mycar.make станет строка "Eagle", mycar.year - это целое число 1993, и так далее.
Вы можете создать столько объектов car, сколько нужно, просто вызывая new . Например:
Var kenscar = new Car("Nissan", "300ZX", 1992); var vpgscar = new Car("Mazda", "Miata", 1990);
Объект может иметь свойство, которое будет другим объектом. Например, далее определяется объект типа Person следующим образом:
Function Person(name, age, sex) { this.name = name; this.age = age; this.sex = sex; }
и затем создать два новых экземпляра объектов Person как показано далее:
Var rand = new Person("Rand McKinnon", 33, "M"); var ken = new Person("Ken Jones", 39, "M");
Затем, вы можете переписать определение car и включить в него свойство owner , которому назначить объект person следующим образом:
Function Car(make, model, year, owner) { this.make = make; this.model = model; this.year = year; this.owner = owner; }
Затем, чтобы создать экземпляры новых объектов, выполните следующие инструкции:
Var car1 = new Car("Eagle", "Talon TSi", 1993, rand); var car2 = new Car("Nissan", "300ZX", 1992, ken);
Заметьте, что вместо того, чтобы передавать строку, литерал или целое число при создании новых объектов, в выражениях выше передаются объекты rand и ken как аргумент функции. Теперь, если вам нужно узнать имя владельца car2, это можно сделать следующим образом:
Car2.owner
Заметьте, что в любое время вы можете добавить новое свойство ранее созданному объекту. Например, выражение
Car1.color = "black";
добавляет свойство color к car1, и устанавливаего его значение равным "black." Как бы там ни было, это не влияет на любые другие объекты. Чтобы добавить новое свойство всем объектам одного типа, вы должны добавить свойство в определение типа объекта car .
Использование метода Object.create
Объекты также можно создавать с помощью метода Object.create . Этот метод очень удобен, так как позволяет вам указывать объект прототип для нового вашего объекта без определения функции конструктора.
// список свойств и методов для Animal var Animal = { type: "Invertebrates", // Значение type по умолчанию displayType: function() { // Метод отображающий тип объекта Animal console.log(this.type); } }; // Создаем объект Animal var animal1 = Object.create(Animal); animal1.displayType(); // Выведет:Invertebrates // Создаем объект Animal и присваиваем ему type = Fishes var fish = Object.create(Animal); fish.type = "Fishes"; fish.displayType(); // Выведет:Fishes
Наследование
Все объекты в JavaScript наследуются как минимум от другого объекта. Объект, от которого произошло наследование называется прототипом, и унаследованные свойства могут быть найдены в объекте prototype конструктора.
Индексы свойств объекта
В JavaScript 1.0 вы можете сослаться на свойства объекта либо по его имени, либо по его порядковому индексу. В JavaScript 1.1 и позже, если вы изначально определили свойство по имени, вы всегда должны ссылаться на него по его имени, и если вы изначально определили свойство по индексу, то должны ссылаться на него по его индексу.
Это ограничение налагается когда вы создаете объект и его свойства с помощью функции конструктора (как мы это делали ранее с типом Car ) и когда вы определяете индивидуальные свойства явно (например, myCar.color = "red"). Если вы изначально определили свойство объекта через индекс, например myCar = "25 mpg" , то впоследствии сослаться на это свойство можно только так myCar .
Исключение из правил - объекты, отображаемые из HTML, например массив forms . Вы всегда можете сослаться на объекты в этих массивах или используя их индекс (который основывается на порядке появления в HTML документе), или по их именам (если таковые были определены). Например, если второй html-тег