Типы данных в ES2015. Какие есть типы, какие из них примитивные, в чём разница и каковы особенности? Для каких есть литералы? Оператор typeof.

Типы данных в ES2015. Какие есть типы, какие из них примитивные, в чём разница и каковы особенности? Для каких есть литералы? Оператор typeof.

В JavaScript есть 6 «примитивных» типов: number, string, boolean, symbol, null, undefined и 7-й тип – объекты object.

Число «number»

Тип number используется как для целых, так и для дробных чисел. Существуют специальные числовые значения Infinity (бесконечность) и NaN (ошибка вычислений). Эти значения формально принадлежат типу «число», хотя, конечно, числами в их обычном понимании не являются.

Строка «string»

В JavaScript одинарные и двойные кавычки равноправны. Можно использовать или те или другие. Тип char (символ) не существует, есть только string.

Булевый (логический) тип «boolean»

У него всего два значения: true (истина) и false (ложь). Как правило, такой тип используется для хранения значения типа да/нет.

Ложные значения: false, null, undefined, '', 0, NaN.

Все остальные — истина.

Тип данных «symbol»

Symbol служит для создания уникальных идентификаторов.

Специальное значение «null»

Значение null не относится ни к одному из типов выше, а образует свой отдельный тип, состоящий из единственного значения null. В JavaScript null не является «ссылкой на несуществующий объект» или «нулевым указателем», как в некоторых других языках. Это просто специальное значение, которое имеет смысл «ничего» или «значение неизвестно».

Специальное значение «undefined»

Значение undefined, как и null, образует свой собственный тип, состоящий из одного этого значения. Оно имеет смысл «значение не присвоено». Если переменная объявлена, но в неё ничего не записано, то её значение как раз и есть undefined.

Объекты «object»

Первые 6 типов называют «примитивными». Отдельно стоит седьмой тип: «объекты». Он используется для коллекций данных и для объявления более сложных сущностей.

Объявляются объекты при помощи фигурных скобок.

Оператор «typeof»

Оператор typeof возвращает тип аргумента. Результатом typeof является строка, содержащая тип:

typeof undefined; //"undefined"

typeof 0; //"number"

typeof true; //"boolean"

typeof "off"; //"string"

typeof {}; //"object"

let sym = Symbol();

typeof sym; //symbol

typeof null; //"object"

typeof function() {} //"function"

В последних двух строках typeof ведет себя по-особому:

ü Результат typeof null == "object" – это официально признанная ошибка в языке, которая сохраняется для совместимости. На самом деле null – это не объект, а отдельный тип данных.

ü Функции не являются отдельным базовым типом в JavaScript, а подвидом объектов. Но typeof выделяет функции отдельно, возвращая для них "function". На практике это весьма удобно, так как позволяет легко определить функцию.

Литералы:

Численный — 123

Строковый — '', "", ``

Объекта — {}

Массива — []

Функции — function() {}, () => {}

Регулярного выражения — /^.*$/gim

Доступ к символам

charAt( index: number ): string

— получить символ в заданной позиции (от нуля). Если запрошенная позиция выходит за пределы строки, вернётся пустая строка.

'text'.charAt( 1 ); // 'e'

'text'.charAt( -1 ); // ''

'text'.charAt( 10 ); // ''

'text'.charAt( 0 ); // 't'

Также для доступа к символу можно использовать квадратные скобки:

‘text’ [0]; // "t"

Разница между этим способом и charAt заключается в том, что если символа нет – charAt выдает пустую строку, а скобки – undefined:

"".charAt(0); // пустая строка

"" [0]; // undefined

Изменения строк

Содержимое строки в JavaScript нельзя изменять. Нельзя взять символ посередине и заменить его. Как только строка создана – она такая навсегда.

Можно лишь создать целиком новую строку и присвоить в переменную вместо старой, например:

let str = "строка";

str = str[3] + str[4] + str[5];

alert( str ); // ока

Смена регистра

Методы toLowerCase() и toUpperCase() меняют регистр строки на нижний/верхний:

"Интерфейс".toUpperCase(); // ИНТЕРФЕЙС

Пример ниже получает первый символ и приводит его к нижнему регистру:

"Интерфейс" [0].toLowerCase(); // 'и'

Поиск подстроки

indexOf( searchString: string, fromIndex?: number )

