Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

Объекты как ассоциативные массивы

Лекция



Привет, сегодня поговорим про объекты как ассоциативные массивы, обещаю рассказать все что знаю. Для того чтобы лучше понимать что такое объекты как ассоциативные массивы , настоятельно рекомендую прочитать все из категории Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend).


  1. Ассоциативные массивы
  2. Создание объектов
  3. Операции с объектом
    1. Доступ через квадратные скобки
    2. Объявление со свойствами
      1. Вложенные объекты в объявлении
  4. Перебор свойств и значений
    1. Количество свойств в объекте
    2. Порядок перебора свойств
  5. Передача по ссылке
  6. Компактное представление объектов
  7. Итого

Объекты в JavaScript являются «двуличными». Они сочетают в себе два важных функционала.

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

Второй — языковые возможности для объектно-ориентированного программирования. Эти возможности мы изучим в последующих разделах учебника.

Ассоциативные массивы

Ассоциативный массив — структура данных, в которой можно хранить любые данные в формате ключ-значение.

Ее можно легко представить как шкаф с подписанными ящиками. Все данные хранятся в ящичках. По имени можно легко найти ящик и взять то значение, которое в нем лежит.

В отличие от реальных шкафов, в ассоциативный массив можно в любой момент добавить новые именованные «ящики» или удалить существующие. Далее мы увидим примеры, как это делается.

Кстати, в других языках программирования такую структуру данных также называют «словарь» и«хэш».

Создание объектов

Пустой объект («пустой шкаф») может быть создан одним из двух синтаксисов:

 

1. o = new Object();
2. o = {};   // пустые фигурные скобки

 

Обычно все пользуются синтаксисом (2), т.к. он короче.

Операции с объектом

Объект может содержать в себе любые значения, которые называются свойствами объекта. Доступ к свойствам осуществляется по имени свойства (иногда говорят «по ключу»).

Например, создадим объект person для хранения информации о человеке:

 

var person = {}; // пока пустой

 

Основные операции с объектами — это:

  1. Присвоение свойства по ключу.
  2. Чтение свойства по ключу.
  3. Удаление свойства по ключу.

Для обращения к свойствам используется запись «через точку», вида объект.свойство:

 

   
01 var person = {};
02  
03 // 1. присвоение
04 // при присвоении свойства в объекте автоматически создается "ящик"
05 // с именем "name" и в него записывается содержимое 'Вася'
06 person.name = 'Вася';
07  
08 person.age = 25;  // запишем еще одно свойство: с именем 'age' и значением 25
09  
10 // 2. чтение
11 alert(person.name + ': ' + person.age); // вывести значения
12  
13 // 3. удаление
14 delete person.name; // удалить "ящик" с именем "name" вместе со значением в нем

 

Следующая операция:

  1. Проверка существования свойства с определенным ключом.

Например, есть объект person, и нужно проверить, существует ли в нем свойство age.

Для проверки существования есть оператор in. Его синтаксис: "prop" in obj, причем имя свойства — в виде строки, например:

 

1 var person = { };
2  
3 if ("age" in person) {
4   alert("Свойство age существует!");
5 }

 

Впрочем, чаще используется другой способ — сравнение значения с undefined.

Дело в том, что в JavaScript можно обратиться к любому свойству объекта, даже если его нет. Ошибки не будет.

Но если свойство не существует, то вернется специальное значение undefined:

 

   
1 var person = {};
2  
3 alert(person.lalala); // undefined, нет свойства с ключом lalala

 

Таким образом мы можем легко проверить существование свойства — получив его и сравнив сundefined:

 

   
1 var person = { name: "Василий" };
2  
3 alert(person.lalala === undefined); // true, свойства нет
4 alert(person.name === undefined); // false, свойство есть.

 

 

Разница между проверками in и === undefined

Есть два средства для проверки наличия свойства в объекте: первое — оператор in, второе — получить его и сравнить его с undefined.

Они почти идентичны, но есть одна небольшая разница.

Дело в том, что технически возможно, что свойство есть и равно undefined:

   
1 var obj = {};
2 obj.test = undefined// добавили свойство со значением undefined
3  
4 // проверим наличие свойств test и заведомо отсутствующего blabla
5 alert(obj.test === undefined); // true
6 alert(obj.blabla === undefined); // true

 

…При этом, как видно из кода, при простом сравнении наличие такого свойства будет неотличимо от его отсутствия.

Но оператор in гарантирует правильный результат:

   
1 var obj = {};
2 obj.test = undefined;
3  
4 alert( "test" in obj ); // true
5 alert( "blabla" in obj ); // false

 

