Автор оригинала: FreeCodeCamp Community Member.
Алексей Самошкин
Знать ваши двигатели
[Править 2/5/2018] : Этот пост сейчас Доступно на русском языке Отказ Хлопья к Серж Булавик за его усилия.
Тип принуждения Процесс преобразования значения из одного типа на другое (например, строку к номеру, объект к логическому регису и т. Д.). Любой тип, будь то примитив или объект, является действительным предметом для принуждения к типу. Чтобы вспомнить, примитивы: номер, строка, логический, нулевой, неопределенный + символ + (добавляется в ES6).
В качестве примера типового принуждения на практике посмотрите на Таблица сравнения JavaScript , что показывает, как свободное равенство ==
Оператор ведет себя для разных А
и B
Типы. Эта матрица выглядит страшно из-за неявного принуждения к тому, что ==
Оператор делает, и вряд ли можно вспомнить все эти комбинации. И вам не нужно это делать – просто выучите основные принципы принуждения к типу.
Эта статья идет углублена тем, как в JavaScript работает принуждение в JavaScript, и будет вооружать вас основным знанием, поэтому вы можете чувствовать себя уверенно, объяснив, что подчиняется следующим выражениям. К концу статьи я покажу ответы и объясни их.
true + false 12 / "6" "number" + 15 + 3 15 + 3 + "number" [1] > null "foo" + + "bar" 'true' == true false == 'false' null == '' !!"false" == !!"true" ['x'] == 'x' [] + null + 1 [1,2,3] == [1,2,3] {}+[]+{}+[1] !+[]+[]+![] new Date(0) - 0 new Date(0) + 0
Да, этот список полон довольно глупых вещей, которые вы можете сделать в качестве разработчика. В 90% случаев использования лучше избегать неявного типа принуждения. Рассмотрим этот список в качестве учебного упражнения для проверки ваших знаний о том, как работает принуждение к приложению. Если вам скучно, вы можете найти больше примеров на wtfjs.com Отказ
Кстати, иногда вы можете столкнуться с такими вопросами в интервью для позиции разработчика JavaScript. Итак, продолжайте читать?
Неявность против явного принуждения
Тип принуждения может быть явным и неявным.
Когда разработчик выражает намерение преобразовать между типами, написав соответствующий код, как Номер (значение)
это называется Явный тип принуждения (или тип литья).
Поскольку JavaScript – это слабо напечатанный язык, значения также могут быть автоматически преобразованы между различными типами, и он называется неявный тип принуждения Отказ Обычно это происходит, когда вы применяете операторы до значений различных типов, таких как 1
, 2/'5'
, null + новая дата ()
или это может быть вызвано окружающим контекстом, как с Если (значение) {...}
, где ценность
принужден к логию.
Один оператор, который не вызывает неявный тип принуждения, является ===
, который называется строгим оператором равенства. Свободный оператор равенства ==
С другой стороны, как нужно как сравнение, так и тип принуждения.
Принуждение неявного типа – это двойной край Sword: это отличный источник разочарования и дефектов, но и полезный механизм, который позволяет нам писать меньше кода, не теряя читаемость.
Три типа конверсии
Первое правило, чтобы знать, есть лишь три типа преобразования в JavaScript:
- нанизывать
- до логии
- на номер
Во-вторых, конверсионная логика для примитивов и объектов работает по-разному, но как примитивы, так и объекты могут быть преобразованы только этими тремя способами.
Давайте сначала начнем с примитивов.
Конверсия строки
Чтобы явно преобразовать значения в строку Применить Строка ()
функция. Неявное принуждение запускается двоичным +
Оператор, когда любой операнд является строкой:
String(123) // explicit 123 + '' // implicit
Все примитивные значения преобразуются в строки, естественно, как вы ожидаете:
String(123) // '123' String(-12.3) // '-12.3' String(null) // 'null' String(undefined) // 'undefined' String(true) // 'true' String(false) // 'false'
Конвертация символов немного сложно, потому что он может быть конвертирован только явно, но не касащенным неявно. Читать дальше на Символ
Правила принуждения.
String(Symbol('my symbol')) // 'Symbol(my symbol)' '' + Symbol('my symbol') // TypeError is thrown
Логическое преобразование
Явным образом преобразовать значение логичному мостику Применить Boolean ()
функция. Неявное преобразование происходит в логическом контексте или срабатывает логическими операторами (
&&
!
Boolean(2) // explicit if (2) { ... } // implicit due to logical context !!2 // implicit due to logical operator 2 || 'hello' // implicit due to logical operator
Примечание : Логические операторы, такие как
и
&& логические преобразования внутри, но на самом деле вернуть значение оригинальных операндов
// returns number 123, instead of returning true // 'hello' and 123 are still coerced to boolean internally to calculate the expression let x = 'hello' && 123; // x === 123
Как только 2 возможных результатов булевой конверсии: правда
или ложь
Просто проще вспомнить список фальсифицированных ценностей.
Boolean('') // false Boolean(0) // false Boolean(-0) // false Boolean(NaN) // false Boolean(null) // false Boolean(undefined) // false Boolean(false) // false
Любое значение, которое не в списке, преобразуется в правда
, в том числе объект, функция, Массив
, Дата
, определенный пользователем тип и так далее. Символы – это правдивые ценности. Пустой объект и массивы – это правдивые значения:
Boolean({}) // true Boolean([]) // true Boolean(Symbol()) // true !!Symbol() // true Boolean(function() {}) // true
Числовое преобразование
Для явного преобразования просто примените Номер ()
Функция, такая же, как вы сделали с Boolean ()
и Строка ()
Отказ
Неявное преобразование сложно, потому что он срабатывает в большем количестве случаев:
- Операторы сравнения (
>
,<
,<=
,> =
) - Битовые операторы (
|
&
^
~
) - Арифметические операторы (
-
+
*
/
%
). Обратите внимание, что двоичный+
Не вызывает числовое преобразование, когда любой операнд является строкой. - Унарный
+
оператор - Свободный оператор равенства
==
(вкл.! =
). Обратите внимание, что==
Не вызывает числовое преобразование, когда обе операнды являются строками.
Number('123') // explicit +'123' // implicit 123 != '456' // implicit 4 > '5' // implicit 5/null // implicit true | 0 // implicit
Вот как примитивные значения преобразуются в цифры:
Number(null) // 0 Number(undefined) // NaN Number(true) // 1 Number(false) // 0 Number(" 12 ") // 12 Number("-12.34") // -12.34 Number("\n") // 0 Number(" 12s ") // NaN Number(123) // 123
При преобразовании строки на номер двигателя первые отделки ведущих и конечных пробелов, \ N
, \ T
Персонажи, возвращение Нан
Если обрезанная строка не представляет действительный номер. Если строка пуста, она возвращает 0
Отказ
null
и undefined
обрабатываются по-разному: null
становится 0
, тогда как undefined
становится Нан
Отказ
Символы не могут быть преобразованы в число ни явно, ни безупречно. Более того, Типеррор
брошен, а не молча преобразования в Нан
, как будто это происходит для undefined
Отказ Увидеть больше на правилах преобразования символов на MDN Отказ
Number(Symbol('my symbol')) // TypeError is thrown +Symbol('123') // TypeError is thrown
Есть два Особые правила помнить:
- При применении
==
кnull
илиundefined
Числовое преобразование не происходит.null
равняется толькоnull
илиundefined
и не равно ничего еще.
null == 0 // false, null is not converted to 0 null == null // true undefined == undefined // true null == undefined // true
2. NAN не равен ничего себе:
if (value !== value) { console.log("we're dealing with NaN here") }
Тип принуждения к объектам
До сих пор мы посмотрели принуждение к типу для примитивных ценностей. Это не очень захватывающе.
Когда дело доходит до объектов и двигателя, сталкивается с выражением, как [1] + [2,3]
Сначала ему необходимо преобразовать объект в примитивное значение, которое затем преобразуется в конечный тип. И еще есть только три типа преобразования: числовая, струнная и логическая.
Самый простой случай – булево преобразование: любая не примитивная ценность всегда принуждено к правда
Независимо от того, если объект или массив пусты или нет.
Объекты преобразуются в примитивы через внутреннюю [[Отправьте]]
Метод, который несет ответственность за числовое и строковое преобразование.
Вот псевдо реализация [[Отправьте]]
Метод:
[[Отправьте]]
пропускается с входным значением и предпочтительным типом преобразования: Номер
или Строка
Отказ ПредпочтительТтип
не является обязательным.
Как числовое и строковое преобразование использует два метода входного объекта: Ценность
и TOSTRING
Отказ Оба метода объявлены на Объект. Прототип
и поэтому доступно для любых производных типов, таких как Дата
, Массив
, так далее.
В целом алгоритм выглядит следующим образом:
- Если вход уже является примитивным, ничего не сделайте и верните его.
2. Позвоните input.tostring ()
, если результат примитивно, верните его.
3. Позвоните input.valueof ()
, если результат примитивно, верните его.
4. Если ни input.tostring ()
ни input.valueof ()
Урожай примитив, бросок Типеррор
Отказ
Числовое преобразование Первые звонки Ценность
(3) С ответвлением к TOSTRING
(2). Конверсия строки делает противоположное: TOSTRING
(2) с последующим Ценность
(3).
Самые встроенные типы не имеют Ценность
или иметь Ценность
Возвращение это
Сам объект, так что он игнорируется, потому что это не примитивно. Вот почему числовое и строковое преобразование может работать то же самое – оба в конечном итоге вызывают TOSTRING ()
Отказ
Различные операторы могут вызвать либо числовое или строковое преобразование с помощью ПредпочтительТтип
параметр. Но есть два исключения: свободное равенство ==
и бинарный +
Операторы триггеруют режимы преобразования по умолчанию ( PreferredType
не указан или равен по умолчанию
). В этом случае большинство встроенных типов предполагают числовое преобразование в виде по умолчанию, кроме Дата
это строковое преобразование.
Вот пример Дата
Поведение преобразования:
Вы можете переопределить по умолчанию TOSTRING ()
и ValueOf ()
Методы для подключения к объектно-примитивной конверсию.
Обратите внимание, как obj + ''
Возвращает '101'
как строка. +
Оператор запускает режим преобразования по умолчанию, и как сказал до Объект
Предполагается, что числовое преобразование в виде по умолчанию, таким образом, используя ValueOf ()
метод в первую очередь вместо TOSTRING ()
Отказ
ES6 Symbol. Топривисительный метод
В ES5 вы можете подключить к логике преобразования объекта к примитивным путем, переопределив TOSTRING
и Ценность
методы.
В ES6 вы можете пойти дальше и полностью заменить внутреннюю [[Отправьте]]
рутина путем реализации [Symbol.toprimtive]
Метод на объекте.
Примеры
Вооруженный теорией, теперь давайте вернемся к нашим примерам:
true + false // 1 12 / "6" // 2 "number" + 15 + 3 // 'number153' 15 + 3 + "number" // '18number' [1] > null // true "foo" + + "bar" // 'fooNaN' 'true' == true // false false == 'false' // false null == '' // false !!"false" == !!"true" // true ['x'] == 'x' // true [] + null + 1 // 'null1' [1,2,3] == [1,2,3] // false {}+[]+{}+[1] // '0[object Object]1' !+[]+[]+![] // 'truefalse' new Date(0) - 0 // 0 new Date(0) + 0 // 'Thu Jan 01 1970 02:00:00(EET)0'
Ниже вы можете найти объяснение для каждого выражения.
Бинарный +
Оператор вызывает числовое преобразование для правда
и ложный
true + false ==> 1 + 0 ==> 1
Оператор арифметической дивизии /
Триггеры числовое преобразование для строки '6'
:
12 / '6' ==> 12 / 6 ==>> 2
Оператор +
Увеличить ассоциативность, поэтому выражение «Номер» + 15
работает в первую очередь. Поскольку один операнд – это строка, +
Оператор триггеры строки преобразования для числа 15
Отказ На втором шаге выражение "№15" + 3
оценивается аналогично.
"number" + 15 + 3 ==> "number15" + 3 ==> "number153"
Выражение 15 + 3
оценивается в первую очередь. Нет необходимости в принуждении вообще, так как обе операнды номера. На втором шаге выражение 18 + «Номер»
Оценивается, и поскольку один операнд представляет собой строку, он вызывает преобразование строки.
15 + 3 + "number" ==> 18 + "number" ==> "18number"
Оператор сравнения &
GT; Триггеры числовое преобразование f или
[1] A ND N
.
[1] > null ==> '1' > 0 ==> 1 > 0 ==> true
Унарный +
Оператор имеет более высокий приоритет за двоичным +
оператор. Итак, + 'Бар'
Выражение оценивает первый. Унарный плюс триггеры числовое преобразование для строки «Бар»
Отказ Поскольку строка не представляет действительный номер, результат является Нан
Отказ На втором шаге выражение 'foo' + Nan
оценивается.
"foo" + + "bar" ==> "foo" + (+"bar") ==> "foo" + NaN ==> "fooNaN"
==
Оператор триггеры числовой преобразования, строка «Истина»
преобразуется в Nan, Boolean правда
преобразуется в 1.
'true' == true ==> NaN == 1 ==> false false == 'false' ==> 0 == NaN ==> false
==
обычно вызывает числовое преобразование, но это не так с null
Отказ null
равна null
или undefined
Только только и не равно ничего.
null == '' ==> false
!
Оператор преобразует оба «Истина»
и «Ложь»
Строки до логика правда
, так как они не пустые строки. Тогда ==
Просто проверяет равенство двух логических правда
без всякого принуждения.
!!"false" == !!"true" ==> true == true ==> true
==
Оператор вызывает числовое преобразование для массива. Массив ValueOf ()
Метод возвращает сам массив и игнорируется, потому что это не примитивно. Массив TOSTRING ()
преобразует ['x']
просто 'x'
нить.
['x'] == 'x' ==> 'x' == 'x' ==> true
+
Оператор вызывает числовое преобразование для []
Отказ Массив ValueOf ()
Метод игнорируется, потому что он возвращает сам массив, который не примитивна. Массив TOSTRING
Возвращает пустую строку.
На втором этапе выражение '' + NULL + 1
оценивается.
[] + null + 1 ==> '' + null + 1 ==> 'null' + 1 ==> 'null1'
Логично
и
&& Операторы принуждают операнды к логии, но вернуть оригинальные операнды (не логические).
0 Является ли язвой, тогда как
‘0’ это правда, потому что это не пустая строка.
{}
0 || "0" && {} ==> (0 || "0") && {} ==> (false || true) && true // internally ==> "0" && {} ==> true && true // internally ==> {}
Никакое принуждение не требуется, потому что обе операнды имеют тот же тип. С ==
Проверяет идентификацию объекта (а не для равенства объекта), и два массива являются двумя разными экземплярами, результатом является ложь
Отказ
[1,2,3] == [1,2,3] ==> false
Все операнды не примитивные значения, поэтому +
начинается с левого запускающего числового преобразования. Оба Объект
и Массив
Ценность
Метод возвращает сам объект, поэтому он игнорируется. TOSTRING ()
используется в качестве спада. Хитрость вот что первая {}
не считается литералом объекта, а скорее как заявление об объявлении Блока, поэтому он игнорируется. Оценка начинается с следующего + []
выражение, которое преобразуется в пустую строку через TOSTRING ()
метод, а затем к 0
Отказ
{}+[]+{}+[1] ==> +[]+{}+[1] ==> 0 + {} + [1] ==> 0 + '[object Object]' + [1] ==> '0[object Object]' + [1] ==> '0[object Object]' + '1' ==> '0[object Object]1'
Это лучше объяснить шаг за шагом в соответствии с приоритетом оператора.
!+[]+[]+![] ==> (!+[]) + [] + (![]) ==> !0 + [] + false ==> true + [] + false ==> true + '' + false ==> 'truefalse'
-
Оператор вызывает числовое преобразование для Дата
Отказ Date.valueof ()
Возвращает количество миллисекунд с эпохи Unix.
new Date(0) - 0 ==> 0 - 0 ==> 0
+
Оператор вызывает преобразование по умолчанию. Дата предполагает преобразование строки как один, поэтому TOSTRING ()
Метод используется, а не ValueOf ()
Отказ
new Date(0) + 0 ==> 'Thu Jan 01 1970 02:00:00 GMT+0200 (EET)' + 0 ==> 'Thu Jan 01 1970 02:00:00 GMT+0200 (EET)0'
Ресурсы
Я действительно хочу порекомендовать отличную книгу « Понимание ES6 », написанные Николас С. Закас Отказ Это отличный ресурс обучения ES6, не слишком высокий уровень, и не слишком много копает в внутренних органах.
А вот хорошая книга только на ES5 – Meadjs написано Axel Rauschmayer Отказ
( Русский ) Современный Учебник JavaScript – https://learn.javascript.ru/ Отказ Особенно эти Два Страницы на принуждении к типу.
Таблица сравнения JavaScript – https://dorey.github.io/javascript-equality-table/
WTFJS – маленький код блога о том языке, который мы любим, несмотря на то, что нам так много, чтобы ненавидеть – https://wtfjs.com/