- возвращает позицию, на которой находится подстрока или -1, если ничего не найдено. Например:

'test text'.indexOf( 't' ) // 0

'test text'.indexOf( 't', 1 ) // 3

'test text'.indexOf( 'te', 1 ) // 5

'test text'.indexOf( 'z' ) // -1

lastIndexOf( searchString: string, toIndex?: number )

— находит последнее вхождение подстроки `searchString` в строке до позиции `toIndex` (0..длина), если указана, иначе — до конца строки. Возвращается позиция первого символа (от нуля), или «-1», если вхождения нет.

'test text'.lastIndexOf( 't' ) // 8

'test text'.lastIndexOf( 't', 7 ) // 5

'test text'.lastIndexOf( 'te' ) // 5

'test text'.lastIndexOf( 'z' ) // -1

includes( searchString: string, position?: number ): Boolean

— проверяет вхождение подстроки `searchString` в строке, начиная от позиции `position` (0..длина), если указана, иначе — с начала строки. Возвращает `true`, если подстрока найдена, иначе — `false`.

'test text'.includes( 't' ) // true

'test text'.includes( 'st' ) // true

'test text'.includes( 'st', 3 ) // false

'test text'.includes( 'z' ) // false

endsWith( searchString: string, endPosition?: number ): Boolean

— проверяет, что строка завершается подстрокой `searchString`. Если указано `endPosition`, то строка считается данной длины, иначе поиск идёт до конца строки.

'test text'.endsWith( 't' ) // true

'test text'.endsWith( 'x' ) // false

'test text'.endsWith( 'st', 4 ) // true

'test text'.endsWith( 'st', 5 ) // false

Взятие подстроки: substr, substring, slice

В JavaScript существуют целых 3 метода для взятия подстроки, с небольшими отличиями между ними.

substring(start [, end])

- возвращает подстроку с позиции start до, но не включая end. Если аргумент end отсутствует, то идет до конца строки.

‘stringify’.substring(0,1)); // "s"

‘stringify’.substring(2)); // "ringify"

substr(start [, length])

- первый аргумент имеет такой же смысл, как и в substring, а второй содержит не конечную позицию, а количество символов. Если второго аргумента нет – подразумевается «до конца строки».

‘stringify’.substr(2,4); // ring

slice(start [, end])

- возвращает часть строки от позиции start до, но не включая, позиции end.

Отрицательные аргументы

Различие между substring и slice – в том, как они работают с отрицательными и выходящими за границу строки аргументами:

substring(start, end)

Отрицательные аргументы интерпретируются как равные нулю. Слишком большие значения усекаются до длины строки:

"testme".substring(-2); // "testme", -2 становится 0

Кроме того, если start > end, то аргументы меняются местами, т.е. возвращается участок строки междуstart и end:

"testme".substring(4, -1); // "test"

// -1 становится 0 -> получили substring(4, 0)

// 4 > 0, так что аргументы меняются местами -> substring(0, 4) = "test"

slice(start [, end])

Отрицательные значения отсчитываются от конца строки:

"testme".slice(-2); // "me", от 2 позиции с конца

"testme".slice(1, -1); // "estm", от 1 позиции до первой с конца.

Кодировка Юникод

charCodeAt( index: number ): number

— возвращает числовой Unicode-код символа (0…65535). При выходе за диапазон возвращает NaN.

'text'.charCodeAt( 1 ) // 101

'text'.charCodeAt( 10 ) // NaN

codePointAt( position: number ): number | undefined

— возвращает числовой Unicode-код символа с подержкой суррогатных пар (два 16-битных значения, где каждое значение лежит в диапазоне от 0xD800 и до 0xDFFF; другими словами, два «типа символа» образуют один «настоящий» символ). Если в указанной позиции нет символа, возвращается `undefined`.

'text'.codePointAt( 1 ) // 101

'text'.codePointAt( 10 ) // undefined

'\uD800\uDC00'.codePointAt( 0 ) // 65536

Другие методы

concat( ...strings: string[] ): string

— объединение двух или более строк. Объединение через оператор «+» является предпочтительнее.

't'.concat( 'e', 'x', 't' ) // 'text'

localeCompare( compareString: string ): number

— сравнивает две строки. Если compareString больше — результат отрицательный, меньше — положительный, равны — нулевой.

'a'.localeCompare( 'b' ) // -1

