aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/data_structures/index.html
blob: 71eeb219ef57abf159731517cc2a641615b79a4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
---
title: Типы данных JavaScript и структуры данных
slug: Web/JavaScript/Data_structures
tags:
  - JavaScript
  - Типы данных
  - Учебник
translation_of: Web/JavaScript/Data_structures
---
<div>{{jsSidebar("More")}}</div>

<p>Все языки программирования содержат встроенные типы данных, но они часто отличаются друг от друга в разных языках. Эта статья — попытка описать встроенные структуры (типы) данных, доступные в JavaScript, и их свойства. На их основе строятся другие структуры данных. Когда это возможно, то мы будем сравнивать типы данных в разных языках.</p>

<h2 id="Динамическая_типизация">Динамическая типизация</h2>

<p>JavaScript является <em>слабо типизированным</em> или <em>динамическим</em> языком. Это значит, что вам не нужно определять тип переменной заранее. Тип определится автоматически во время выполнения программы. Также это значит, что вы можете использовать одну переменную для хранения данных различных типов:</p>

<pre class="brush: js notranslate">var foo = 42; // сейчас foo типа Number
foo = "bar"; // а теперь foo типа String
foo = true;  // foo становится типа Boolean
</pre>

<h2 id="Типы_данных">Типы данных</h2>

<p>Стандарт ECMAScript определяет 9 типов:</p>

<ul>
 <li>6 типов данных являющихся примитивами:
  <ul>
   <li>{{Glossary("Undefined")}} (Неопределённый тип)  : <code>typeof instance === "undefined"</code></li>
   <li>{{Glossary("Boolean")}} (Булев, Логический тип) : <code>typeof instance === "boolean"</code></li>
   <li>{{Glossary("Number")}} (Число) : <code>typeof instance === "number"</code></li>
   <li>{{Glossary("String")}} (Строка) : <code>typeof instance === "string"</code></li>
   <li>{{Glossary("BigInt")}}  : <code>typeof instance === "bigint"</code></li>
   <li>{{Glossary("Symbol")}} (в ECMAScript 6)  : <code>typeof instance === "symbol"</code></li>
  </ul>
 </li>
 <li>{{Glossary("Null")}} (Null тип ) : <code>typeof instance === "object"</code>. Специальный примитив, используемый не только для данных но и в качестве указателя на финальную точку в <a href="/ru/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">Цепочке Прототипов</a>;</li>
 <li>{{Glossary("Object")}} (Объект) : <code>typeof instance === "object"</code>. Простая структура, используемая не только для хранения данных, но и для создания других структур, где любая структура создаётся с использованием ключевого слова <code><a href="/ru/docs/Web/JavaScript/Reference/Operators/new">new</a></code>: new <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a>, new <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a>, new <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Map">Map</a>, new <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Set">Set</a>, new <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/WeakMap">WeakMap</a>, new <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/WeakSet">WeakSet</a>, new <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Date">Date</a> и множество других структур;</li>
 <li>и {{Glossary("Function")}} : <code>typeof instance === "function"</code>. Специальный случай, упрощающий определение типа для Функций, несмотря на то, что все функции конструктивно унаследованы от Object.</li>
</ul>

<p>И здесь нам необходимо сделать предостережение относительно использования оператора <code>typeof</code> для определения типа структур, т.к. все структуры будут возвращать <code>"object"</code> при его использовании, так как назначение <code>typeof</code> -- проверка типа данных, но не структур. Если проверить тип структуры всё же необходимо, то в этом случае желательно использовать оператор <a href="/ru/docs/Web/JavaScript/Reference/Operators/instanceof">instanceof</a>, так как именно он отвечает на вопрос о том, какой конструктор был использован для создания структуры.</p>

<h2 id="Примитивные_значения">Примитивные значения</h2>

<p>Все типы данных в JavaScript, кроме объектов, являются иммутабельными (значения не могут быть модифицированы, а только перезаписаны новым полным значением). Например, в отличии от C, где строку можно посимвольно корректировать, в JavaScript строки пересоздаются только полностью. Значения таких типов называются «примитивными значениями».</p>

<h3 id="Булевый_тип_данных">Булевый тип данных</h3>

<p>Булевый тип представляет логическую сущность и имеет два значения: <code>true (истина)</code> и <code>false (ложь)</code>. Смотрите {{Glossary("Boolean")}} и {{jsxref("Boolean")}} для получения подробностей.</p>