Как правило, в коде мы не будем присваивать undefined, чтобы корректно работали обе проверки. А в качестве значения, обозначающего неизвестность и неопределенность, будем использовать null.

 

Доступ через квадратные скобки

Существует альтернативный синтаксис работы со свойствами, использующий квадратные скобкиобъект['свойство']:

   
1 var person = {};
2  
3 person['name'] = 'Вася'// то же что и person.name
4  
5 alert(person['name']);
6  
7 delete person['name'];

 

В квадратные скобки можно передать переменную:
obj[key] использует значение переменной key в качестве имени свойства:

 

   
1 var person = { age: 25 };
2 var key = 'age';
3  
4 alert(person[key]);  // выведет person['age']

 

Записи person['age'] и person.age идентичны. С другой стороны, если имя свойства хранится в переменной (var key = "age"), то единственный способ к нему обратиться — квадратные скобкиperson[key].

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

 

Ограничения на имя свойства
  • На имя свойства при доступе «через точку» наложены синтаксические ограничения — примерно те же, что и на имя переменной. Оно не может начинаться с числа, содержать пробелы и т.п.
  • При обращении через квадратные скобки можно использовать любую строку.

Например:

person['день рождения!'] = '18.04.1982';
// запись через точку "person.день рождения! = ..." невозможна

 

В обоих случаях, имя свойства обязано быть строкой. Если использовано значение другого типа — JavaScript приведет его к строке автоматически.

 

Объявление со свойствами

Объект можно заполнить значениями при создании, указав их в фигурных скобках:{ ключ1: значение1, ключ2: значение2, ... }.

Такой синтаксис называется литеральным (оригинал - literal), например:

Объекты как ассоциативные массивы

Следующие два фрагмента кода создают одинаковый объект:

01 var menuSetup = {
02     width:  300,
03     height: 200,
04     title: "Menu"
05 };
06  
07 // то же самое, что:
08  
09 var menuSetup = {};
10 menuSetup.width = 300;
11 menuSetup.height = 200;
12 menuSetup.title = 'Menu';

 

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

Например:

1 var menuSetup = {
2     width:  300,
3     'height': 200,
4     "мама мыла раму"true
5 };

 

 

Важность: 3

Мини-задача на синтаксис объектов. Об этом говорит сайт https://intellect.icu . Напишите код, по строке на каждое действие.

  1. Создайте пустой объект user.
  2. Добавьте свойство name со значением Вася.
  3. Добавьте свойство surname со значением Петров.
  4. Поменяйте значение name на Сергей.
  5. Удалите свойство name из объекта.
Решение

 

1 var user = {};
2 user.name = "Вася";
3 user.surname = "Петров";
4 user.name = "Сергей";
5 delete user.name;

 

[Открыть задачу в новом окне]

 

Вложенные объекты в объявлении

Значением свойства может быть объект:

01 var user = {
02   name:  "Таня",
03   age: 25,
04   size: {
05     top: 90,
06     middle: 60,
07     bottom: 90
08   }
09 }
10  
11 alert( user.name ) // "Таня"
12  
13 alert( user.size.top ) // 90

 

Здесь значением свойства size является объект {top: 90, middle: 60, bottom: 90 }.

 

Вывод объекта, Firefox

Для целей отладки иногда хочется вывести объект целиком. В Firefox для этого существует нестандартный метод toSource.

 

   
1 var user = {
2   name:  "Таня",
3   size: {
4     top: 90,
5     middle: 60
6   }
7 }
8  
9 alert( user.toSource() ); // работает только в Firefox

 

В других браузерах его нет, но объект можно посмотреть через инструменты разработчика: отладчик или console.log.

 

Перебор свойств и значений

Для перебора всех свойств из объекта используется цикл по свойствам for..in. Это специальная синтаксическая конструкция, которая работает не так, как обычный цикл for (i=0;i<n;i++).

Синтаксис:

 

for (key in obj) {
  /* ... делать что-то с obj[key] ... */
}

 

При этом в key будут последовательно записаны имена свойств.

 

Объявление переменной в цикле for (var key in obj)

Переменную можно объявить прямо в цикле:

 

for (var key in menu) {
  // ...
}
Так иногда пишут для краткости кода.

 

 

Например:

 

   
01 var menu = {
02     width:  300,
03     height: 200,
04     title: "Menu"
05 };
06  
07 for (var key in menu) {
08     // этот код будет вызван для каждого свойства объекта   
09     // ..и выведет имя свойства и его значение
10  
11     alert("Ключ: " + key + " значение:" + menu[key]);
12 }

 

Конечно, вместо key может быть любое другое имя переменной.