'a'.localeCompare( 'c' ) // -1

'ё'.localeCompare( 'я' ) // -1

trim(): string

— удаляет интервальные символы по сторонам строки (пробелы, табуляцию, переводы строк).

' test \t\n '.trim() === 'test'

search( regexp: string | RegExp ): number

— находит первое совпадение регулярного выражения со строкой. Глобальный поиск не осуществляет (флаг «g» не учитывается).

'test text'.search( /.t/ ) // 2

'test text'.search( '.t' ) // 2

'test text'.search( /^.t/ ) // -1

match( regexp: string | RegExp ): RegExpMatchArray | null

— возвращает перечень совпадений регулярного выражения по строке.

'test text'.match( /.t/g ) // [ 'st', ' t', 'xt' ]

replace( searchValue: string | RegExp, replaceValue: string | Function )

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

Строка замены понимает следующие мета-последовательности:

* `$$` — символ «$»

* `$&` — совпавшая подстрока

* `$`` — часть строки до совпадения

* `$'` — часть строки после совпадения

* `$1`, `$2`, … — результат совпадения соответствующего подшаблона регулярного выражения

Функция замены принимает следующие аргументы:

* math — совпавшая подстрока

* p1, p2, … — результат совпадения соответствующего подшаблона регулярного выражения

* offset — позиция подстроки в строке

* string — исходная строка

'test text'.replace( 'te', 'be' ) // 'best text'

'test text'.replace( /te/, 'be' ) // 'best text'

'test text'.replace( /te/g, 'be' ) // 'best bext'

'test text'.replace( ' ', '[$`]<$&>($\')' ) // 'test[test]< >(text)text'

split( [separator][, limit] )

— разделяет строку на массив подстрок.

separator — разделитель строки, может быть строкой или регулярным выражением.

limit — устанавливает ограницение на количество разделяемых частей.

'test text'.split() // [ 'test text' ]

'test text'.split( '' ) // ['t', 'e', 's', 't', ' ', 't', 'e', 'x', 't']

'test text'.split( ' ' ) // [ 'test', 'text' ]

'test text'.split( 't' ) // [ '', 'es', ' ', 'ex', '' ]

'test text'.split( 't', 3 ) // [ '', 'es', ' ' ]

String.fromCharCode( num1, ..., numN )

— строка из кодов символов.

String.fromCharCode( 65, 66, 67 ) // ABC

Строковые шаблоны

Добавлен новый вид кавычек для строк:

let str = `обратные кавычки`;

Основные отличия:

ü Поддерживают многострочность

`моя

многострочная

строка`;

ü Можно вставлять выражения при помощи${…}

`2 + 3 = ${2 + 3}`; // 2 + 3 = 5

При помощи ${…} можно вставлять как значение переменной, так и более сложные выражения, которые могут включать в себя операторы, вызовы функций и т.п. Такую вставку называют «интерполяцией».

ü Поддерживают тег-функцию

Название этой функции ставится перед первой обратной кавычкой:

let str = func`моя строка`;

Эта функция будет автоматически вызвана и получит в качестве аргументов строку, разбитую по вхождениям параметров ${…} и сами эти параметры.

function myTag( strings, ...values )

{

console.log( strings );

console.log( strings.raw );

console.log( values );

return `[${strings.join( '][' )}]`;

}

myTag`Test \u263A ${1} template ${2} literal ${3} string`

В strings.raw содержатся участки строки в «изначально введённом» виде. То есть, если в строке находится \n или \u1234 или другое особое сочетание символов, то оно таким и останется.

Объявление

let sym = Symbol();

Не new Symbol, а просто Symbol, так как это – примитив. Каждый символ – уникален. У функции Symbol есть необязательный аргумент «имя символа». Его можно использовать для описания символа, в целях отладки, но при этом, если у двух символов одинаковое имя, то это не значит, что они равны.

Глобальные символы

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

// создание символа в реестре

let name = Symbol.for("name");

Таким образом, можно из разных частей программы, обратившись к реестру, получить единый глобальный символ с именем "name".

У вызова Symbol.for, который возвращает символ по имени, есть обратный вызов – Symbol.keyFor(sym). Он позволяет получить по глобальному символу его имя:

// получение имени символа

Symbol.keyFor(name); // name

Symbol.keyFor возвращает undefined, если символ не глобальный.