<h3 id="Null">Null</h3>

<p>Этот тип данных имеет всего одно значение: <code>null</code>. Смотрите {{jsxref("null")}} и {{Glossary("Null")}} для получения подробностей.</p>

<h3 id="Undefined">Undefined</h3>

<p>Переменная, которой не было присвоено значение, будет иметь значение <code>undefined</code>. Смотрите {{jsxref("undefined")}} и {{Glossary("undefined")}} для получения подробностей.</p>

<h3 id="Числа">Числа</h3>

<p>В соответствии со стандартом ECMAScript, существует только один числовой тип, который представляет собой <a href="https://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%BE_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BD%D0%BE%D0%B9_%D1%82%D0%BE%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8">64-битное число двойной точности согласно стандарту IEEE 754</a>. Другими словами, <strong>специального типа для целых чисел в JavaScript нет</strong>. Это означает, что при числовых операциях вы можете получить неточное (округлённое) значение. В дополнение к возможности представлять числа с плавающей запятой, есть несколько символических значений: <code>+Infinity</code> (положительная бесконечность), <code>-Infinity</code> (отрицательная бесконечность), и <code>NaN</code> (не число).</p>

<p>Для получения самого большого или самого меньшего доступного значения в пределах <code>+/-Infinity</code>, можно использовать константы {{jsxref("Number.MAX_VALUE")}} или {{jsxref("Number.MIN_VALUE")}}. А начиная с ECMAScript 2015, вы также можете проверить, находится ли число в безопасном для целых чисел диапазоне, используя метод {{jsxref("Number.isSafeInteger()")}}, либо константы {{jsxref("Number.MAX_SAFE_INTEGER")}} и {{jsxref("Number.MIN_SAFE_INTEGER")}}. За пределами этого диапазона операции с целыми числами будут небезопасными, и возвращать приближённые значения.</p>

<p>Ноль в JavaScript имеет два представления: -0 и +0. («0» это синоним +0). На практике это имеет малозаметный эффект. Например, выражение <code>+0 === -0</code> является истинным. Однако, это может проявиться при делении на ноль:</p>

<pre class="brush: js notranslate"><code>&gt; 42 / +0
Infinity
&gt; 42 / -0
-Infinity</code></pre>

<p>Хотя число в большинстве случаев представляет только своё значение, JavaScript предоставляет <a href="/ru/JavaScript/Reference/Operators/Bitwise_Operators" title="en/JavaScript/Reference/Operators/Bitwise_Operators">несколько бинарных операций</a>. Они могут использоваться для того, чтобы представлять число как несколько булевых значений, с помощью <a class="external" href="https://ru.wikipedia.org/wiki/%D0%91%D0%B8%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BC%D0%B0%D1%81%D0%BA%D0%B0">битовой маски</a>. Это считается плохой практикой, так как JavaScript предлагает другие способы представления булевых значений (например, массив элементов с булевыми значениями или объект, содержащий набор булевых свойств). Кроме того, битовые маски часто делают код более трудным для чтения, понимания и дальнейшей поддержки. Эта техника может быть необходима в условиях технических ограничений, таких как объём локального хранилища данных, или в такой экстремальной ситуации, когда каждый бит передаваемый по сети на счету. Данный подход следует использовать как крайнюю меру, когда не остаётся других путей для необходимой оптимизации.</p>

<h3 id="Текстовые_строки">Текстовые строки</h3>

<p>В JavaScript для представления текстовых данных служит тип {{jsxref("Global_Objects/String", "String")}}. Он представляет собой цепочку «элементов» 16-битных беззнаковых целочисленных значений. Каждый такой элемент занимает свою позицию в строке. Первый элемент имеет индекс 0, следующий — 1, и так далее. Длина строки — это количество элементов в ней.</p>

<p>В отличие от языков подобных C, строки в JavaScript являются иммутабельными. Это означает, что после того, как строковое значение создано, его нельзя модифицировать. Остаётся лишь создать новую строку путём совершения некой операции над исходной строкой. Например:</p>

<ul>
 <li>Получить часть исходной строки выборкой отдельных символов, либо применением метода {{jsxref("String.substr()")}}.</li>
 <li>Объединить две строки в одну, применив оператор (<code>+</code>) или метод {{jsxref("String.concat()")}}.</li>
</ul>