Количество свойств в объекте

Одного метода, который вернул бы количество свойств нет. Кросс-браузерный способ — это сделать цикл по свойствам и посчитать:

 

1 function getKeysCount(obj) {
2   var counter = 0;
3   for (var key in obj) {
4     counter++;
5   }
6   return counter;
7 }

 

А вот так выглядит функция проверки на «пустоту»:

1 function isEmpty(obj) {
2   for (var key in obj) {
3     return false// если цикл хоть раз сработал, то объект не пустой => false
4   }
5   // дошли до этой строки - значит цикл не нашел ни одного свойства => true
6   return true;
7 }

 

Порядок перебора свойств

Упорядочены ли свойства в объектах? В теории, т.е. по спецификации — нет. На практике, все сложнее.

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

 

  • Браузеры IE<9, Firefox, Safari перебирают ключи в том же порядке, в котором свойства присваивались.
  • Opera, современный IE, Chrome гарантируют сохранение порядка только длястроковых ключей. Численные ключи сортируются и идут до строковых.

 

То есть, если свойства в объекте строковые, то такой объект упорядочен. Свойства будут перебираться в порядке их присвоения:

 

   
1 var user = {
2   name: "Вася",
3   surname: "Петров"
4 };
5 user.age = 25;
6  
7 for (var prop in user) {
8   alert(prop); // name, surname, age
9 }

 

Рассмотрим теперь случай, когда ключи «численные». Как мы знаем, у объектов в JavaScript ключи могут быть только строками, но если строка имеет вид целого числа, то некоторые интерпретаторы распознают это и обрабатывают такие ключи по-другому.

Например, рассмотрим объект, который задает список опций для выбора страны:

1 var codes = {
2   // телефонные коды в формате "код страны": "название"
3   "255""Танзания"
4   "7""Россия",
5   "38""Украина",
6   // ..,
7   "1""США"
8 };

 

Мы хотим вывести эти опции посетителю в том же порядке, то есть «Танзания» в начале, а «США» — в конце (это если наш офис находится в Занзибаре, тогда такой порядок будет наиболее актуален).

Однако, при переборе их через for..in некоторые браузеры (IE9+, Chrome, Opera) выведут ключи не в том порядке, в котором они заданы, а в отсортированном порядке:

 

   
01 var codes = {
02   "255""Танзания",
03   "7""Россия",
04   "38""Украина",
05   "1""США"
06 };
07  
08 for (var key in codes) {
09   alert(key + ": "+codes[key]); // 1, 7, 38, 255 в IE9+, Chrome, Opera
10 }

 

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

В этом случае браузер сочтет ключи строковыми и сохранит порядок перебора:

 

   
01 var codes = {
02   "+255""Танзания"// передаем 255 в виде строки, чтобы браузер сохранил порядок
03   "+7""Россия",
04   "+38""Украина",
05   "+1""США"
06 };
07  
08 for (var key in codes ) {
09   var value = codes[key];
10   var id = +key; // ..если нам нужно именно число, преобразуем: "+255" -> 255
11   
12   alert( id + ": " + value ); // 255, 7, 38, 1 во всех браузерах
13 }

 

Передача по ссылке

Обычные значения: строки, числа, булевы значения, null/undefined копируются «по значению».

Это означает, что если в переменной message хранится значение "Привет", и ее скопировалиphrase = message, то значение копируются, и у нас будут две переменные, каждая из которых хранит значение: "Привет".

Объекты присваиваются и передаются «по ссылке».

В переменной хранится не сам объект, а ссылка на его место в памяти. Чтобы лучше понять это — сравним с обычными переменными.

Например:

var message = "Привет"// значение в переменной

 

Объекты как ассоциативные массивы

А вот как выглядит переменная user = { name: "Вася" }.

Внимание: объект — вне переменной. В переменной — лишь ссылка («адрес места в памяти, где лежит объект»).

Объекты как ассоциативные массивы

При копировании переменной с объектом — копируется эта ссылка, а объект по-прежнему остается в единственном экземпляре.

Получается, что несколько переменных ссылаются на один и тот же объект:

 

var user = { name: "Вася" }; // в переменной - ссылка
 
var admin = user; // скопировали ссылку

 

Объекты как ассоциативные массивы

Так как объект всего один, то в какой бы переменной его не меняли — это отражается на других:

 

   
1 var user = { name: 'Вася' };
2  
3 var admin = user;
4  
5 admin.name = 'Петя'// поменяли данные через admin
6  
7 alert(user.name); // 'Петя', изменения видны в user

 

 

Переменная с объектом как «код» к сейфу с данными