Использование символов

Самое широкое применение символов предусмотрено внутри самого стандарта JavaScript. В современном стандарте есть много системных символов. Их список есть в спецификации, в таблице Well-known Symbols. В спецификации для краткости символы принято обозначать как „@@имя“, например @@iterator, но доступны они как свойства Symbol.

Например:

· Symbol.toPrimitive – идентификатор для свойства, задающего функцию преобразования объекта в примитив.

· Symbol.iterator – идентификатор для свойства, задающего функцию итерации по объекту.

Допустим, в новом стандарте нам надо добавить к объекту «особый» функционал, например, функцию, которая задаёт преобразование объекта к примитиву. Мы ведь не можем просто сказать, что «свойство obj.toPrimitive теперь будет задавать преобразование к примитиву и автоматически вызываться в таких-то ситуациях». Это опасно. Мы не можем так просто взять и придать особый смысл свойству. Мало ли, вполне возможно, что свойство с таким именем уже используется в существующем коде, и если сделать его особым, то он сломается. Нельзя просто взять и зарезервировать какие-то свойства существующих объектов для нового функционала. Поэтому ввели целый тип «символы». Их можно использовать для задания таких свойств, так как они: уникальны; не участвуют в циклах; заведомо не сломают старый код, который о них слыхом не слыхивал. Чтобы получить все символы объекта, есть особый вызов Object.getOwnPropertySymbols. Эта функция возвращает все символы в объекте (и только их).

Специальные значения

Интуитивно, значенияnull/undefinedассоциируются с нулём, но при преобразованиях ведут себя иначе.Специальные значения преобразуются к числу так:

Значение Преобразуется в
undefined NaN
null

Это преобразование осуществляется при арифметических операциях и сравнениях >, >=, <, <=, но не при проверке равенства ==. В нём считается, что null и undefined равны "==" между собой, но эти значения не равны никакому другому значению. Это ведёт к забавным последствиям.

alert( null >= 0 ); // true, т.к. null преобразуется к 0

alert( null > 0 ); // false, т.к. null преобразуется к 0

alert( null == 0 ); // false, т.к. == рассматривает null особо.

alert( undefined > 0 ); // false, т.к. undefined -> NaN

alert( undefined == 0 ); // false, т.к. это undefined (без преобразования)

alert( undefined < 0 ); // false, т.к. undefined -> NaN

Логическое преобразование

Преобразование к true/false происходит в логическом контексте, таком как if(value), и при применении логических операторов.

Все значения, которые интуитивно «пусты», становятся false. Их несколько: 0, пустая строка, null, undefined и NaN. Остальное, в том числе и любые объекты – true.

Полная таблица преобразований:

Значение Преобразуется в
undefined, null false
Числа Все true, кроме 0, NaN - false.
Строки Все true, кроме пустой строки "" - false
Объекты Всегда true

Для явного преобразования используется двойное логическое отрицание!!valueили вызовBoolean(value).

Встроенные модальные окна.

alert

Синтаксис:

alert(сообщение);

alert выводит на экран окно с сообщением и приостанавливает выполнение скрипта, пока пользователь не нажмёт «ОК». Окно сообщения, которое выводится, является модальным окном. Слово «модальное» означает, что посетитель не может взаимодействовать со страницей, нажимать другие кнопки и т.п., пока не разберётся с окном. В данном случае – пока не нажмёт на «OK».

prompt

Функция prompt принимает два аргумента:

result = prompt(title, default);

Она выводит модальное окно с заголовком title, полем для ввода текста, заполненным строкой по умолчанию default и кнопками OK/CANCEL. Пользователь должен либо что-то ввести и нажать OK, либо отменить ввод кликом на CANCEL или нажатием Esc на клавиатуре. Вызов prompt возвращает то, что ввёл посетитель – строку или специальное значение null, если ввод отменён.

confirm

Синтаксис:

result = confirm(question);

confirm выводит окно с вопросом question с двумя кнопками: OK и CANCEL. Результатом будет true при нажатии OK и false – при CANCEL(Esc).

ArrayBuffer

Объект ArrayBuffer представляет собой буфер необработанных данных, в котором хранятся данные для разных типизированных массивов. ArrayBuffer недоступен для чтения или записи данных, но позволяет передать его в типизированный массив или объект DataView для интерпретации необработанного буфера. ArrayBuffer можно использовать для хранения любого рода данных (или смешанных типов данных).