<h4 id="Избегайте_повсеместного_использования_строк_в_своём_коде!">Избегайте повсеместного использования строк в своём коде!</h4>

<p>Иногда может показаться соблазнительным использование строк для представления сложных структур данных. Это даст небольшие краткосрочные выгоды:</p>

<ul>
 <li>Легко соединять данные в кучу сложением строк.</li>
 <li>Легко отлаживать (данные выглядят «как есть», в читаемом текстовом виде).</li>
 <li>Строки — это распространённый формат данных, используемый разнообразными API (<a href="/ru/docs/Web/API/HTMLInputElement" title="HTMLInputElement">поля ввода</a>, значения <a href="/ru/docs/Storage" title="Storage">локального хранилища</a>, {{ domxref("XMLHttpRequest") }} возвращает ответ в виде строки, и т. д.) и использовать только строки может показаться заманчивым.</li>
</ul>

<p>Несмотря на то, что в строке можно выразить данные любой сложности, делать это — не самая лучшая идея. Например, используя разделитель, строку можно использовать как список элементов (массив JavaScript будет более подходящим решением). К сожалению, если такой сепаратор встретится в значении одного из элементов, такой список будет сломан. Выходом может стать добавление символа экранирования, и т. д. Всё это потребует добавления множества ненужных правил, и станет обременительным при поддержке.</p>

<p>Используйте строки только для текстовых данных. Для составных структур преобразуйте строки в подобающие конструкции.</p>

<h3 id="Тип_данных_Символ_Symbol">Тип данных Символ (Symbol)</h3>

<p>Символы являются нововведением JavaScript начиная с ECMAScript 2015. Символ — это <strong>уникальное</strong> и <strong>иммутабельное</strong> примитивное значение, которое может быть использовано как ключ для свойства объекта (смотрите ниже). В некоторых языках программирования символы называются атомами. Их также можно сравнить с именованными значениями перечисления (enum) в языке C. Подробнее смотрите {{Glossary("Symbol")}} и {{jsxref("Symbol")}}.</p>

<h3 id="Тип_данных_Большое_целое_BigInt">Тип данных Большое целое (BigInt)</h3>

<p><code>BigInt</code><font><font> является встроенным объектом, который предоставляет способ представления целых чисел, которые больше 2 </font></font><sup><font><font>53</font></font></sup><font><font>, что является наибольшим числом, которое JavaScript может надёжно представить с помощью </font></font><code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number" title="JavaScript-объект Number - это объект-оболочка, позволяющий работать с числовыми значениями.  Объект Number создаётся с помощью конструктора Number ().  Номер объекта типа примитива создаётся с помощью функции Number ().">Number</a></code><font><font> примитива.</font></font></p>

<pre class="brush: js notranslate"><code>&gt; let bigInt = 19241924124n;
&gt; console.log(bigInt);
19241924124n
&gt; console.log(typeof bigInt);
</code>"bigint"</pre>

<h2 id="Объекты">Объекты</h2>

<p>В компьютерной терминологии, объект — это значение в памяти, на которое возможно сослаться с помощью {{Glossary("Identifier", "идентификатора")}}.</p>

<h3 id="Свойства">Свойства</h3>

<p>В JavaScript объект может расцениваться как набор свойств. <a href="/ru/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Object_literals">Литеральная инициализация объекта</a> задаёт определённое количество начальных свойств, и в процессе работы приложения поля могут добавляться и удаляться. Значения свойств могут иметь любой тип, включая другие объекты, что позволяет строить сложные, разветвлённые иерархии данных. Каждое свойство объекта идентифицируется ключом, в качестве которого может выступать значение с типом Строка или Символ.</p>

<p>Есть два типа свойств: свойство-значение и свойство-акцессор (свойство, обёрнутое в геттер и сеттер). Они отличаются определёнными атрибутами.</p>

<h4 id="Свойство-значение">Свойство-значение</h4>

<p>Ассоциирует ключ со значением, и имеет следующие атрибуты:</p>

