From 5d5238d86b75de41b6de7d8c9b4e577ef0f9c6af Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Wed, 30 Mar 2022 22:05:23 +0600 Subject: [PATCH 01/16] update object to primitive article --- .../09-object-toprimitive/article.md | 204 +++++++++++------- 1 file changed, 129 insertions(+), 75 deletions(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index ac2575dd70..5646d08a71 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -3,28 +3,45 @@ Что произойдёт, если сложить два объекта `obj1 + obj2`, вычесть один из другого `obj1 - obj2` или вывести их на экран, воспользовавшись `alert(obj)`? -В этом случае объекты сначала автоматически преобразуются в примитивы, а затем выполняется операция. +JavaScript совершенно не позволяет настраивать, как операторы работают с объектами. В отличие от некоторых других языков программирования, таких как Ruby или C++, мы не можем реализовать специальный объектный метод для обработки сложения (или других операторов). -В главе мы видели правила для численных, строковых и логических преобразований. Но обделили вниманием объекты. Теперь, поскольку мы уже знаем о методах объектов и символах, можно исправить это упущение. +В случае таких операций, объекты автоматически преобразуются в примитивы, затем выполняется сама операция над этими примитивами, и на выходе мы получаем примитивное значение. -1. Все объекты в логическом контексте являются `true`. Существуют лишь их численные и строковые преобразования. -2. Численные преобразования происходят, когда мы вычитаем объекты или выполняем математические операции. Например, объекты `Date` (мы рассмотрим их в статье ) могут вычитаться, и результатом `date1 - date2` будет временной отрезок между двумя датами. -3. Что касается строковых преобразований -- они обычно происходят, когда мы выводим объект `alert(obj)`, а также в других случаях, когда объект используется как строка. +Это важное ограничение, результатом `obj1 + obj2` не может быть другой объект! -## Преобразование к примитивам +К примеру, мы не можем создавать объекты, представляющие векторы или матрицы (или достижения или может ещё что-то), складывать их и ожидать в качестве результата "суммированный" объект. Такие архитектурные подвиги автоматически оказываются "за бортом". -Мы можем тонко настраивать строковые и численные преобразования, используя специальные методы объекта. +Итак, поскольку мы здесь мало что можем сделать, в реальных проектах нет математики с объектами. Когда это происходит, обычно это происходит из-за ошибки в коде. -Существуют три варианта преобразований ("три хинта"), описанные в [спецификации](https://tc39.github.io/ecma262/#sec-toprimitive): +В этой главе мы рассмотрим, как объект преобразуется в примитив и как это можно настроить. + +У нас есть две цели: + +1. Это позволит нам понять, что происходит в случае ошибок коде, когда такая операция произошла случайно. +2. Есть исключения, когда такие операции возможны и выглядят хорошо. Например, вычитание или сравнение дат (`Date` объекты). Мы встретимся с ними позже. + +## Правила преобразования + +В главе мы рассмотрели правила для числовых, строковых и логических преобразований примитивов. Но мы оставили пробел для объектов. Но теперь, когда мы уже знаем о методах и символах, пришло время заполнить этот пробел. + +1. Все объекты являются `true` в логическом контексте. Существуют лишь их численные и строковые преобразования. +2. Числовое преобразование происходит, когда мы вычитаем объекты или применяем математические функции. Например, объекты `Date` (которые будут рассмотрены в главе ) могут быть вычтены, и результатом `date1 - date2` будет разница во времени между двумя датами. +3. Что касается преобразования строки -- это обычно происходит, когда мы выводим их на экран объект как `alert(obj)` и в подобных контекстах. + +Мы можем точно настроить преобразование строк и чисел, используя специальные объектные методы. + +Существует три варианта преобразования типов, которые происходят в различных ситуациях. + +Они называются "хинтами", как описано в [спецификации](https://tc39.github.io/ecma262/#sec-toprimitive): `"string"` -: Для преобразования объекта к строке, когда операция ожидает получить строку, например `alert`: +: Для преобразования объекта в строку, когда мы выполняем операцию над объектом, которая ожидает строку, например `alert`: ```js // вывод alert(obj); - // используем объект в качестве имени свойства + // используем объект в качестве ключа свойства anotherObj[obj] = 123; ``` @@ -35,53 +52,62 @@ // явное преобразование let num = Number(obj); - // математическое (исключая бинарный оператор "+") + // математические (не считая бинарного плюса) let n = +obj; // унарный плюс let delta = date1 - date2; - // сравнения больше/меньше + // сравнение больше/меньше let greater = user1 > user2; ``` `"default"` -: Происходит редко, когда оператор "не уверен", какой тип ожидать. +: Возникает в редких случаях, когда оператор "не уверен", какого типа ожидать. - Например, бинарный плюс `+` может работать с обоими типами: строками (объединять их) и числами (складывать). Таким образом, и те, и другие будут вычисляться. Или когда происходит сравнение объектов с помощью нестрогого равенства `==` со строкой, числом или символом, и неясно, какое преобразование должно быть выполнено. + Например, бинарный плюс `+` может работать как со строками (объединяя их), так и с числами (складывая их), поэтому подойдут и строки, и числа. Таким образом, если двоичный плюс получает объект в качестве аргумента, он использует хинт `"default"` для его преобразования. + + Кроме того, если объект сравнивается с помощью `==` со строкой, числом или символом, также неясно, какое преобразование следует выполнить, поэтому используется хинт "default". ```js - // бинарный плюс - let total = car1 + car2; + // бинарный плюс использует хинт "default" + let total = obj1 + obj2; - // obj == string/number/symbol + // obj == number использует хинт "default" if (user == 1) { ... }; ``` - Оператор больше/меньше `<>` также может работать как со строками, так и с числами. Однако, по историческим причинам он использует хинт "number", а не "default". + Операторы сравнения больше/меньше, такие как `<` `>`, также могут работать как со строками, так и с числами. Тем не менее, по историческим причинам, они используют хинт `"number"`, а не `"default"`. - На практике все встроенные объекты, исключая `Date` (мы познакомимся с ним чуть позже), реализуют `"default"` преобразования тем же способом, что и `"number"`. И нам следует поступать так же. + Впрочем на практике, нам не нужно запоминать эти специфические детали, потому что все встроенные объекты, за исключением одного случая (объект `Date`, который мы рассмотрим позже), реализуют `"default"` преобразование тем же способом, что и `"number"`. И мы можем поступать так же. -Обратите внимание, что существуют лишь три варианта хинтов. Всё настолько просто. Не существует хинта со значением "boolean" (все объекты являются `true` в логическом контексте) или каких-либо ещё. И если мы считаем `"default"` и `"number"` одинаковыми, как большинство встроенных объектов, то остаются всего два варианта преобразований. +```smart header="Нет `\"логического\"` хинта" +Обратите внимание -- есть только три хинта. Это очень просто. -**В процессе преобразования движок JavaScript пытается найти и вызвать три следующих метода объекта:** +Не существует хинта со значением "boolean" (все объекты являются `true` в логическом контексте) или каких-либо ещё. И если мы будем относиться к "default" и "number" одинаково, как это делают большинство встроенных объектов, то тогда будет только два преобразования. +``` -1. Вызывает `obj[Symbol.toPrimitive](hint)` - метод с символьным ключом `Symbol.toPrimitive` (системный символ), если такой метод существует, и передаёт ему хинт. -2. Иначе, если хинт равен `"string"` - - пытается вызвать `obj.toString()`, а если его нет, то `obj.valueOf()`, если он существует. +**Чтобы выполнить преобразование, JavaScript пытается найти и вызвать три следующих объектных метода:** + +1. Вызов `obj[Symbol.toPrimitive](hint)` - метод с символьным ключом `Symbol.toPrimitive` (системный символ), если такой метод существует, +2. В противном случае, если хинт равен `"string"` + - пробует `obj.toString()` и `obj.valueOf()`, независимо от того, что существует. 3. В случае, если хинт равен `"number"` или `"default"` - - пытается вызвать `obj.valueOf()`, а если его нет, то `obj.toString()`, если он существует. + - пробует `obj.valueOf()` и `obj.toString()`, независимо от того, что существует. ## Symbol.toPrimitive -Начнём с универсального подхода - символа `Symbol.toPrimitive`: метод с таким названием (если есть) используется для всех преобразований: +Давайте начнём с первого метода. Есть встроенный символ с именем `Symbol.toPrimitive`, который следует использовать для обозначения метода преобразования, например: ```js obj[Symbol.toPrimitive] = function(hint) { - // должен вернуть примитивное значение - // hint равно чему-то одному из: "string", "number" или "default" + // вот код для преобразования этого объекта в примитив + // он должен вернуть примитивное значение + // hint = чему-то из "string", "number", "default" }; ``` -Для примера используем его в реализации объекта `user`: +Если метод `Symbol.toPrimitive` существует, он используется для всех хинтов, и больше никаких методов не требуется. + +Например, здесь объект `user` реализует это: ```js run let user = { @@ -100,19 +126,41 @@ alert(+user); // hint: number -> 1000 alert(user + 500); // hint: default -> 1500 ``` -Как мы видим из кода, `user` преобразовывается либо в информативную читаемую строку, либо в денежный счёт в зависимости от значения хинта. Единственный метод `user[Symbol.toPrimitive]` смог обработать все случаи преобразований. +Как мы можем видеть из кода, `user` становится либо самодостаточной строкой или денежной суммой в зависимости от преобразования. Один метод `user[Symbol.toPrimitive]` обрабатывает все случаи преобразования. + + +## toString/valueOf + +Если нет `Symbol.toPrimitive`, тогда JavaScript пытается найти методы `toString` и `valueOf`: + +- Для хинта "string": `toString`, а если он не существует, то `valueOf` (таким образом `toString` имеет приоритет для преобразования строк). +- Для других хинтов: `valueOf`, а если он не существует, то `toString` (таким образом `valueOf` имеет приоритет для математических операций). + +Методы `toString` и `valueOf` берут своё начало с древних времён. Это не символы (символов ещё тогда не было), а скорее просто "обычные" методы со строковыми именами. Они предоставляют альтернативный "старомодный" способ реализации преобразования. + +Эти методы должны возвращать примитивное значение. Если `toString` или `valueOf` возвращает объект, то он игнорируется (так же, как если бы метода не было). + +По умолчанию обычный объект имеет следующие методы `toString` и `valueOf`: +- Метод `toString` возвращает строку `"[object Object]"`. +- Метод `valueOf` возвращает сам объект. -## Методы toString/valueOf +Взгляните на пример: -Методы `toString` и `valueOf` берут своё начало с древних времён. Это не символы, так как в то время символов ещё не существовало, а просто обычные методы объектов со строковыми именами. Они предоставляют "устаревший" способ реализации преобразований объектов. +```js run +let user = {name: "John"}; + +alert(user); // [object Object] +alert(user.valueOf() === user); // true +``` -Если нет метода `Symbol.toPrimitive`, движок JavaScript пытается найти эти методы и вызвать их следующим образом: +Таким образом, если мы попытаемся использовать объект в качестве строки, как например в 'alert' или вроде того, то по умолчанию мы увидим `[object Object]`. -- `toString -> valueOf` для хинта со значением "string". -- `valueOf -> toString` -- в ином случае. +Значение по умолчанию `valueOf` упоминается здесь только для полноты картины, чтобы избежать какой-либо путаницы. Как вы можете видеть, он возвращает сам объект и поэтому игнорируется. Не спрашивайте меня почему, это по историческим причинам. Так что мы можем предположить, что его не существует. -Для примера, используем их в реализации всё того же объекта `user`. Воспроизведём его поведение комбинацией методов `toString` и `valueOf`: +Давайте применим эти методы для настройки преобразования. + +Для примера, используем их в реализации всё того же объекта `user`. Но уже используя комбинацию `toString` и `valueOf` вместо `Symbol.toPrimitive`: ```js run let user = { @@ -138,7 +186,7 @@ alert(user + 500); // valueOf -> 1500 Как видим, получилось то же поведение, что и в предыдущем примере с `Symbol.toPrimitive`. -Довольно часто мы хотим описать одно "универсальное" преобразование объекта к примитиву для всех ситуаций. Для этого достаточно создать один `toString`: +Довольно часто нам нужно единое "универсальное" место для обработки всех примитивных преобразований. В этом случае мы можем реализовать только `toString`: ```js run let user = { @@ -153,71 +201,77 @@ alert(user); // toString -> John alert(user + 500); // toString -> John500 ``` -В отсутствие `Symbol.toPrimitive` и `valueOf`, `toString` обработает все случаи преобразований к примитивам. - +В отсутствие Symbol.toPrimitive` и `valueOf`, `toString` обработает все примитивные преобразования. -## Возвращаемые типы +### Преобразование может вернуть любой примитивный тип -Важно понимать, что все описанные методы для преобразований объектов не обязаны возвращать именно требуемый "хинтом" тип примитива. +Важная вещь, которую следует знать обо всех методах преобразования примитивов, заключается в том, что они не обязательно возвращают подсказанный хинтом примитив. -Нет обязательного требования, чтобы `toString()` возвращал именно строку, или чтобы метод `Symbol.toPrimitive` возвращал именно число для хинта "number". +Нет никакого контроля над тем, вернёт ли `toString` именно строку, или чтобы метод `Symbol.toPrimitive` возращал число для хинта `"number"`. -**Единственное обязательное требование: методы должны возвращать примитив, а не объект.** +Единственное обязательное условие: эти методы должны возвращать примитив, а не объект. ```smart header="Историческая справка" -По историческим причинам, если `toString` или `valueOf` вернёт объект, то ошибки не будет, но такое значение будет проигнорировано (как если бы метода вообще не существовало). +По историческим причинам, если `toString` или `valueOf` вернёт объект, то ошибки не будет, но такое значение будет проигнорировано (как если бы метода вообще не существовало). Это всё потому, что в древние времена в JavaScript не было хорошей концепции "ошибки". -Метод `Symbol.toPrimitive`, напротив, *обязан* возвращать примитив, иначе будет ошибка. +К примеру `Symbol.toPrimitive`, напротив, *обязан* возвращать примитив, иначе будет ошибка. ``` -## Последующие операции +## Дальнейшие преобразования -Операция, инициировавшая преобразование, получает примитив и затем продолжает работу с ним, производя дальнейшие преобразования, если это необходимо. +Как мы уже знаем, многие операторы и функции выполняют преобразования типов, например, умножение `*` преобразует операнды в числа. + +Если мы передаём объект в качестве аргумента, то на это есть два этапа: +1. Объект преобразуется в примитив (с использованием правил, описанных выше). +2. Если полученный примитив не имеет подходящего типа, он преобразуется. Например: -- Математические операции, исключая бинарный плюс, преобразуют примитив к числу: +```js run +let obj = { + // toString обрабатывает все преобразования в случае отсутствия других методов + toString() { + return "2"; + } +}; - ```js run - let obj = { - // toString обрабатывает все преобразования в случае отсутствия других методов - toString() { - return "2"; - } - }; +alert(obj * 2); // 4, объект был преобразован к примитиву "2", затем умножение сделало его числом +``` - alert(obj * 2); // 4, объект был преобразован к примитиву "2", затем умножение сделало его числом - ``` +1. 1. Умножение `obj * 2` сначала преобразует объект в примитив (это строка `"2"`). +2. Затем `"2" * 2` становится `2 * 2` (строка преобразуется в число). -- Бинарный плюс `+` в аналогичном случае сложит строки: +А вот, к примеру, бинарный плюс в подобной ситуации соединил бы строки, так как он совсем не брезгует строк: - ```js run - let obj = { - toString() { - return "2"; - } - }; +```js run +let obj = { + toString() { + return "2"; + } +}; - alert(obj + 2); // 22 (преобразование к примитиву вернуло строку => конкатенация) - ``` +alert(obj + 2); // 22 ("2" + 2), conversion to primitive returned a string => concatenation +``` ## Итого -Преобразование объектов в примитивы вызывается автоматически многими встроенными функциями и операторами, которые ожидают примитив в качестве аргумента. +Преобразование объекта в примитив вызывается автоматически многими встроенными функциями и операторами, которые ожидают примитив в качестве значения. -Существует всего 3 типа преобразований (хинтов): +Существует всего 3 типа (хинтов) для этого: - `"string"` (для `alert` и других операций, которым нужна строка) - `"number"` (для математических операций) -- `"default"` (для некоторых операций) +- `"default"` (для нескольких других операторов) -В спецификации явно указано, какой хинт должен использовать каждый оператор. И существует совсем немного операторов, которые не знают, что ожидать, и используют хинт со значением `"default"`. Обычно для встроенных объектов хинт `"default"` обрабатывается так же, как `"number"`. Таким образом, последние два очень часто объединяют вместе. +Спецификация явно описывает, какой оператор использует тот или иной хинт. И существует совсем немного операторов, которые "не знают, чего ожидать" и используют хинт `"default"`. Обычно для встроенных объектов хинт `"default"` обрабатывается так же, как `"number"`, поэтому на практике последние два часто сливаются воедино. -Алгоритм преобразований к примитивам следующий: +Алгоритм преобразования таков: 1. Сначала вызывается метод `obj[Symbol.toPrimitive](hint)`, если он существует. -2. Иначе, если хинт равен `"string"` - - происходит попытка вызвать `obj.toString()`, затем `obj.valueOf()`, смотря что есть. +2. В случае, если хинт равен `"string"` + - происходит попытка вызвать `obj.toString()` и `obj.valueOf()`, смотря что есть. 3. Иначе, если хинт равен `"number"` или `"default"` - - происходит попытка вызвать `obj.valueOf()`, затем `obj.toString()`, смотря что есть. + - происходит попытка вызвать `obj.valueOf()` и `obj.toString()`, смотря что есть. + +На практике часто бывает достаточно реализовать только `obj.toString()` в качестве универсального метода для преобразований строк, который должен возвращать удобочитаемое представление объекта для целей ведения логирования или отладки. -На практике довольно часто достаточно реализовать только `obj.toString()` как "универсальный" метод для всех типов преобразований, возвращающий "читаемое" представление объекта, достаточное для логирования или отладки. +Что касается математических операций, JavaScript не предоставляет способа "переопределить" их с помощью методов, поэтому в реальных проектах они редко используются для объектов. From ee13ccba24f049f1920766f71a842ef952538283 Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Wed, 30 Mar 2022 22:10:14 +0600 Subject: [PATCH 02/16] smth --- 1-js/04-object-basics/09-object-toprimitive/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 5646d08a71..f9d5ad1f85 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -250,7 +250,7 @@ let obj = { } }; -alert(obj + 2); // 22 ("2" + 2), conversion to primitive returned a string => concatenation +alert(obj + 2); // 22 ("2" + 2), преобразование к примитиву вернуло строку => конкатенация ``` ## Итого From 598e16133c0050ac4ec17e43956d4b6f5321197f Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Wed, 30 Mar 2022 22:12:45 +0600 Subject: [PATCH 03/16] smth --- 1-js/04-object-basics/09-object-toprimitive/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index f9d5ad1f85..63b83dc7cc 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -266,7 +266,7 @@ alert(obj + 2); // 22 ("2" + 2), преобразование к примити Алгоритм преобразования таков: -1. Сначала вызывается метод `obj[Symbol.toPrimitive](hint)`, если он существует. +1. Сначала вызывается метод `obj[Symbol.toPrimitive](hint)`, если он существует, 2. В случае, если хинт равен `"string"` - происходит попытка вызвать `obj.toString()` и `obj.valueOf()`, смотря что есть. 3. Иначе, если хинт равен `"number"` или `"default"` From fca6453a6656df61f37359114f773043ac59b1d1 Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Wed, 30 Mar 2022 22:19:09 +0600 Subject: [PATCH 04/16] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BB?= =?UTF-8?q?=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1-js/04-object-basics/09-object-toprimitive/article.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 63b83dc7cc..4c9cb816a2 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -35,7 +35,7 @@ JavaScript совершенно не позволяет настраивать, Они называются "хинтами", как описано в [спецификации](https://tc39.github.io/ecma262/#sec-toprimitive): `"string"` -: Для преобразования объекта в строку, когда мы выполняем операцию над объектом, которая ожидает строку, например `alert`: +: Для преобразования объекта в строку, когда мы выполняем операцию над объектом, которая ожидает строку, например `alert`: ```js // вывод @@ -56,12 +56,12 @@ JavaScript совершенно не позволяет настраивать, let n = +obj; // унарный плюс let delta = date1 - date2; - // сравнение больше/меньше + // сравнения больше/меньше let greater = user1 > user2; ``` `"default"` -: Возникает в редких случаях, когда оператор "не уверен", какого типа ожидать. +: Происходит редко, когда оператор "не уверен", какой тип ожидать. Например, бинарный плюс `+` может работать как со строками (объединяя их), так и с числами (складывая их), поэтому подойдут и строки, и числа. Таким образом, если двоичный плюс получает объект в качестве аргумента, он использует хинт `"default"` для его преобразования. From 63c59672c52ba38fb4feef1dfdd72027c2e6a6e1 Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Wed, 30 Mar 2022 22:22:59 +0600 Subject: [PATCH 05/16] smth --- 1-js/04-object-basics/09-object-toprimitive/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 4c9cb816a2..a5abcb9a9a 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -28,14 +28,14 @@ JavaScript совершенно не позволяет настраивать, 2. Числовое преобразование происходит, когда мы вычитаем объекты или применяем математические функции. Например, объекты `Date` (которые будут рассмотрены в главе ) могут быть вычтены, и результатом `date1 - date2` будет разница во времени между двумя датами. 3. Что касается преобразования строки -- это обычно происходит, когда мы выводим их на экран объект как `alert(obj)` и в подобных контекстах. -Мы можем точно настроить преобразование строк и чисел, используя специальные объектные методы. +Мы можем тонко настроить преобразование строк и чисел, используя специальные объектные методы. Существует три варианта преобразования типов, которые происходят в различных ситуациях. Они называются "хинтами", как описано в [спецификации](https://tc39.github.io/ecma262/#sec-toprimitive): `"string"` -: Для преобразования объекта в строку, когда мы выполняем операцию над объектом, которая ожидает строку, например `alert`: +: Для преобразования объекта к строке, когда мы выполняем операцию над объектом, которая ожидает строку, например `alert`: ```js // вывод From 3dc728c5ad286932ebad1f8e189a3571cdae525c Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Wed, 30 Mar 2022 22:25:46 +0600 Subject: [PATCH 06/16] smth --- 1-js/04-object-basics/09-object-toprimitive/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index a5abcb9a9a..baba5c5894 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -88,7 +88,7 @@ JavaScript совершенно не позволяет настраивать, **Чтобы выполнить преобразование, JavaScript пытается найти и вызвать три следующих объектных метода:** 1. Вызов `obj[Symbol.toPrimitive](hint)` - метод с символьным ключом `Symbol.toPrimitive` (системный символ), если такой метод существует, -2. В противном случае, если хинт равен `"string"` +2. В случае, если хинт равен `"string"` - пробует `obj.toString()` и `obj.valueOf()`, независимо от того, что существует. 3. В случае, если хинт равен `"number"` или `"default"` - пробует `obj.valueOf()` и `obj.toString()`, независимо от того, что существует. @@ -269,7 +269,7 @@ alert(obj + 2); // 22 ("2" + 2), преобразование к примити 1. Сначала вызывается метод `obj[Symbol.toPrimitive](hint)`, если он существует, 2. В случае, если хинт равен `"string"` - происходит попытка вызвать `obj.toString()` и `obj.valueOf()`, смотря что есть. -3. Иначе, если хинт равен `"number"` или `"default"` +3. В случае, если хинт равен `"number"` или `"default"` - происходит попытка вызвать `obj.valueOf()` и `obj.toString()`, смотря что есть. На практике часто бывает достаточно реализовать только `obj.toString()` в качестве универсального метода для преобразований строк, который должен возвращать удобочитаемое представление объекта для целей ведения логирования или отладки. From c5d6340b7f9baf7ed58063d676ba73129e510a4b Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Fri, 1 Apr 2022 02:06:21 +0600 Subject: [PATCH 07/16] some fixes --- 1-js/04-object-basics/09-object-toprimitive/article.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index baba5c5894..6c1cdd2ac5 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -5,7 +5,7 @@ JavaScript совершенно не позволяет настраивать, как операторы работают с объектами. В отличие от некоторых других языков программирования, таких как Ruby или C++, мы не можем реализовать специальный объектный метод для обработки сложения (или других операторов). -В случае таких операций, объекты автоматически преобразуются в примитивы, затем выполняется сама операция над этими примитивами, и на выходе мы получаем примитивное значение. +В случае таких операций, объекты автоматически преобразуются в примитивы, затем выполняется сама операция над этими примитивами, и на выходе мы получим примитивное значение. Это важное ограничение, результатом `obj1 + obj2` не может быть другой объект! @@ -201,7 +201,7 @@ alert(user); // toString -> John alert(user + 500); // toString -> John500 ``` -В отсутствие Symbol.toPrimitive` и `valueOf`, `toString` обработает все примитивные преобразования. +В отсутствие `Symbol.toPrimitive` и `valueOf`, `toString` обработает все примитивные преобразования. ### Преобразование может вернуть любой примитивный тип @@ -274,4 +274,4 @@ alert(obj + 2); // 22 ("2" + 2), преобразование к примити На практике часто бывает достаточно реализовать только `obj.toString()` в качестве универсального метода для преобразований строк, который должен возвращать удобочитаемое представление объекта для целей ведения логирования или отладки. -Что касается математических операций, JavaScript не предоставляет способа "переопределить" их с помощью методов, поэтому в реальных проектах они редко используются для объектов. +Что касается математических операций, JavaScript не предоставляет способа "переопределить" их с помощью методов, поэтому в реальных проектах они редко используются на объектах. From e1ccd6ada151f0290f98ba20af963dcd3f374a46 Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Fri, 1 Apr 2022 02:57:02 +0600 Subject: [PATCH 08/16] fix --- 1-js/04-object-basics/09-object-toprimitive/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 6c1cdd2ac5..aec32328e0 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -41,7 +41,7 @@ JavaScript совершенно не позволяет настраивать, // вывод alert(obj); - // используем объект в качестве ключа свойства + // используем объект в качестве ключа anotherObj[obj] = 123; ``` From 987a9312c1206eb13bc57ab228850849dd7a397f Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Sat, 2 Apr 2022 17:49:43 +0600 Subject: [PATCH 09/16] smth --- 1-js/04-object-basics/09-object-toprimitive/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index aec32328e0..d677471ed4 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -11,7 +11,7 @@ JavaScript совершенно не позволяет настраивать, К примеру, мы не можем создавать объекты, представляющие векторы или матрицы (или достижения или может ещё что-то), складывать их и ожидать в качестве результата "суммированный" объект. Такие архитектурные подвиги автоматически оказываются "за бортом". -Итак, поскольку мы здесь мало что можем сделать, в реальных проектах нет математики с объектами. Когда это происходит, обычно это происходит из-за ошибки в коде. +Итак, поскольку мы здесь мало что можем сделать, в реальных проектах нет математики с объектами. Если это всё же происходит, то обычно это из-за ошибки в коде. В этой главе мы рассмотрим, как объект преобразуется в примитив и как это можно настроить. From 0ff5d8b00b8705410d7f871b4651b848e679787e Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Sat, 2 Apr 2022 17:53:14 +0600 Subject: [PATCH 10/16] smth --- 1-js/04-object-basics/09-object-toprimitive/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index d677471ed4..0812102a98 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -17,8 +17,8 @@ JavaScript совершенно не позволяет настраивать, У нас есть две цели: -1. Это позволит нам понять, что происходит в случае ошибок коде, когда такая операция произошла случайно. -2. Есть исключения, когда такие операции возможны и выглядят хорошо. Например, вычитание или сравнение дат (`Date` объекты). Мы встретимся с ними позже. +1. Это позволит нам понять, что происходит в случае ошибок в коде, когда такая операция произошла случайно. +2. Есть исключения, когда такие операции возможны и вполне уместны. Например, вычитание или сравнение дат (`Date` объекты). Мы встретимся с ними позже. ## Правила преобразования From 7c925ab4ea69bac6586ff1b903c3272dedb6282a Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Sat, 2 Apr 2022 22:18:10 +0600 Subject: [PATCH 11/16] smth --- 1-js/04-object-basics/09-object-toprimitive/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 0812102a98..2b9cd9a5e2 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -26,9 +26,9 @@ JavaScript совершенно не позволяет настраивать, 1. Все объекты являются `true` в логическом контексте. Существуют лишь их численные и строковые преобразования. 2. Числовое преобразование происходит, когда мы вычитаем объекты или применяем математические функции. Например, объекты `Date` (которые будут рассмотрены в главе ) могут быть вычтены, и результатом `date1 - date2` будет разница во времени между двумя датами. -3. Что касается преобразования строки -- это обычно происходит, когда мы выводим их на экран объект как `alert(obj)` и в подобных контекстах. +3. Что касается преобразований к строке -- это обычно происходит, когда мы выводим на экран объект как `alert(obj)` и в подобных контекстах. -Мы можем тонко настроить преобразование строк и чисел, используя специальные объектные методы. +Мы можем тонко настроить преобразования к строкам и числам, используя специальные объектные методы. Существует три варианта преобразования типов, которые происходят в различных ситуациях. From e0cedbe112e34c792d412c79cdaf0b5c8b1d6030 Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Sun, 10 Apr 2022 15:26:41 +0600 Subject: [PATCH 12/16] Update article.md --- 1-js/04-object-basics/09-object-toprimitive/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 2b9cd9a5e2..3e7d3b785b 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -63,7 +63,7 @@ JavaScript совершенно не позволяет настраивать, `"default"` : Происходит редко, когда оператор "не уверен", какой тип ожидать. - Например, бинарный плюс `+` может работать как со строками (объединяя их), так и с числами (складывая их), поэтому подойдут и строки, и числа. Таким образом, если двоичный плюс получает объект в качестве аргумента, он использует хинт `"default"` для его преобразования. + Например, бинарный плюс `+` может работать как со строками (объединяя их), так и с числами (складывая их), поэтому подойдут и строки, и числа. Таким образом, если бинарный плюс получает объект в качестве аргумента, он использует хинт `"default"` для его преобразования. Кроме того, если объект сравнивается с помощью `==` со строкой, числом или символом, также неясно, какое преобразование следует выполнить, поэтому используется хинт "default". From 340b4674b32d81bbc15b32d7b8caa948272099e3 Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Sun, 10 Apr 2022 15:50:13 +0600 Subject: [PATCH 13/16] Update article.md --- 1-js/04-object-basics/09-object-toprimitive/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 3e7d3b785b..17a6c6dcd2 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -95,7 +95,7 @@ JavaScript совершенно не позволяет настраивать, ## Symbol.toPrimitive -Давайте начнём с первого метода. Есть встроенный символ с именем `Symbol.toPrimitive`, который следует использовать для обозначения метода преобразования, например: +Давайте начнём с первого метода. Есть встроенный символ с именем `Symbol.toPrimitive`, который следует использовать для обозначения метода преобразования, вот так: ```js obj[Symbol.toPrimitive] = function(hint) { From 65ea852d444b81c34fc1ca74a20199bf66784dfa Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Tue, 12 Apr 2022 00:20:16 +0600 Subject: [PATCH 14/16] Update article.md --- 1-js/04-object-basics/09-object-toprimitive/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 17a6c6dcd2..9b6c2ef1f3 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -136,7 +136,7 @@ alert(user + 500); // hint: default -> 1500 - Для хинта "string": `toString`, а если он не существует, то `valueOf` (таким образом `toString` имеет приоритет для преобразования строк). - Для других хинтов: `valueOf`, а если он не существует, то `toString` (таким образом `valueOf` имеет приоритет для математических операций). -Методы `toString` и `valueOf` берут своё начало с древних времён. Это не символы (символов ещё тогда не было), а скорее просто "обычные" методы со строковыми именами. Они предоставляют альтернативный "старомодный" способ реализации преобразования. +Методы `toString` и `valueOf` берут своё начало с древних времён. Это не символы (символов тогда ещё не было), а скорее просто "обычные" методы со строковыми именами. Они предоставляют альтернативный "старомодный" способ реализации преобразования. Эти методы должны возвращать примитивное значение. Если `toString` или `valueOf` возвращает объект, то он игнорируется (так же, как если бы метода не было). @@ -154,7 +154,7 @@ alert(user); // [object Object] alert(user.valueOf() === user); // true ``` -Таким образом, если мы попытаемся использовать объект в качестве строки, как например в 'alert' или вроде того, то по умолчанию мы увидим `[object Object]`. +Таким образом, если мы попытаемся использовать объект в качестве строки, как например в `alert` или вроде того, то по умолчанию мы увидим `[object Object]`. Значение по умолчанию `valueOf` упоминается здесь только для полноты картины, чтобы избежать какой-либо путаницы. Как вы можете видеть, он возвращает сам объект и поэтому игнорируется. Не спрашивайте меня почему, это по историческим причинам. Так что мы можем предположить, что его не существует. From e9142a623b6d8aec6a3d35de8dfcc3d65d3a3211 Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Tue, 12 Apr 2022 00:49:44 +0600 Subject: [PATCH 15/16] Update article.md --- 1-js/04-object-basics/09-object-toprimitive/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 9b6c2ef1f3..de96bc6bcd 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -238,7 +238,7 @@ let obj = { alert(obj * 2); // 4, объект был преобразован к примитиву "2", затем умножение сделало его числом ``` -1. 1. Умножение `obj * 2` сначала преобразует объект в примитив (это строка `"2"`). +1. Умножение `obj * 2` сначала преобразует объект в примитив (это строка `"2"`). 2. Затем `"2" * 2` становится `2 * 2` (строка преобразуется в число). А вот, к примеру, бинарный плюс в подобной ситуации соединил бы строки, так как он совсем не брезгует строк: From 9c948ee12504dc695f551619bf3323c41ad77880 Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Tue, 12 Apr 2022 00:54:42 +0600 Subject: [PATCH 16/16] Update article.md --- 1-js/04-object-basics/09-object-toprimitive/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index de96bc6bcd..0ae60b58a0 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -272,6 +272,6 @@ alert(obj + 2); // 22 ("2" + 2), преобразование к примити 3. В случае, если хинт равен `"number"` или `"default"` - происходит попытка вызвать `obj.valueOf()` и `obj.toString()`, смотря что есть. -На практике часто бывает достаточно реализовать только `obj.toString()` в качестве универсального метода для преобразований строк, который должен возвращать удобочитаемое представление объекта для целей ведения логирования или отладки. +На практике часто бывает достаточно реализовать только `obj.toString()` в качестве универсального метода для преобразований к строке, который должен возвращать удобочитаемое представление объекта для целей ведения логирования или отладки. Что касается математических операций, JavaScript не предоставляет способа "переопределить" их с помощью методов, поэтому в реальных проектах они редко используются на объектах.