Рубрики
Без рубрики

Alexey Samoshkin JavaScript Type Concionceenceknous Your EmbiesWeinsWirds Вещи могут произойти в JavaScript [Редактировать 2/5/2018]: Этот пост теперь доступен на русском языке. Хлопья в Серж Булавик за его усилия. Тип принуждения – это процесс преобразования значения из одного типа на другой (например, string к номеру,

Alexey Samoshkin JavaScript Type Concionceenceknous Your EmbiesWeinsWirds Вещи могут произойти в JavaScript [Редактировать 2/5/2018]: Этот пост теперь доступен на русском языке. Хлопья в Серж Булавик за его усилия. Тип принуждения – это процесс преобразования значения из одного типа на другой (например, string к номеру,

Автор оригинала: 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

Есть два Особые правила помнить:

  1. При применении == к 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 Отказ Оба метода объявлены на Объект. Прототип и поэтому доступно для любых производных типов, таких как Дата , Массив , так далее.

В целом алгоритм выглядит следующим образом:

  1. Если вход уже является примитивным, ничего не сделайте и верните его.

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/