<table>
 <caption>Атрибуты свойства-значения</caption>
 <tbody>
  <tr>
   <th>Атрибут</th>
   <th>Тип</th>
   <th>Описание</th>
   <th>Значение по умолчанию</th>
  </tr>
  <tr>
   <td>[[Value]]</td>
   <td>Любой тип JavaScript</td>
   <td>Значение, возвращаемое при обращении к свойству.</td>
   <td>undefined</td>
  </tr>
  <tr>
   <td>[[Writable]]</td>
   <td>Boolean</td>
   <td>Если <code>false</code>, то [[Value]] свойства не может быть изменено.</td>
   <td>false</td>
  </tr>
  <tr>
   <td>[[Enumerable]]</td>
   <td>Boolean</td>
   <td>Если <code>true</code>, свойство будет перечислено в цикле <a href="/ru/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a>. Смотрите подробнее <a href="/ru/docs/Web/JavaScript/Enumerability_and_ownership_of_properties">Перечисляемость и владение свойствами</a>.</td>
   <td>false</td>
  </tr>
  <tr>
   <td>[[Configurable]]</td>
   <td>Boolean</td>
   <td>Если <code>false</code>, то свойство не может быть удалено, а его атрибуты, кроме [[Value]] и [[Writable]] не могут быть изменены.</td>
   <td>false</td>
  </tr>
 </tbody>
</table>

<table>
 <caption>Устаревшие атрибуты (присутствуют в ECMAScript 3, но переименованы в ECMAScript 5)</caption>
 <tbody>
  <tr>
   <th>Атрибут</th>
   <th>Тип</th>
   <th>Описание</th>
  </tr>
  <tr>
   <td>Read-only</td>
   <td>Boolean</td>
   <td>Зарезервировано по атрибуту [[Writable]] ES5.</td>
  </tr>
  <tr>
   <td>DontEnum</td>
   <td>Boolean</td>
   <td>Зарезервировано по атрибуту [[Enumerable]] ES5.</td>
  </tr>
  <tr>
   <td>DontDelete</td>
   <td>Boolean</td>
   <td>Зарезервировано по атрибуту [[Configurable]] ES5.</td>
  </tr>
 </tbody>
</table>

<h4 id="Свойство-акцессор">Свойство-акцессор</h4>

<p>Ассоциирует ключ с одной из двух функций-акцессоров (геттер и сеттер) для получения или изменения значения свойства, и имеет следующий атрибуты:</p>

<table>
 <caption>Атрибуты свойства-акцессора</caption>
 <tbody>
  <tr>
   <th>Атрибут</th>
   <th>Тип</th>
   <th>Описание</th>
   <th>Значение по умолчанию</th>
  </tr>
  <tr>
   <td>[[Get]]</td>
   <td>Function или undefined</td>
   <td>Функция вызывается без параметров и возвращает значение свойства каждый раз, когда происходит чтение свойства. Смотрите также <a href="/ru/docs/Web/JavaScript/Reference/Operators/get"><code>get</code></a>.</td>
   <td>undefined</td>
  </tr>
  <tr>
   <td>[[Set]]</td>
   <td>Function или undefined</td>
   <td>Функция вызывается с одним аргументом, содержащим присваиваемое значение, каждый раз, когда происходит попытка присвоить свойству новое значение. Смотрите также <a href="/ru/docs/Web/JavaScript/Reference/Operators/set"><code>set</code></a>.</td>
   <td>undefined</td>
  </tr>
  <tr>
   <td>[[Enumerable]]</td>
   <td>Boolean</td>
   <td>Если <code>true</code>, свойство будет перечислено в цикле <a href="/ru/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a>.</td>
   <td>false</td>
  </tr>
  <tr>
   <td>[[Configurable]]</td>
   <td>Boolean</td>
   <td>Если <code>false</code>, то свойство не может быть удалено, и не может быть преобразовано в свойство-значение.</td>
   <td>false</td>
  </tr>
 </tbody>
</table>

<div class="note">
<p><strong>Примечание: </strong>Атрибуты обычно используются движком JavaScript, поэтому вы не можете обратиться к ним напрямую (смотрите подробнее <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty()</a>). Вот почему в таблицах выше они помещены в двойные квадратные скобки вместо одиночных.</p>
</div>

<h3 id="«Обычные»_объекты_и_функции">«Обычные» объекты и функции</h3>

<p>Объект JavaScript — это таблица соотношений между ключами и значениями. Ключи — это строки (или {{jsxref("Symbol")}}), а значения могут быть любыми. Это делает объекты полностью отвечающими определению <a href="https://ru.wikipedia.org/wiki/%D0%A5%D0%B5%D1%88-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0">хеш-таблицы</a>.</p>

<p>Функции — это обычные объекты, имеющие дополнительную возможность быть вызванными для исполнения.</p>

<h3 id="Даты">Даты</h3>