Еще одна аналогия: переменная, в которую присвоен объект, на самом деле хранит не сами данные, а код к сейфу, где они хранятся.

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

 

 

«Настоящее» копирование объекта

Итак, при передаче объекта куда-либо, копируется лишь ссылка на него.

Чтобы скопировать сами данные, нужно достать их из объекта и скопировать на уровне примитивов.

Примерно так:

   
01 function clone(obj) {
02   var obj2 = {};
03  
04   // если свойства могут быть объектами, то нужно перебирать и их
05   for(var key in obj) obj2[key] = obj[key];
06  
07   return obj2;
08 }
09  
10 var user = { name: 'Вася' }; // user - ссылка на объект
11  
12 var admin = clone(user);
13  
14 admin.name = 'Петя'// поменяли данные в admin
15 alert(user.name); // 'Вася'

 

 

 

Важность: 5

Создайте функцию multiplyNumeric, которая получает объект и умножает все численные свойства на 2. Например:

01 // до вызова
02 var menu = {
03     width: 200, 
04     height: 300,
05     title: "My menu"
06 };
07  
08 multiplyNumeric(menu);
09  
10 // после вызова
11 menu = {
12     width: 400,
13     height: 600,
14     title: "My menu"
15 };

 

P.S. Для проверки на число используйте функцию:

function isNumeric(n) {
  return !isNaN(parseFloat(n)) && isFinite(n)
}

 

Решение

 

   
01 var menu = {
02   width: 200,
03   height: 300,
04   title: "My menu"
05 };
06  
07 function isNumeric(n) {
08   return !isNaN(parseFloat(n)) && isFinite(n);
09 }
10  
11 function multiplyNumeric(obj) {
12   for(var key in obj) {
13     if (isNumeric( obj[key] )) {
14       obj[key] *= 2;
15     }
16   }
17 }
18  
19 multiplyNumeric(menu);
20  
21 alert("menu width="+menu.width+" height="+menu.height+" title="+menu.title);

 

[Открыть задачу в новом окне]

 

Компактное представление объектов

 

Hardcore coders only

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

 

Объект, в таком виде как он описывается — занимает много места в памяти, например:

1 var user = {
2   name: "Vasya",
3   age: 25
4 };
Здесь содержится информация о свойстве name и его строковом значении, а также о свойстве age и его численном значении. Представим, что таких объектов много.

 

Получится, что информация об именах свойств name и age дублируется в каждом объекте.

Чтобы избежать этого, браузеры используют специальное «компактное представление объектов».

При создании множества объектов одного и того же вида (с одинаковыми полями) интерпретатор запоминает, сколько у него полей и какие они, и хранит эти данные в отдельной структуре. А сам объект — в виде непрерывного массива данных.

Например, для объектов вида {name: "Вася", age: 25} будет создана структура, которая описывает данный вид объектов: «строка name, затем целое age», а сами объекты будут представлены в памяти данными: Вася25. Причем вместо строки обычно будет указатель на нее.

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

Что же происходит, если к объекту добавляется новое поле? Например:

user.admin = true;

 

В этом случае браузер смотрит, есть ли уже структура, под которую подходит такой объект («строкаname, целое age, логическое admin»). Если нет — она создается. Изменившиеся данные объекта привязываются к ней.

Детали применения и реализации этого способа хранения варьируются от браузера к браузеру. Применяются дополнительные оптимизации.

Более подробно внутреннем устройстве типов вы можете узнать, например, из презентации Know Your Engines (Velocity 2011).

Итого

Объекты — это ассоциативные массивы с дополнительными возможностями:

  • Доступ к элементам осуществляется:
    • Напрямую по ключу obj.prop = 5
    • Через переменную, в которой хранится ключ:
      var key = "prop";
      obj[key] = 5
  • Удаление ключей: delete obj.name.
  • Цикл по ключам: for (key in obj), порядок перебора соответствует порядку объявления для строковых ключей, а для числовых - зависит от браузера.
  • Существование свойства может проверять оператор inif ("prop" in obj), как правило, работает и просто сравнение if (obj.prop !== undefined).
  • Переменная хранит не сам объект, а ссылку на него. Копирование такой переменной и передача ее в функцию дублируют ссылку, но объект остается один.

К сожалению, в одной статье не просто дать все знания про объекты как ассоциативные массивы. Но я - старался. Если ты проявишь интерес к раскрытию подробностей,я обязательно напишу продолжение! Надеюсь, что теперь ты понял что такое объекты как ассоциативные массивы и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)

создано: 2014-10-07
обновлено: 2021-03-13
132714



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей



Комментарии


Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий, не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
To reply

Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)

Термины: Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)