Преобразование типов это процесс конвертации значения из одного типа в другой (например, строки в число, объекта к булеву значению и т.д.).
Любой тип, будь то примитив или объект, может быть преобразован в другой тип.
В JavaScript есть 3 типа преобразования:
- Строковое:
- явное - функции String(value), value.toString();
- неявное - конкатенация со строкой (с помощью бинарного + ), функция alert.
- Числовое:
- явное - функция Number(value);
- неявное:
- арифметические операции (кроме бинарного +);
- нестрогое сравнение разных типов (==, включая !=);
- унарный оператор + (например, +’58’, +true и т.п.).
- Логические (булевы) преобразования:
- явное - функция Boolean(value) (например, Boolean(‘test me’) вернет true);
- неявное:
- в логическом контексте if (val) { … } или
- при применении логических операторов (||, &&, !).
Унарным называется оператор, который применяется к одному операнду. Например, оператор унарный минус "-" - это оператор отрицания, который меняет знак числа на противоположный:
1 2 3 |
let x = 1; x = -x; console.log( x ); // -1 |
Бинарным называется оператор, который применяется к двум операндам. Например, бинарная форма минуса (арифметическое действие с двумя числами):
1 2 3 |
let x = 1, y = 3; console.log( y - x ); // 2, бинарный минус вычитает из одного числа другое |
Строковое преобразование в JavaScript
Строковое преобразование:
- явное:
- функция String(value);
- метод toString();
- неявное:
- конкатенация со строкой (с помощью бинарного + );
- функция alert, метод toFixed() и т.п.
Особенности строкового преобразования:
- стандартное строковое представление пользовательского объекта - строка "[object Object]";
- если в объекте явно присутствует метод toString, который возвращает примитив, то он используется для преобразования;
- метод toString для функции выводит её код.
Примеры строкового преобразования:
1 2 3 4 5 6 7 8 9 10 11 |
// Из двух переменных a=20 и b=16 получить переменную string, в которой будет содержаться текст “2016” let a = 20; let b = 16; // Вариант 1 (методом toString) let string_3 = a.toString()+b.toString(); // Вариант 2 (конкатенация со строкой) let string_3 = a + "" + b; console.log(string_3, typeof string_3); // 2016 string |
1 2 3 4 5 6 |
String(123); // '123' String(-123); // '-123' String(null); // 'null' String(undefined); // 'undefined' String(true); // 'true' String(false); // 'false' |
Если в объекте явно присутствует метод toString, который возвращает примитив, то именно он используется для преобразования (а не возвращает строку "[object Object]").
1 2 3 4 5 6 7 8 9 |
var user = { firstName: 'Alex', toString: function() { return 'Пользователь ' + this.firstName; } }; console.log(obj.toString()); // Пользователь Alex console.log(String(obj)); // Пользователь Alex |
Результатом toString может быть любой примитив.
Метод toString не обязан возвращать именно строку. Его результат может быть любого примитивного типа. Например, это может быть число, как в примере ниже:
1 2 3 4 5 6 7 8 9 10 11 12 |
// toString возвращает строку var obj = { toString() { return "200" } } console.log(obj + 1) // '2001' console.log(obj + 'a') // '200a' // toString возвращает число var obj = { toString() { return 200 } } console.log(obj + 1) // 201 console.log(obj + 'a') // '200a' |
Поэтому мы и называем его «строковое преобразование», а не «преобразование к строке».
Числовое преобразование в JavaScript
Числовое преобразование:
-
- явное: функция Number(value);
- неявное:
- арифметические операции (кроме бинарного +);
- нестрогое сравнение разных типов (==, включая !=);
- унарный оператор + (например, +’58’, +true и т.п.);
- функции parseInt и parseFloat.
Подробнее обо всех операторах JavaScriptпо ссылке https://developer.mozilla.org
Особенности числового преобразования:
- true → 1;
- false → 0;
- undefined → NaN;
- null → 0 (см. исключения);
- “text” → NaN;
- "" (пустая строка) → 0;
- null == undefined.
Исключения: NaN не равен ничему, даже самому себе. Оператор == обычно вызывает преобразование в число, но это не так в случае со значением null.
Оператор унарный плюс + - быстрейший и предпочитаемый способ конвертирования чего-либо в число потому, что он не выполняет каких-либо операций с числом. Он может конвертировать строковые представления целых и чисел с плавающей точкой, а также нестроковые значения true, false и null. Поддерживаются числа в десятичном и шестнадцатиричном (с префиксом "0x") формате. Отрицательные числа тоже поддерживаются (но не 16-ричные). Если он не может вычислить конкретное значение, вернет NaN.
Примеры числового преобразования:
1 2 3 4 5 6 7 8 9 |
Number(123); // 123 Number("12"); // 12 Number("-12.34"); // -12.34 Number("12s"); // NaN Number(true); // 1 Number(false); // 0 Number(undefined); // NaN Number(null); // 0 Number("\n"); // 0 |
1 2 3 4 5 6 7 8 9 10 11 |
// Неявное преобразование typeof +"123"; 123 != "456"; 4 > "5"; 5 / null; true | 0; // побитовое ИЛИ // Функция parseInt возвращает целое число, а parseFloat возвращает число с плавающей точкой // символы, не являющиеся цифрами, отсекаются (но только не в начале строки!) parseInt("200px"); // 200 (для целых чисел) parseFloat("200.456px"); // 200.456 (для дробных чисел) |
Булево (логическое) преобразование в JavaScript
- явное - функция Boolean(value) ;
- неявное:
- в логическом контексте if (val) { … } или
- при применении логических операторов ( || , && , ! ) (приводят значение операндов к логическому типу, но возвращают исходные операнды , которые могут иметь тип, отличный от логического).
Особенности булева преобразования:
-
- Boolean("", null, undefined, NaN, false, 0, -0) → false;
- Boolean(2016, ‘string’, {}, [], любой объект или массив, даже пустые) → true.
Замечание: Boolean можно заменить двойным отрицанием - !!, которое также преобразует значения к логическому типу:
1 2 |
alert( !!"non-empty string" ); // true alert( !!null ); // false |
Логические операторы ( || , && , ! ) обычно используются с булевыми (логическими) значениями, при этом возвращаемое ими значение также является булевым.
Операторы && (И) и || (ИЛИ) фактически возвращают значение одного из операндов, поэтому, если эти операторы используются с не булевыми величинами, то возвращаемая ими величина также может быть не булевой.
Оператор | Использование | Описание |
Логическое И (&&) | expr1 && expr2 (Логическое И) |
Таким образом, при использовании булевых величин в качестве операндов, оператор && возвращает true, если оба операнда true; в противном случае возвращает false. |
Логическое ИЛИ (||) | expr1 || expr2 (Логическое ИЛИ) |
Таким образом, при использовании булевых величин в качестве операндов, оператор || возвращает true, если один из операндов true; если же оба false, то возвращает false. |
Логическое НЕ (!) | !expr (Логическое НЕ) |
|
Использование оператора || (ИЛИ) для задания значений по умолчанию:
1 2 3 4 5 6 7 8 9 10 11 12 |
let userAge = { age: null, setAge(age) { this.age = age || 10; }, }; userAge.setAge(); // не передаем аргументы в метод console.log(userAge.age); // 10 userAge.setAge(25); console.log(userAge.age); // 25 |
Следующий код демонстрирует примеры использования оператора && (логическое И).
1 2 3 4 5 6 7 8 |
var a1 = true && true; // t && t возвращает true var a2 = true && false; // t && f возвращает false var a3 = false && true; // f && t возвращает false var a4 = false && (3 == 4); // f && f возвращает false var a5 = "Cat" && "Dog"; // t && t возвращает Dog var a6 = false && "Cat"; // f && t возвращает false var a7 = "Cat" && false; // t && f возвращает false value = "" && !null; // "" (возвращается первый операнд), так как пустая строка может быть преобразована к false |
Следующий код демонстрирует примеры использования оператора || (логическое ИЛИ).
1 2 3 4 5 6 7 8 9 10 |
var o1 = true || true; // t || t возвращает true var o2 = false || true; // f || t возвращает true var o3 = true || false; // t || f возвращает true var o4 = false || (3 == 4); // f || f возвращает false var o5 = "Cat" || "Dog"; // t || t возвращает Cat var o6 = false || "Cat"; // f || t возвращает Cat var o7 = "Cat" || false; // t || f возвращает Cat value = !!"" || false; // false value = !!"" || null; // null value = !!" " || null; // true |
Следующий код демонстрирует примеры использования оператора ! (логическое НЕ).
1 2 3 4 |
var n1 = !true; // !t возвращает false var n2 = !false; // !f возвращает true var n3 = !"Cat"; // !t возвращает false value = !!"" || !null; // true |
Преобразования типов при сравнении примитивов
При сравнении примитивов (кроме !== и ===) сначала всё приводится к числу, а потом сравнивается:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
'12' > 2; // true (12 > 2) true < 2 // true (1 < 2) false == 0 // true (0 == 0) // НО! '12' > '2'; // false (посимвольное сравнение: первый символ первой строки "1" меньше, // чем первый символ второй строки - "2") undefined == false // false null == false // false, т.к. null может равняться только null или undefined, и ничему другому null == null // true null == undefined // true |
Преобразование сложных типов в JS
Когда дело доходит до объектов, движок сначала приводит объекты к примитивным значениям, а уже потом выполнить финальное преобразование. Как и в случае с примитивами, объект может быть преобразован всего тремя способами (численным, строковым, булевым).
Алгоритм преобразования сложных типов (в общем случае):
- Если входящее значение уже является примитивом, то оно возвращается без изменений.
- Вызывается метод toString(), если результат вызова - примитив, то вернуть его.
- Вызывается метод valueOf(), если результат вызова - примитив, то вернуть его.
- Если ни один из методов не вернул примитив — вернуть ошибку TypeError.
При численном преобразовании сначала вызывается метод valueOf(), а уже затем toString().
При строковом преобразовании — сначала происходит вызов toString(), а уже потом valueOf().
Введенный разработчиком метод toString() объекта не обязан возвращать именно строку, его результат может быть любого примитивного типа (например, это может быть число).
1 2 |
'' + new Date // 'Thu Mar 07 2018 21:14:50 GMT+0300' (приведение к string) + new Date // 1551982490848 (приведение к number) |
При логическом (булевом) преобразовании любое не примитивное значение всегда приводится к true, включая пустые объекты и массивы.
Примеры:
1 2 3 4 5 6 |
[] + [] // "" ("" + "" - в итоге пустая строка) [] + [1] // "1" (""+"1") 1 - [1] // 0 [1] + [1] // "11" ("1" + "1") {} + {} // "[object Object][object Object]" {} - {} // NaN |
Подробнее о преобразовании типов - по ссылке . И ещё подробно тут.
Интересные задачи для понимания.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
const bool = new Boolean(false); // создаем новый объект Boolean(false) - экземпляр класса if (bool) console.log(bool); // т.к. Boolean(false) - объект, то он будет приведен к true, значит, if(bool) // true, а консоль выведет // Boolean {false} if (bool == false) console.log(bool); // сравнение bool=Boolean(false) с false // true, а консоль приведет объект к строке и выведет // Boolean {false} console.log(typeof null) // object (это баг JS, фактически null — примитивное значение) new Date(0) - 0; // 0 new Array(1)[0] + ""; // new Array(num) при вызове с единственным аргументом-числом создаёт массив данной длины, без элементов. Поэтому его нулевой элемент равен undefined, при сложении со строкой получается строка "undefined". ({})[0]; // фигурные скобки внутри круглых – это создание пустого объекта, у него нет свойства '0', т.е. значением будет undefined. [1] + 1; // 11 (массив вернет строку "1", далее - конкатенация) [1, 2] + [3, 4]; // 1,23,4 (массивы вернут строковые значения с запятыми) [] + null + 1; // null1 (массив вернет пустую строку, далее - конкатенация) [[0]][0][0]; // 0 ([[0]] – это вложенный массив [0] внутри внешнего [ ]. Затем мы берём от него нулевой элемент, и потом ещё раз) {} + {}; // [object Object][object Object] (используется toString, в итоге складываются строковые представления объектов) 0 || «0» && {} // {} (ИЛИ вернет "0", далее "0" && {}, который вернет второй операнд - {}) |