Сталкивались ли вы с ситуацией, когда вам нужно преобразовать строковый литерал в определенной системе счисления в целое число или число в десятичной системе, и наоборот. В этой статье я рассмотрю использование parseInt() и toString() методов в JavaScript для достижения этих преобразований, а также некоторые интересные случаи и исключения.

Начнем с parseInt
- parseInt принимает строковый литерал в качестве первого аргумента, а второй аргумент (основание) сообщает, в какой системе счисления находится строковый литерал (8-октальное, 16-шестнадцатеричное, 2-двоичное…).
- Он всегда возвращает целое число или NaN в зависимости от допустимости строкового литерала, соответствующего основанию системы счисления.
- Что, если основание системы счисления не указано? Предполагается, что это 10 в соответствии со спецификацией ECMAScript 5, за некоторыми исключениями, которые мы обсудим ниже.

Хорошо. Теперь вы знаете, что он делает. Начнем с простых примеров и нескольких интересных случаев.

parseInt(‘100’, 10) //returns 100
parseInt(‘100’, 2) //returns 4
parseInt(‘100’, 8) //returns 64
parseInt(‘100’, 16) //returns 256

Выше приведены очевидные случаи преобразования числа 100 в различных системах счисления в целое число.

parseInt('215', 2)   // returns NaN as there is no 2 in binary system
parseInt('H85', 10)  //returns NaN as there are no characters in decimal system
parseInt('85EX',10)  // returns 85 ignoring the characters after the first invalid character
parseInt('32',8)   //   returns 26
parseInt('329',8)  //   returns 26, parses till 32 and ignores 9

Что можно сделать из вышесказанного?
- Во-первых, функция возвращает NaN, если первый символ строкового литерала не является символом в указанной системе счисления.
- Во-вторых, если первый символ - действительный, он анализирует строку до тех пор, пока не обнаружит недопустимый символ, а остальные усекает.

parseInt('0xff')     //returns 255 
parseInt('0xff',16)  //returns 255
parseInt('021')      //returns 21
parseInt('021',8)    //returns 17 
parseInt(021)        //returns 17
parseInt(021,8)      //returns 15

Помните, я говорил вам, что когда основание системы счисления не указано, предполагается, что оно равно 10 за некоторыми исключениями. Ну вот и те.

В ECMAScript 5 указано:
Если основание системы счисления не определено или 0, предполагается, что оно равно 10, кроме случаев, когда число начинается с пар символов 0x или 0X, и в этом случае предполагается, что основание системы счисления равно 16.

Итак, первые два утверждения ясны. А как насчет остальных?
Я знаю, что это сбивает с толку. Мне потребовалось некоторое время, чтобы придумать теорию, чтобы выяснить, что происходит.
До ES5 предполагалось, что строковые литералы, начинающиеся с 0, должны быть восьмеричными, так же как и те, которые начинаются с 0x, являются шестнадцатеричными. Но в ES5 предполагается, что это 10. Но, думаю, это относится только к строковым литералам. Итак, когда первый аргумент не является строкой, функция parseInt считает, что он находится в восьмеричной системе, и преобразует его в строку, используя метод toString(), передавая 8 как основание в метод toString(). Это объясняет, почему передача 021 в качестве аргумента функции parseInt без указанного основания возвращает 17. Что происходит при указании основания 8. Он снова преобразует его, предполагая, что преобразованное число изначально находится в восьмеричной системе.

Звучит довольно запутанно, правда? Это только для восьмеричной интерпретации. Чтобы понять более четко, вставьте следующие утверждения один за другим в консоль разработчика и попытайтесь угадать ответ, прежде чем нажимать клавишу ВВОД.

parseInt('74')       //pretty straightforward
parseInt('74',10)    //Not much difficulty here
parseInt('074')      //Easy one
parseInt('074', 10)  //No surprises
parseInt('0X74')     //Notice the prefix 0X
parseInt(0X74)       //any different from the above answer?
parseInt('74', 16)   //just another representation
parseInt('74', 8)    //as you expected
parseInt(074)        //Now, you should be starting to understand
parseInt(074, 8)     //Isn't it similar to parseInt(parseInt('74', 8), 8)
parseInt(074,16)     //Another interesting case. Should return the same value as parseInt(parseInt('74', 8), 16)

Ну .. это о parseInt. Посмотрим, что может предложить toString().

toString() при вызове числа является противоположностью parseInt, то есть он преобразует десятичную дробь в любую систему счисления от 2 до 36.

(21).toString(2)    //"10101"
(21).toString(8)    //"25"
(21).toString(16)   //"15"
0x21.toString()     //"33"
021.toString()      //"17" (octal representation)

На Object.prototype доступен toString() метод. Этот метод может быть переопределен любым настраиваемым объектом, и когда он не переопределен, он возвращает строку "[Object type]”, где type - тип объекта.

function Vehicle (wheels, color) {
    this.wheels = wheels;
    this.color = color;
}
Vehicle.prototype.toString=function(){
    return "overridden string value"
}
let car = new Vehicle(4,'blue');
car.toString() //returns "overridden string value"

Помните, что метод parseInt внутренне вызывает toString() метод для первого переданного аргумента. Что, если вы передадите пользовательский объект в parseInt. Давай посмотрим что происходит.

function Random () { }
Random.prototype.toString = function(){
    return 11111;
}
let obj = new Random();
parseInt(obj,2)       // returns 31

Как указывалось ранее, метод toString() при вызове любого объекта наследует метод Object, если не переопределен, что помогает определить тип объекта. Приведенные ниже утверждения и примеры взяты из документации MDN.

let toString = Object.prototype.toString;

toString.call(new Date);    // [object Date]
toString.call(new String);  // [object String]
toString.call(Math);        // [object Math]
toString.call(undefined);   // [object Undefined]
toString.call(null);        // [object Null]

Я надеюсь, что осознание того, как работают toString() и parseInt(), позволит вам использовать их возможности и преобразовать числовой или строковый литерал из одной системы счисления в другую, а также легко применить остальные варианты их использования.

Спасибо, что прочитали это !! Надеюсь, сегодня вы узнали что-то новое.