<p>Для работы с датами служит встроенный глобальный объект <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Date"><code>Date</code></a>.</p>

<h3 id="Массивы_общие_и_типизированные">Массивы общие и типизированные</h3>

<p><a href="/ru/docs/JavaScript/Reference/Global_Objects/Array" title="Array">Массив</a> — это обычный объект с дополнительной связью между целочисленными ключами его свойств и специальным свойством length. Вдобавок ко всему, массивы наследуют <code>Array.prototype</code>, предоставляющий исчерпывающий набор методов для манипуляции массивами. Например, метод <code><a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf" title="en/JavaScript/Reference/Global_Objects/Array/indexOf">indexOf</a></code> (служит для поиска значения в массиве), <code><a href="/ru/docs/JavaScript/Reference/Global_Objects/Array/push" title="en/JavaScript/Reference/Global_Objects/Array/push">push</a></code> (добавляет элемент в конец массива) и т. д. Всё это делает массив идеальным кандидатом для представления списков и перечислений.</p>

<p><a href="/ru/docs/Web/JavaScript/Typed_arrays">Типизированный массив</a> является новинкой ECMAScript Edition 6 и является массивоподобным представлением для лежащего в его основе бинарного буфера памяти. Следующая таблица поможет вам найти соответствующие типы языка C:</p>

<p>{{page("/ru/docs/Web/JavaScript/Reference/Global_Objects/TypedArray", "Объекты_TypedArray", "", 0, 3)}}</p>

<h3 id="Коллекции_Maps_Sets_WeakMaps_WeakSets">Коллекции: Maps, Sets, WeakMaps, WeakSets</h3>

<p>Эти наборы данных используют ссылку на объект в качестве ключа, и введены в JavaScript с приходом ECMAScript Edition 6. {{jsxref("Set")}} и {{jsxref("WeakSet")}} являют собой набор уникальных объектов, в то время как {{jsxref("Map")}} и {{jsxref("WeakMap")}} ассоциируют с объектом (выступающим в качестве ключа) некоторое значение. Разница между Map и WeakMap заключается в том, что только у Map ключи являются перечисляемыми. Это позволяет оптимизировать сборку мусора для WeakMap.</p>

<p>Можно было бы написать собственную реализацию Map и Set на чистом ECMAScript 5. Однако, так как объекты нельзя сравнивать на больше или меньше, то производительность поиска в самодельной реализации будет вынужденно линейной. Нативная реализация (включая WeakMap) имеет производительность логарифмически близкую к константе.</p>

<p>Обычно, для привязки некоторых данных к узлу DOM, приходится устанавливать свойства этому узлу непосредственно, либо использовать его атрибуты <code>data-*</code>. Обратной стороной такого подхода является то, что эти данные будут доступны любому скрипту, работающему в том же контексте. Maps и WeakMaps дают возможность приватной привязки данных к объекту.</p>

<h3 id="Структурированные_данные_JSON">Структурированные данные: JSON</h3>

<p>JSON (JavaScript Object Notation) — это легковесный формат обмена данными, происходящий от JavaScript, но используемый во множестве языков программирования. JSON строит универсальные структуры данных. Смотрите {{Glossary("JSON")}} и {{jsxref("JSON")}} для детального изучения.</p>

<h3 id="Больше_объектов_и_стандартная_библиотека">Больше объектов и стандартная библиотека</h3>

<p>JavaScript имеет стандартную библиотеку встроенных объектов. Пожалуйста, обратитесь к <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects">справочнику</a>, чтобы найти описание всех объектов доступных для работы.</p>

<h2 id="Определение_типов_оператором_typeof">Определение типов оператором <code>typeof</code></h2>

<p>Оператор <code>typeof</code> может помочь определить тип вашей переменной. Смотрите <a href="/ru/docs/Web/JavaScript/Reference/Operators/typeof">страницу документации</a>, где приведены его детали и случаи использования.</p>

<h2 id="Спецификации">Спецификации</h2>

{{Specifications}}

<h2 id="Смотрите_также">Смотрите также</h2>

<ul>
 <li><a href="https://github.com/nzakas/computer-science-in-javascript/">Nicholas Zakas, коллекция некоторых классических структур данных и алгоритмов, написанных на JavaScript.</a></li>
 <li><a href="https://github.com/monmohan/DataStructures_In_Javascript">Реализация некоторых структур данных для JavaScript</a></li>
</ul>