DataView

Объект DataView можно использовать для чтения и записи различных типов двоичных данных в любое место ArrayBuffer.

Типизированные массивы

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

Название Размер (в байтах) Описание
Объект Int8Array 8-разрядное целое число со знаком
Объект Uint8Array 8-разрядное целое число без знака
Объект Int16Array 16-разрядное целое число со знаком
Объект Uint16Array 16-разрядное целое число без знака
Объект Int32Array 32-разрядное целое число со знаком
Объект Uint32Array 32-разрядное целое число без знака
Объект Float32Array 32-разрядное число с плавающей точкой
Объект Float64Array 64-разрядное число с плавающей точкой

Варианты объявления функций в ES2015, чем они отличаются?

Стандартные способы, которые появились в ранних версиях

// Function Declaration

function sum1(a, b) {

return a + b;

};

// Function Expression

const sum2 = function (a, b) {

return a + b;

};

Основное отличие в том, что Function Declaration, создаются интерпретатором до выполнения кода. Это называется "поднятие функции", то есть функцию можно вызвать до ее объявления.

Параметры по умолчанию

Можно указывать параметры по умолчанию через равенство =, например:

function showMenu(title = "Без заголовка", width = 100, height = 200) {

alert(title + ' ' + width + ' ' + height);

}

showMenu("Меню"); // Меню 100 200

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

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

function sayHi(who = getCurrentUser().toUpperCase()) {

alert('Привет, ' + who);

}

function getCurrentUser() {

return 'Вася';

}

sayHi(); // Привет, ВАСЯ

Заметим, что значение выражения getCurrentUser().toUpperCase() будет вычислено, и соответствующие функции вызваны – лишь в том случае, если это необходимо, то есть когда функция вызвана без параметра.

Создание

Для создания нового объекта типа Date используется один из синтаксисов:

new Date()

Создает объект Date с текущей датой и временем:

var now = new Date();

new Date(milliseconds)

Создает объект Date, значение которого равно количеству миллисекунд (1/1000 секунды), прошедших с 1 января 1970 года GMT+0.

var Jan02_1970 = new Date(3600 * 24 * 1000);

new Date(datestring)

Если единственный аргумент – строка, используется вызов Date.parse для чтения даты из неё. Метод Date.parse(str) разбирает строку str в формате YYYY-MM-DDTHH:mm:ss.sssZ и возвращает соответствующее ей количество миллисекунд. Если это невозможно, Date.parse возвращает NaN. Например:

var msUTC = Date.parse('2012-01-26T13:51:50.417Z'); // зона UTC

alert( msUTC ); // 1327571510417 (число миллисекунд)

С таймзоной -07:00 GMT:

var ms = Date.parse('2012-01-26T13:51:50.417-07:00');

alert( ms ); // 1327611110417 (число миллисекунд)

new Date(year, month, date, hours, minutes, seconds, ms)

Дату можно создать, используя компоненты в местной временной зоне. Для этого формата обязательны только первые два аргумента. Отсутствующие параметры, начиная с hours считаются равными нулю, а date – единице. Год year должен быть из 4 цифр. Отсчет месяцев month начинается с нуля 0.

new Date(2011, 0, 1); // 1 января 2011, 00:00:00

Получение компонентов даты

getFullYear() - получить год (из 4 цифр)

getMonth() - получить месяц, от 0 до 11.

getDate() - получить число месяца, от 1 до 31.

getHours(), getMinutes(), getSeconds(), getMilliseconds() - получить соответствующие компоненты.

getDay() - получить номер дня в неделе. Неделя в JavaScript начинается с воскресенья, так что результат будет числом от 0(воскресенье) до 6(суббота).

Все методы, указанные выше, возвращают результат для местной временной зоны. Существуют также UTC-варианты этих методов, возвращающие день, месяц, год и т.п. для зоны GMT+0 (UTC): getUTCFullYear(), getUTCMonth(), getUTCDay().

Кроме описанных выше, существуют два специальных метода без UTC-варианта:

getTime() - возвращает число миллисекунд, прошедших с 1 января 1970 года GMT+0.

getTimezoneOffset() - возвращает разницу между местным и UTC-временем, в минутах.

Установка компонентов даты

Следующие методы позволяют устанавливать компоненты даты и времени:

