Я был заинтригован одним вопросом, который спросил на моем Таким образом, вы думаете, что вы знаете артикул JavaScript.
{} + []; // returns 0 ?? 🤔
Я признаю, что в тот момент я не знал правильный ответ, но вместо того, чтобы обвинять и критиковать систему принуждения и типа JavaScript, я влюблен в спецификации, чтобы найти определение Дополнение оператора Отказ Сначала спецификация не имеет большого смысла для меня. Я нашел это многолетнее. Может быть, мой мозг не обучен на чтении спецификаций. Да, давайте честным, сколько из нас читают спецификации, когда есть вопрос о JavaScript? У нас есть наш любимый Переполнение стека . Правильно?
Ну, я отчаянно хотел узнать ответ. Я не хотел быть в категории этих разработчиков, которые считают принуждение как внутреннюю магию и опасную, чтобы избежать или избегать.
Итак, эта статья – поделиться своим пониманием Принуждение В JavaScript и иллюстрируйте, почему плохая репутация принуждения преувеличена и несколько незаслужена – чтобы перевернуть свою перспективу, чтобы вы могли видеть его полезность и мощность.
Система типа JavaScript
JavaScript это Динамически набран Язык, где переменные нет типов- Значения имеют типы Отказ Система типа JavaScript не обеспечивает примечания того, что переменная всегда удерживает тот же самый начальный тип, с которым он начинается.
// variable 'a' starts out with holding a string value type. var a = 'some string'; // you can change the type in the next line and it's completely valid // Now, the variable 'a' holds the value of type number a = 10;
Я всегда вижу это одной из самых сильных точек системы JavaScript System. Но некоторые разработки от сильно напечатанного языка могут найти это как недостаток на языке и объектируйте использование слова «тип». И я думаю, что это одна из многих причин, по которым мы постоянно изучаем пути ( Поток и TeampScript ) Чтобы поставить слой типа системы на языке. На мой взгляд, это как у нас есть JavaScript javascript в системе, которая является не в ДНК языка.
Я считаю, что мы всегда должны стремиться изучать основы и думать одинаково JavaScript. Вместо того, чтобы течь против него, давайте течь к нему и посмотрим, почему вышеупомянутый вопрос не должен быть переоценен, думая, что JavaScript странный.
Давайте быстро пересматриваем то, что мы все знаем о Типы JavaScript И тогда мы будем глубоко погружаться в Принуждение в более поздних разделах.
JavaScript имеет семь встроенных типов:
- нулевой
- неопределенный.
- нить
- номер
- логический
- объект
- символ
Кроме объект Все остальные типы называются «примитивы». Тип Оператор – это хорошая встроенная утилита для проверки типов. Имейте в виду, что Тип всегда возвращает Строка тип.
typeof 'you are awesome!' // 'string'
typeof 42 // 'number'
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof {name: 'aman'}. // 'object'
typeof Symbol() // 'symbol'
------------------------
typeof function foo(){}. // 'function'
typeof [] // 'object'
Вы будете интересно, зачем вызов Тип на Функция и Массив вернуть «функцию» и «объект» соответственно. Причина в том, что функции и Массив подтипы объект тип. И из-за этого вы можете добавлять свойства на функцию и вызывать некоторые методы, которые имеет тип объекта- TOSTRING () и ValueOf () Отказ
function foo(a,b){}
// you can add any property on foo object.
foo.someProperty = 'I am a property on foo function';
// function object has 'length' property set to number of formal params it takes when declared
foo.length; // 2
// invoke 'toString()'
foo.toString(); // "function foo(a,b){}"
// invoke 'valueOf'
foo.valueOf(); // return this -> the function itself
Бонус : Согласно Тип SPEC, если тип объекта реализует внутреннюю [[Звонок]] Метод, то Тип Проверить возвраты «Функция». Объектные литералы и массив не реализуют его, но функция делает.
Есть несколько готов, которые вам нужно знать с Тип оператор. Как вы, возможно, заметили, что я исключил Тип ноль из списка выше. Причина в том, что null это особый случай, когда Тип Оператор возвращает «объект». Это единственный примитив в JavaScript, который является «Falsy» и возвращает «объект» от Тип чек.
Примечание : null является единственным примитивным в JavaScript, который является « Falsy ‘и возвращает’ объект ‘От Тип чек.
typeof null; // 'object';
Итак, как бы вы пошли проверить null Тип явно? Вам может понадобиться заявление, как:
var a = null; !a && typeof a == 'object'; // true // Or you can use strict equality comparison a === null; // true
Давайте рассмотрим еще одну quirk с оператором типа:
var a; typeof a; // 'undefined' typeof b; // 'undefined'
В JavaScript, VAR объявлен Переменные получают значение undefined когда у них нет текущего значения. И вот причина Тип Оператор возвращает ‘ undefined ‘. Но если вы видите, что мы не объявили переменную B где угодно, но Тип Оператор все еще удается напечатать «undefined». Это потому, что JavaScript Engine воспроизводится безопасным и вместо того, чтобы возвращать некоторую ошибку, он возвращает undefined.
Как я уже говорил, зная, что эти различия – это все равно что согласовать ваш разум с помощью JavaScript Engine. Каждый язык имеет несколько уголков. JavaScript не является исключением. Вместо того, чтобы сделать шутку о языке, я думаю, что решается понять их, чтобы вы могли принимать лучшие решения в вашей программе.
Теперь давайте перейдем к следующей части взаимопонимания принуждения в JavaScript.
Принуждение
Принуждение AKA ‘Type Conversion’ – это механизм преобразования одного типа на другой. В статически (сильно) напечатанном языке этот процесс происходит при компиляционном времени, тогда как принуждение – это преобразование времени выполнения для динамически набранных языков.
В JavaScript мы можем иметь два типа принуждения: «неявный» и «явный». Как подразумевает имя, неявный Принуждение – это тот, который происходит как менее очевиден побочный эффект какой-то преднамеренной операции. Наоборот, явный
var a = 10;
var b = 'programmer' + a; // implicit coercion
var c = `you owe me ${a} dollars`. // implicit coercion
var d = String(a); // explicit coercion
var e = Number('42') // explicit coercion
Вы когда-нибудь задумывались, насколько принудительно работает внутри страны? Вот где все интересно. Но прежде чем мы сможем исследовать внутренние процедуры, нам нужно понимать некоторые операции, которые определены в ECMAScript 2020 раздел 7, называемые Абстрактная операция Отказ Эти операции не являются частью языка, но используются для помощи спецификации семантики языка JavaScript. Вы можете думать об этих операциях как концептуальные операции.
Абстрактные операции
Каждый раз, когда происходит конверсия стоимости, оно обрабатывается одной или несколькими абстрактными операцией с некоторыми правилами, определенными в спецификации. Здесь мы рассмотрим три абстрактных операции: TOSTRING , Тонобил и Отправляющий Отказ
Абстрактные операции используются для помощи спецификации семантики языка JavaScript.
Нанизывать
Всякий раз, когда мы принудием некруточное значение для строкового значения, TOSTRING обрабатывает преобразование как в Раздел 7.1.12 спецификации. Примитивные типы имеют естественную строги. Стол выглядит как:
// ToString abstract operation (string conversion) null -> 'null' undefined -> 'undefined' true -> 'true' false -> 'false' 52 -> '52'
Для обычного объект и Массив , по умолчанию TOSTRING () вызывается, который определен на Объект. Прототип
var a = {language: 'JavaScript'};
a.toString(); // "[object Object]"
[].toString(); // ""
Вы также можете указать свой собственный TOSTRING Метод переопределить значение возврата по умолчанию:
var a = { language: 'JavaScript', toString(){return 'I love JavaScript'} };
a.toString(); // "I love JavaScript"
Тональный
Всякий раз, когда не имеющее значение поставляется в операции, где ожидается число, например, математическая операция, ES2020 определяет Тонобил Абстрактная операция в Раздел 7.1.3 Отказ Например
// ToNumber abstract operation (number conversion) true -> 1 false -> 0 undefined -> NaN (not a valid number) null -> 0
Для объект и Массив , значения сначала преобразуются в их Примитивное значение Эквивалент (через Toprimitive Операция) И полученное значение затем принуждено к числу в соответствии с Тонобил Абстрактная операция.
Toboolean.
Toboolean немного проще, чем TOSTRING и Тонобил Работа, так как это не делает внутреннее преобразование. Он выполняет только настольный поиск, как упомянуто в Раздел 7.1.2 Отказ
| ложный | неопределенный |
| ложный | нулевой |
| Возврат аргументации | логический |
| Если аргумент +0, -0 или NAN, верните false; в противном случае правда | номер |
| Если аргумент является пустой строкой, верните false; в противном случае правда | нить |
| истинный | символ |
| истинный | объект |
Потрясение
Если у нас нет примитивного типа (например, функция, объект, массив), и нам нужен примитивный эквивалент, ES2020 определяет Отправляющий в Раздел 7.1.1 Отказ
Toprimitve Операция принимает два аргумента: ввод и Подсказка (по желанию). Если вы выполняете числовую операцию, подсказка будет типа «номер». А для операции строки (вроде конкатенации) пропущенной подсказкой будет строка. Обратите внимание, что торадимость – это рекурсивная операция, которая означает, что если результат вызовов срабатывания не является примитивным, он снова будет вызывать, пока мы не сможем получить примитивную ценность или ошибку в некоторых случаях.
Теперь давайте посмотрим на алгоритм за топравированными операциями.
Каждый не примитивный может иметь два метода: TOSTRING и значение Отказ Если подсказка «номер» отправляется, ValueOf () Метод вызывается первым. И если мы получим Примитивный тип из результата, тогда мы сделаем. Но если результат снова является немитивным, TOSTRING () позывается Аналогично, в случае «строкового» типа подсказки порядка этих операций обращается. Если вызов этих двух операций не возвращает примитив, вообще это Типеррр Отказ
Визуально заказ можно рассматривать следующим образом:
// ToPrimitive Abstract Operation // hint: "number" valueOf() toString() // hint: "string" toString() valueOf()
Чтобы сделать его более понятным, вот диаграмма блок-диаграммы алгоритма, которую мы обсуждали выше:
Сейчас вооружен этим новым знанием абстрактных операций, пришло время уверенно ответить на несколько вопросов.
Тестирование наших знаний
// Why the following expression produces '5' as a result? [] + 5; // '5'
Согласно спецификации в разделе дополнение оператора ‘+’ выполняет конконтрацию строки или числовое добавление на основе типа аргумента. Если любой из аргументов является строка, он будет выполнять строковые конкатенацию. Это называется Оператор перегрузки Отказ Теперь давай посмотрим, как мы в конечном итоге получили строку “5” ?
Мы ожидали, что Примитивный тип Но в конечном итоге получить Массив как один из аргументов. Следовательно, Отправляющий Абстрактная операция выполняется с «Номер» прошел как намек. Ссылаясь на торавную диаграмму выше, мы можем утверждать, что следующие шаги будут иметь место для получения результата.
- []. ValueOf () //возвращает [];
- Как, [] это не Примитивный двигатель вызван []. TOSTRING () в результате чего Пустой нить.
- Теперь выражение уменьшает до “+ 5 Отказ
- Как мы упоминали, что Оператор дополнения выполняет конкатенацию строки Когда любой из аргумент это Тип строки Отказ
- Итак, 5 будет неявно привлечен к “5” через TOSTRING Абстрактная операция, проходящая «строка» как намек.
- Наконец выражение сводится к “” + “5” в результате чего ценить “5” Отказ
[] + 5; // ToPrimitive is invoked on [] // "" + 5; // "" + "5"; // "5"
Теперь это момент внутреннего удовлетворения. Не так ли? Я не знаю о тебе Но когда я понял это, я был в восторге.
Прежде чем мы завершите, давайте быстро демистифицируйте некоторые из следующих выражений для укрепления нашего захвата. Я собираюсь уменьшить выражение сверху вниз (через абстрактные операции), чтобы достичь результата.
[] + []; // ToPrimitive is invoked on both operands
// "" + "";
""
----------
[] + {}; // ToPrimitive is invoked on both operands
// "" + "[object Object]";
"[object Object]"
----------
'' - true;
// There's no operator overloading for subtract operator.
//ToNumber is invoked on both the operands (already primitive)
// 0 - 1;
-1
-----------
1 < 2 < 3;
// (1 < 2) < 3;
// true < 3; // ToNumber is invoked on true -> 1
// 1 < 3;
true;
-----------
3 < 2 < 1; // true ooops!
// (3 < 2) < 1;
// false < 1; // ToNumber is invoked on false -> 0
// 0 < 1;
true
Сейчас самое время ответить на вопрос, который в основном привел меня к написанию этой статьи.
{} + []; // 0 🤔??
Здесь ‘{}’ это не пустой объект Но просто пустой блок {}. Итак, JavaScript Engine игнорирует это и осталось с + [] утверждение для выполнения. Это Числовая операция и, следовательно, а «Номер» Подсказка будет передана для преобразования этого пустого массива в Примитивный Значение, которое является Пустая строка Отказ Наконец, пустая строка снова принуждена через Тонобил Операция, ведущая к значению 0 Отказ 😀
{} + []; // empty block is ignored
// + [];
// + '';
// + 0 ;
0
Резюме:
- JavaScript – это динамически напечатанный язык, где Значения имеют тип -Не переменные.
- Принуждение ака «преобразование типа» является процедурой преобразования одного типа значения в другое; Это происходит при компиляционном времени для JavaScript.
- Принуждение может быть двух типов: неявный и явный Отказ
- Абстрактные операции являются ключами для понимания принуждения. Они не являются фактическими операцией на языке, но используются для помощи спецификации семантики языка JavaScript.
- Всякий раз, когда мы получаем не примитивное значение для операции, где ожидалось примитивного типа, Отправляющий Абстрактная операция вызывается.
- Для любого не примитивного, топравизма вызывает два метода: ValueOf () и TOSTRING () Отказ В зависимости от Подсказка прошло, ValueOf () сопровождается TOSTRING () вызывается для «числа» подсказки и наоборот для «строки».
Вывод:
Динамическая природа JavaScript является одним из его основных функций. Понимание того, как принудительно работает внутри, может помочь нам написать надежный код. У каждого языка есть некоторые причуды, и наша ответственность в качестве разработчика помнить об этих предостережениях. Вместо того, чтобы найти недостатки, нам нужно стремиться к изучению семантики языка и работать по отношению к нему.
Надеюсь, вам понравилась статья, и если это логический истинный Несколько ❤️ заставит меня улыбаться 😍.
Оригинал: “https://dev.to/aman_singh/abstract-operations-the-key-to-understand-coercion-in-javascript-453i”