ü setFullYear(year[, month, date])

ü setMonth(month[, date])

ü setDate(date)

ü setHours(hour[, min, sec, ms])

ü setMinutes(min[, sec, ms])

ü setSeconds(sec[, ms])

ü setMilliseconds(ms)

ü setTime(milliseconds) (устанавливает всю дату по миллисекундам с 01.01.1970 UTC)

Все они, кроме setTime(), обладают также UTC-вариантом, например: setUTCHours().

Автоисправление даты

Автоисправление – очень удобное свойство объектов Date. Оно заключается в том, что можно устанавливать заведомо некорректные компоненты (например 32 января), а объект сам себя поправит.

var d = new Date(2013, 0, 32); // 32 января 2013 ?!?

alert(d); // это 1 февраля 2013!

Форматирование и вывод дат

Во всех браузерах, кроме IE10-, поддерживается новый стандарт Ecma 402, который добавляет специальные методы для форматирования дат.

Это делается вызовом date.toLocaleString(локаль, опции), в котором можно задать много настроек. Он позволяет указать, какие параметры даты нужно вывести, и ряд настроек вывода, после чего интерпретатор сам сформирует строку. Пример с почти всеми параметрами даты и русским, затем английским (США) форматированием:

var date = new Date(2014, 11, 31, 12, 30, 0);

var options = {

era: 'long',

year: 'numeric',

month: 'long',

day: 'numeric',

weekday: 'long',

timezone: 'UTC',

hour: 'numeric',

minute: 'numeric',

second: 'numeric'

};

date.toLocaleString("ru", options); // среда, 31 декабря 2014 г. н.э. 12:30:00

date.toLocaleString("en-US", options); // Wednesday, December 31, 2014 Anno Domini 12:30:00 PM

Методы вывода без локализации:

toString(), toDateString(), toTimeString() - возвращают стандартное строчное представление, не заданное жёстко в стандарте, а зависящее от браузера. Единственное требование к нему – читаемость человеком. Метод toString возвращает дату целиком, toDateString() и toTimeString() – только дату и время соответственно.

Метод Date.now()

Метод Date.now() возвращает дату сразу в виде миллисекунд.

16. Объект как хеш-таблица.

Определение объекта в JavaScript

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

Простой пример объекта в JavaScript:

var person = {

firstName: 'Frank',

lastName: 'Johnson'

};

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

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

В JavaScript существует три способа создания объектов: с помощью литерала объекта, с помощью конструктора Object и с помощью метода Object.create (последний способ предусмотрен только в стандарте ECMAScript 5).

Литералы объектов

Литерал объекта представляет собой фигурные скобки, внутри которых через запятую перечислены свойства:

// Пример пустого объектаvar emptyObject = {}; // Объект, имеющий свойстваvar cat = { color: 'gray', age: 2, say: function() { console.log('Miu miu'); },}

Конструктор Object

Второй способ создания объектов в JavaScript — использование конструктора Object:

var cat = new Object();cat.color = 'gray';cat.age = 2;cat.say = function() { console.log('Miu miu');}

Метод Object.create()

Этот метод принимает один обязательный параметр — прототип создаваемого объекта, и второй необязательный — список свойств объекта. Чтобы создать объект без прототипа, можно вызвать метод Object.create() c параметром null. Рассмотрим примеры:

// Создание объекта, не имеющего прототипаvar emptyObject = Object.create(null); // Объект car наследует свойства wheels и speedvar car = Object.create({ wheels: 4, speed: 100 }); // Пустой объект с прототипом Object.prototype (аналог new Object() или {})var myObject = Object.create(Object.prototype);

Доступ к свойствам объекта

Получить значение свойства объекта можно, указав имя свойства через точку:

console.log(cat.color);

Или указав имя свойства в квадратных скобках:

console.log(cat[color]);

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

Если мы пытаемся обратиться к свойству объекта, которого не существует — будет возвращено значение undefined. Однако попытка получить свойство значения null или undefined вызовет ошибку.

Объект имеет как собственные свойства (определенные в нем), так и унаследованные (определенные в цепочке прототипов). Проверить, имеет ли объект определенное свойство (собственное или унаследованное), можно с помощью оператора in:

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

var cat = { color: 'gray' };

// Проверяем, существует ли свойство 'color'

console.log('color' in cat); // true

// Проверяем, существует ли свойство toString (существует в прототипе Object.prototype)

console.log('toString' in cat); // true

Если нужно проверить только собственные свойства объекта, можно использовать метод hasOwnProperty():

console.log(cat.hasOwnProperty('color')); // true

console.log(cat.hasOwnProperty('toString')); //false

Также получить свойства объекта можно в цикле:

var person = {

name: 'John',

lastName: 'Smith',

age: 32

};

for (var item in person) {

console.log(item);

}

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

Атрибуты свойств

value — содержит непосредственно данные

writable — определяет, доступно ли данное свойство для записи (по умолчанию, true)

set — содержит setter, функцию, которая вызывается при записи свойства

get — содержит getter, функцию, которая вызывается при чтении свойства

enumerable — определяет доступность свойства для перечисления

configurable — определяет доступность свойства для изменения (например, может ли свойство быть удалено, может ли быть изменен какой-либо атрибут свойства)

Дескрипторы свойств

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

Получим дескрипторы свойств объекта circle:

var circle = { x: 0, y: 0, r: 15,};console.log(Object.getOwnPropertyDescriptor(circle, 'r'));/* Получим объект{ configurable: true, enumerable: true, value: 15, writable: true,}*/

С дескрипторами свойств также работают следующие функции:

Object.defineProperty() — создает или изменяет свойство объекта, возвращает модифицированный объект:

const bob2 = {

age: 20,

};

Object.defineProperty(

bob2,

'name',

{

value: 'Bob',

}

);

Object.defineProperty(

bob2,

'age',

{

configurable: true,

value: 21,

}

);

Object.defineProperties() — метод аналогичен defineProperty, но позволяет оперировать сразу с несколькими свойствами. Также возвращает модифицированный объект.

Object.defineProperties(bob2, { name: { value: 'Jhon', }, age: { value: 36, enumerable: false, },});

Object.create() — создание объекта. В качестве первого параметра принимает объект-прототип создаваемого объекта, в качестве второго необязательного параметра — список свойств объекта.

Что такое иммутабельность?

Неизменяемым (англ. immutable) называется объект, состояние которого не может быть изменено после создания. Результатом любой модификации такого объекта всегда будет новый объект, при этом старый объект не изменится.

var immutableArr = Immutable([1, 2, 3, 4]);var newImmutableArr = immutableArr.concat([5]);console.log(immutableArr); //[1, 2, 3, 4];console.log(newImmutableArr); //[1, 2, 3, 4, 5];

Речь не идет о глубоком копировании: если объект имеет вложенную структуру, то все вложенные объекты, не подвергшиеся модификации, будут переиспользованы:

var state = Immutable({ style : { color : { r : 128, g : 64, b : 32, }, font : { family : 'sans-serif', size : 14, }, }, text : 'Example', bounds : { size : { width : 100, height : 200, }, position : { x : 300, y : 400, }, },});var nextState = state.setIn(['style', 'color', 'r'], 99);state.bounds === nextState.bounds; //truestate.text === nextState.text; //true

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

Типы данных в ES2015. Какие есть типы, какие из них примитивные, в чём разница и каковы особенности? Для каких есть литералы? Оператор typeof. - student2.ru

Копирование по ссылке

Фундаментальным отличием объектов от примитивов, является их хранение и копирование «по ссылке». В переменной, которой присвоен объект, хранится не сам объект, а «адрес его места в памяти», иными словами – «ссылка» на него.

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

var user = {

name: "Вася"

};

Типы данных в ES2015. Какие есть типы, какие из них примитивные, в чём разница и каковы особенности? Для каких есть литералы? Оператор typeof. - student2.ru

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

Наследование свойств

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

Запрос свойства: bob -> bob.prototype -> human.prototype -> Object.prototype -> undefined.

hasOwnProperty( prop ) — проверка наличия свойства непосредственно у объекта, не затрагивая цепочку прототипов.

Наследование "методов"

В JavaScript любая функция может быть добавлена к объекту в виде его свойства. Унаследованная функция ведёт себя точно так же, как любое другое свойство объекта, в том числе и в плане "затенения свойств" (property shadowing) - форма переопределения метода (method overriding). В области видимости унаследованной функции ссылка this указывает на наследника, а не на прототип, в котором данная функция является собственным свойством.

Map

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

let map = new Map();

map.set('1', 'str1'); // ключ-строка

map.set(1, 'num1'); // число

map.set(true, 'bool1'); // булевое значение

Как видно из примера выше, для сохранения и чтения значений используются методы get и set. Свойство map.size хранит общее количество записей в map.

При создании Map можно сразу инициализировать списком значений:

let map = new Map([

['1', 'str1'],

[1, 'num1'],

[true, 'bool1']

]);

Аргументом new Map должен быть итерируемый объект (не обязательно именно массив).

В качестве ключейmapможно использовать и объекты:

let user = { name: "Вася" };

// для каждого пользователя будем хранить количество посещений

let visitsCountMap = new Map();

// объект user является ключом в visitsCountMap

visitsCountMap.set(user, 123);

visitsCountMap.get(user); // 123

Методы для удаления записей:

map.delete(key) удаляет запись с ключом key, возвращает true, если такая запись была, иначе false.

map.clear() – удаляет все записи, очищает map.

Для проверки существования ключа:

map.has(key) – возвращает true, если ключ есть, иначе false.

У Map есть стандартный метод forEach, аналогичный массиву:

let recipeMap = new Map([

['огурцов', '500 гр'],

['помидоров', '350 гр'],

['сметаны', '50 гр']

]);

recipeMap.forEach( (value, key, map) => {

alert(`${key}: ${value}`); // огурцов: 500 гр, и т.д.

});

Set

Set – коллекция для хранения множества значений, причём каждое значение может встречаться лишь один раз.

Основные методы:

ü set.add(item) – добавляет в коллекцию item, возвращает set.

ü set.delete(item) – удаляет item из коллекции, возвращает true, если он там был, иначе false.

ü set.has(item) – возвращает true, если item есть в коллекции, иначе false.

ü set.clear() – очищает set.

Перебор Set осуществляется через forEach аналогично Map:

let set = new Set(["апельсины", "яблоки", "бананы"]);

set.forEach((value, valueAgain, set) => {

alert(value); // апельсины, затем яблоки, затем бананы

});

В Set у функции в .forEach три аргумента: значение, ещё раз значение, и затем сам перебираемый объект set. При этом значение повторяется в аргументах два раза. Так сделано для совместимости с Map, где у .forEach-функции также три аргумента. Но в Set первые два всегда совпадают и содержат очередное значение множества.

WeakMap и WeakSet

WeakSet – особый вид Set не препятствующий сборщику мусора удалять свои элементы. То же самое – WeakMap для Map. То есть, если некий объект присутствует только в WeakSet/WeakMap – он удаляется из памяти. Это нужно для тех ситуаций, когда основное место для хранения и использования объектов находится где-то в другом месте кода, а здесь мы хотим хранить для них «вспомогательные» данные, существующие лишь пока жив объект.

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

// текущие активные пользователи

let activeUsers = [

{name: "Вася"},

{name: "Петя"},

{name: "Маша"}

];

// вспомогательная информация о них,

// которая напрямую не входит в объект юзера,

// и потому хранится отдельно

let weakMap = new WeakMap();

weakMap.set(activeUsers[0], 1);

weakMap.set(activeUsers[1], 2);

weakMap.set(activeUsers[2], 3);

weakMap.get(activeUsers[0]); // 1

activeUsers.splice(0, 1); // Вася более не активный пользователь

// weakMap теперь содержит только 2 элемента

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

У WeakMap есть ряд ограничений:

ü Только объекты в качестве ключей.

ü Нет свойства size.

ü Нельзя перебрать элементы итератором или forEach.

ü Нет метода clear().

Иными словами, WeakMap работает только на запись (set, delete) и чтение (get, has) элементов по конкретному ключу, а не как полноценная коллекция. Это связано с тем, что содержимое WeakMap может быть модифицировано сборщиком мусора в любой момент, независимо от программиста. Сборщик мусора работает сам по себе. Он не гарантирует, что очистит объект сразу же, когда это стало возможным. В равной степени он не гарантирует и обратное. Нет какого-то конкретного момента, когда такая очистка точно произойдёт – это определяется внутренними алгоритмами сборщика и его сведениями о системе. Поэтому содержимое WeakMap в произвольный момент, строго говоря, не определено. Может быть, сборщик мусора уже удалил какие-то записи, а может и нет

Наши рекомендации