Javascript умножение – Основы JavaScript для начинающих разработчиков / RUVDS.com corporate blog / Habr

Содержание

Арифметика в Javascript

Арифметические операторы используются для выполнения арифметических операций с числами (константами или переменными):

Оператор Описание
+ Сложение
- Вычитание
* Умножение
/ Деление
% Остаток от деления
++ Увеличение на 1
-- Уменьшение на 1

Арифметические операции

Типичная арифметическая операция осуществляется с двумя числами.

Этими числами могут быть константы:


var x = 100 + 50; 

или переменные:


var x = a + b; 

или выражения:


var x = (100 + 50) * a; 

Операторы и операнды

Числа в арифметической операции называют операндами.

Операция, совершаемая между двумя операндами, называется оператор.

Операнд Оператор Операнд
100 + 50

Оператор сложения (+) вычисляет сумму чисел:


 var x = 5;
 var y = 2;
 var z = x + y; 

Оператор вычитания (-) вычисляет разницу чисел:


 var x = 5;
 var y = 2;
 var z = x - y; 

Оператор умножения (*) перемножает числа:


 var x = 5;
 var y = 2;
 var z = x * y; 

Оператор деления (/) делит одно число на другое:


 var x = 5;
 var y = 2;
 var z = x / y; 

Оператор деления по модулю (%) возвращает остаток от деления двух чисел:


 var x = 5;
 var y = 2;
 var z = x % y; 

Оператор инкремента (++) увеличивает число на 1:


 var x = 5;
 x++;
 var z = x;

Оператор декремента (--) уменьшает число на 1:


 var x = 5;
 x--;
 var z = x; 

Старшинство операторов

Старшинство операторов определяет порядок, в котором совершаются операции в арифметических выражениях.

Рассмотрим следующий пример:


 var x = 100 + 50 * 3; 

Какой результат мы получим? Как при вычислении 150 * 3 или 100 + 150?

Что вычисляется первым - сложение или умножение?

И здесь действуют те же правила, что и в обычной математике: умножение вычисляется первым.

Умножение (*) и деление (/) имеют более высокий приоритет, чем сложение (+) и вычитание (-).

И также как и в обычной математике старшинство можно изменить при помощи круглых скобок:


 var x = (100 + 50) * 3; 

В этом случае первым вычисляется операция, расположенная внутри круглых скобок.

Если у нескольких операций одинаковое старшинство (как у сложения и вычитания), то они вычисляются слева направо:


 var x = 100 + 50 - 3; 

Коэффициенты старшинства операторов в JavaScript:

Коэффициент Оператор Описание Пример
20 ( ) Группирование выражений (3 + 4)
19 . Член объекта person.name
19 [] Член объекта или массива person["name"]
19 () Вызов функции myFunction()
19 new Создание объекта new Date()
17 ++ Постфиксный инкремент i++
17 -- Постфиксный декремент i--
16 ++ Префиксный инкремент ++i
16 -- Префиксный декремент --i
16 ! Логическое НЕ !(x==y)
15 typeof Тип typeof x
15 ** Возведение в степень 10 ** 2
14 * Умножение 10 * 5
14 / Деление 10 / 18
14 % Деление по модулю 10 % 5
13 + Сложение 10 + 5
13 - Вычитание 10 - 8
12 << Сдвиг влево x << 2
12 >> Сдвиг вправо x >> 2
12 >>> Сдвиг вправо (без знака) x >>> 2
11 < Меньше чем x < y
11 <= Меньше или равно x <= y
11 > Больше чем x > y
11 >= Больше или равно x >= y
10 == Равенство x == y
10 === Строгое равенство x === y
10 != Неравенство x != y
10 !== Строгое неравенство x !== y
6 && Логическое И x && y
5 || Логическое ИЛИ x || y
3 = Присваивание x = y
3 += Присваивание x += y
3 -= Присваивание x -= y
3 *= Присваивание x *= y
3 %= Присваивание x %= y
3 <<= Присваивание x <<= y
3 >>= Присваивание x >>= y
3 >>>= Присваивание x >>>= y
3 &= Присваивание x &= y
3 ^= Присваивание x ^= y
3 |= Присваивание x |= y

Внимание! Выражения в круглых скобках полностью вычисляются до применения коэффициентов остальных выражений.

Работа с числами и математическими методами в JavaScript

Подборка самых важных и часто используемых методов работы с числами и математическими функциями в JavaScript с примерами.

Вам будет проще разобраться с этими методами, если вы уже знакомы с типами данных в JavaScript.

Основы работы с числами

Это означает, что все числа в JavaScript имеют плавающую запятую. Пусть вас не обманывает запись var x = 1, на самом деле это float, равный 1.0.

Если вы действительно хотите разобраться в особенностях чисел в JS, загляните сюда:

А в этой статье мы сконцентрируемся на методах работы со значениями типа Number.

Создание чисел

Объявить переменную, содержащую числовое значение, можно с помощью ключевых слов let (если она будет изменяться) или const (если не будет). Перед отрицательными числами ставится -:

const PI = 3.14
const x = 1
const n = -10

Единственный 0 в целой или дробной части числа можно не указывать, но все же стоит это делать для лучшей читаемости кода.

const y = 0.15
const z = .90
const t = 5.

Будьте осторожны с ограничениями по размеру:

const r = 9999999999999999 // 10000000000000000
const l = 999999999999999999999999 // 1e+25
const i = Infinity // Infinity - бесконечность со знаком +

Конвертация в число:

const str = '24.23'
const bin = '110110'
const short = +str // 24.23
const num = Number(str) // 24.23

// второй аргумент – основание системы счисления
const b = Number.parseInt(bin, 2) // 54

Можно работать и в других системах счисления:

const hex = 0xff // 255

const octal = 012 // 10
const betterOctal = 0o23 // 19 - способ работы с восьмеричной системой, введенный в ES6

const binary = 0b1101 // 13

Важные принципы

  • все числа – с плавающей точкой;
  • все числа имеют один тип - "number";
  • как и в других языках, в JS существуют ограничения по максимальному размеру и точности чисел.

Основные методы

Безопасные числа

Скорее всего, вы хотите, чтобы значение числа всегда оставалось тем же самым, что вы ему задали. Но если вы используете в коде, к примеру, число 900719925474099164 оно превратится в 900719925474099200. Дело в том, что оно выходит за пределы так называемого безопасного диапазона.

Узнать эти пределы можно, обратившись к свойствам объекта Number MIN_SAFE_INTEGER и MAX_SAFE_INTEGER. А с помощью функции Number.isSafeInteger можно определить, является ли число безопасным.

// константы минимального и максимального безопасных чисел
Number.MAX_SAFE_INTEGER // 9007199254740991
Number.MIN_SAFE_INTEGER // -9007199254740991

// не путайте их с минимальным и максимальным числом
Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_VALUE // 5e-324

// проверка, находится ли число в безопасном диапазоне
Number.isSafeInteger(1.7976931348623157e+308) // false
Number.isSafeInteger(9007199254740991) // true

Целое ли число?

Используйте метод isInteger объекта Number. Если число не имеет десятичной части, он возвращает true. Обратите внимание, что числа с пустой десятичной частью автоматически конвертируются в целые.

Number.isInteger(5) // true
Number.isInteger(5 / 2) // false
Number.isInteger(5.00) // true

Есть более короткий, но менее читаемый способ проверить, целое ли число:

5 % 1 === 0 // true
5.5 % 1 === 0 // false

Изменение количества знаков после запятой

Используйте метод Number.toFixed, который принимает количество знаков десятичной части, а возвращает строковое представление числа в нужном формате.

const a = 5.6710142
const b = 0.993

a.toFixed(2) // '5.67'
a.toFixed(1) // '5.7'

b.toFixed() // '1'
b.toFixed(20) // '0.99299999999999999378'
b.toFixed(30) // некоторые браузеры не поддерживают более 20 символов

Также можно воспользоваться методом Number.toPrecision, которому нужно передать количество значащих цифр числа. На выходе также получается строка:

const a = 5.6710142
const b = 0.993

a.toPrecision(2) // '5.7'
a.toPrecision(1) // '6'

b.toPrecision() // 0.993
b.toPrecision(20) // 0.99299999999999999378

Преобразование в экспоненциальную форму

Экспоненциальная форма известна также известна как научная нотация. Для преобразования существует специальный метод toExponential. Его единственный необязательный параметр – количество цифр после запятой.

const x = 25893210
const y = 33.1894
const z = 10000000

const p = x.toExponential() // '2.589321e+7'

y.toExponential() // '3.31894e+1'
z.toExponential() // '1e+7'
z.toExponential(2) // '1.00e+7'

// обратное преобразование

console.log(p) // '2.589321e+7'

Number(p) // 25893210

parseFloat(p) // 25893210

Глобальные функции для работы с числами и методы Number

Вы, возможно, знаете, что существуют глобальные функции вроде parseInt, но только что мы использовали Number.parseInt().

Дело в том, что последний стандарт JavaScript пытается модуляризировать глобальные сущности и обновляет некоторые существующие модули. Например, метод isNaN отличается от нового метода Number.isNaN.

Работа с большими числами

Тип BigInt на данный момент находится в статусе предложения и недоступен в ряде браузеров. Большие числа создаются путем добавления n в конец числа или с помощью конструктора.

const large = 9007199254740991n
const constructed = BigInt(9007199254740991) // 9007199254740991n
const fromString = BigInt('9007199254740991') // 9007199254740991n
const safe = BigInt(Number.MAX_SAFE_INTEGER) // 9007199254740991n

safe + 3n // 9007199254740994n
large + safe // 18014398509481982n

Пока нет полной поддержки BigInt, вы можете использовать библиотеку bignumber.js.

Преобразование в другую систему счисления

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

const num = 3241
const bin = num.toString(2) // '110010101001'

num.toString(8) // '6251'
num.toString(16) // 'ca9'
num.toString(10) // '3241'

Number.parseInt(bin, 2) // 3241

Методы числовых литералов

Возможно, вы попытались применить какой-нибудь метод к числовому литералу (

23.toString(2)) и получили синтаксическую ошибку. Это связано со специфическим представлением чисел в JavaScript. Валидная форма для числа 23 - 23. или 23.0 (0 в дробной части можно не указывать).

Когда вы пишете 23.toString(2) JavaScript считает эту запись числом и не понимает, что вызывается метод.

Решением может быть использование скобок или двух точек для указания дробной части (хотя это довольно непонятная запись):

(23).toString(2) // "10111"
23..toString(2)

Не число – это число

Подробное объяснение этого феномена можно найти в статье JS Essentials: Types & Data Structures.

Коротко говоря, NaN является объектом класса Number, но определяется как результат математических операций, значение которых количественно число не является. Правильнее было бы назвать его Invalid Number.

NaN превращает все, с чем имеет дело, в NaN.

const a = 5 + NaN // NaN

Проверка на NaN

Это единственное значение в JavaScript, которое не равно самому себе. Мы можем использовать это, применяя проверку x !== x. Если это условие возвращает

true, то x – это NaN.

Помимо этого можно использовать методы Object.is, isNaN и новый метод Number.isNaN. Обратите внимание, два последних метода ведут себя по-разному с нечисловыми значениями.

NaN == NaN // false
NaN === NaN // false

Object.is(NaN, NaN) // true

isNaN(NaN) // true
isNaN('abc') // true

Number.isNaN(NaN) // true
Number.isNaN('abc') // false
Number.isNaN(+'abc') // true

Способы округления чисел

const x = 5.921

// округление вниз
Math.floor(x) // 5

// округление вверх
Math.ceil(x) // 6

// округление по правилам математики
Math.round(x) // 6
Math.round(5.5) // 6

// до нужного количества цифр после точки
x.toFixed(2) // 5.92
x.toPrecision(2) // 5.9

// битовый сдвиг
// работает быстрее, чем Math.floor
// но очень неочевидно для ваших коллег
x >> 0 // 5

Возведение в степень

В JavaScript существует специальный оператор степени – **. Также можно воспользоваться методом

Math.pow.

2 ** 2 // 4
let x = 2
x ** = 4 // 16
Math.pow(2, 4) // 16

Генерация случайного числа

Метод Math.random генерирует дробное число в диапазоне от 0 (включая) до 1 (не включая).

Math.random() // 0.7610368478059286

// генерация числа в диапазоне от 0 до 9
// битовый сдвиг работает как Math.floor
Math.random() * 10 >> 0
Math.floor(Math.random() * 10)

// генерация числа в диапазоне [x, y)
const getRandom = (min, max) =>
    Math.floor(Math.random() * (max - min + 1)) + min;

Вот небольшой пример: создадим сет – набор уникальных значений, заполним его случайными числами с помощью метода getRandom и отсортируем:

for (let i of Array(500)) {
   values.add(getRandom(1, 10))
}
[...values].sort((a, b) => a - b)
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

Математические функции

В модуле Math очень много полезных методов, которые вы можете найти в документации. Все они имеют довольно очевидный принцип работы.

Полезные ссылки

Практика работы с числами

Несколько полезных челленджей на codewars.com.

Перевод статьи JavaScript Essentials: Numbers and Math.

Полезные ресурсы для начинающего JavaScript-разработчика

JavaScript Арифметика



JavaScript арифметические операторы

Арифметические операторы предназначены для выполнения арифметических действий над числами (литералами или переменными).

Оператор Описание
+ Сложение
- Вычитание
* Умножение
/ Деление
% Модуль
++ Увеличение
-- Уменьшение

Арифметические операторы

Типичная арифметическая операция управляет двумя числами.

Два числа так же, могут быть литералами:

или переменные:

или выражениеми:


Операторы и операнды

Числа, в арифметической операции, называются операндами.

Операция, которая будет выполняться между двумя операндами, определяется как оператор.

Операйд Оператор Операйд
100 + 50

Оператор сложения + складывает числа:

Оператор вычитание - вычитает числа.

Оператор умножения * умножает числа.

Оператор деления / делит числа.

Оператор модуль % возвращает остаток деления.

Оператор увеличения ++ увеличивает числа.

Оператор уменьшения -- уменьшения числа.


Оператор приоритета

Приоритет оператора описывает порядок выполнения операций в арифметическом выражении.

Сложение или умножение, делается первым?

Как и в традиционной школьной математике, умножение делается первым.

Умножение * и деление / имеют наивысшей приоритет, чем сложение + и вычитания -.

И, как в школьной математике, приоритет можно изменить с помощью скобок:

При использовании круглых скобок сначала вычисляются операции внутри круглых скобок.

Когда многие операции имеют одинаковый приоритет (сложение и вычитание), они вычисляются слева направо:


JavaScript Оператор приоритет значения

Бледно-красные записи указывают на ECMAScript 2015 (ES6) или раньше.

Значение Оператор Описание Пример
20 ( ) Группировка выражений (3 + 4)
       
19 . Сотрудник person.name
19 [] Сотрудник person["name"]
19 () Вызов функции myFunction()
19 new Создать new Date()
       
17 ++ Постфикс Инкремент i++
17 -- Постфикс Декремент i--
       
16 ++ Префикс Инкремент ++i
16 -- Префикс Декремент --i
16 ! Логический не !(x==y)
16 typeof Тип typeof x
       
15 ** Возведение в степень (ES2016) 10 ** 2
       
14 * Умножение 10 * 5
14 / Деление 10 / 5
14 % Остаток Деления 10 % 5
       
13 + Сложение 10 + 5
13 - Вычитание 10 - 5
       
12 << Сдвиг влево x << 2
12 >> Сдвиг вправо x >> 2
12 >>> Сдвиг вправо (без знака) x >>> 2
       
11 < Меньше чем x < y 
11 <= Меньше или равно x <= y
11 > Больше чем x > y
11 >= Больше или равно x >= y
11 in Свойство в объекте "PI" in Math
11 instanceof Инстанция объекта instanceof Array
       
10 == Равный x == y
10 === Строго равный x === y
10 != Неравный x != y
10 !== Строго неравные x !== y
       
9 & Битовый И x & y
8 ^ Битовый НЕ x ^ y
7 | Битовый ИЛИ x | y
6 && Логический И x && y
5 || Логический ИЛИ x || y
4 ? : Кондиция ? "Yes" : "No"
       
3 += Назначение x += y
3 /= Назначение x /= y
3 -= Назначение x -= y
3 *= Назначение x *= y
3 %= Назначение x %= y
3 <<= Назначение x <<= y
3 >>= Назначение x >>= y
3 >>>= Назначение x >>>= y
3 &= Назначение x &= y
3 ^= Назначение x ^= y
3 |= Назначение x |= y
       
2 yield Функция "Пауза" yield x
1 , Запятая 5 , 6

Выражения в круглых скобках полностью вычисляются перед значением используется в остальной части выражения.



Математики в шоке: в JavaScript происходит такое!

В это невозможно поверить! 0.1 + 0.2 не равно 0.3! Math.max() меньше, чем Math.min()! Заходи и узнай сам, как JavaScript нас обманывает!

Доводилось ли вам сталкиваться с необъяснимым? Если вы работаете с JavaScript – определенно, да. Этот язык полон тайн, загадок и невероятных феноменов, которые шокируют неподготовленных разработчиков. Но сегодня мы раскроем все секреты JavaScript! Так ли он нелогичен, как нам кажется?

Предупреждение: уберите от экранов детей и особо впечатлительных взрослых!

Невероятно, но JavaScript

Надеемся, ваши нервы достаточно крепки, чтобы выдержать это.

Что вы ожидаете получить в результате каждого из этих примеров?

0.1 + 0.2 == 0.3 
9007199254740991 + 1 === 9007199254740991 + 2
Math.sqrt(-1) == Math.sqrt(-1)
Math.max() > Math.min()
['1', '7', '11'].map(parseInt)
[] + {}
{} + []
1 < 2 < 3
3 > 2 > 1

Вероятно, совсем не то, что вы получите на самом деле!

Откройте JavaScript-консоль браузера и проверьте.

Безусловно, вы шокированы. Вы чувствуете себя обманутым. Язык JavaScript растоптал ваши ожидания, он лжет вам в лицо, коверкая простейшие математические операции. Вы вправе негодовать и осуждать его!

Но подождите, может быть, у JavaScript есть причины так поступать? Может быть, узнав об этих причинах, мы сможем понять его и простить? Возможно, этот язык программирования не совсем потерян для общества и достаточно логичен, чтобы иметь с ним дело?

Когда точки умеют плавать

Феномен

0.1 + 0.2 == 0.3 // false

Объяснение

В JavaScript есть всего лишь один тип для представления чисел – Number, напоминающий double из Java. Это числа двойной точности (64 разряда) с плавающей точкой, соответствующие стандарту IEEE 754.

Суть концепции чисел с плавающей точкой заключается в разделении одного числа на два:

  • мантисса, или значимая часть, содержит цифры;
  • экспонента указывает, где в мантиссе необходимо расположить десятичную точку.

В самом старшем разряде числа хранится его знак, еще 11 битов отведено под экспоненту, оставшиеся занимает мантисса.

Реализация таких чисел может быть очень сложной, ведь в ограниченном количестве разрядов необходимо разместить много информации.

Проблемы такого формата широко известны – он плохо справляется с десятичными дробями. Особенно это важно при работе с денежными суммами. Так, язык JavaScript (и не только он) не может точно представить 0.1 и большую часть других дробей, которые в двоичной системе являются бесконечными.

Вот как на самом деле JS видит эти числа:

Чаще всего погрешности очень малы (иногда они даже взаимно поглощаются) и не приносят никаких проблем. Если высокая точность дробей не является критичной для вашего приложения, достаточно просто округлять полученные результаты или пользоваться обходными приемами вроде умножения и последующего деления на 10.

Чтобы числа с плавающей запятой перестали пугать вас, загляните сюда:

Когда умеешь считать только до 9 квадриллионов

Феномен

9007199254740991 + 1 === 9007199254740991 + 2 // true

Объяснение

Разумеется, это огромное число (9007199254740991) не взято с потолка. Это значение константы Number.MAX_SAFE_INTEGER. Иными словами – верхний предел диапазона безопасных вычислений.

Есть, конечно, и нижний предел – Number.MIN_SAFE_INTEGER.

Пока JavaScript разработчик оперирует числами в этом диапазоне, математические законы (сочетательный, распределительный) работают без фокусов. Вне его начинаются чудеса.

Например, порядок сложения одних и тех же чисел может повлиять на результат:

Читайте подробнее о безопасных числах и других интересных математических особенностях JavaScript в нашей статье.

Когда "не-число" – это число

Феномен

Math.sqrt(-1) == Math.sqrt(-1) // false

Объяснение

Результатом выражения Math.sqrt(-1) является NaN (Not a Number) – специальное значение JavaScript. Получается, что одно значение NaN не равно другому.

На самом деле NaN не равно вообще ничему. Так определено в стандарте IEEE 754, с которым мы познакомились чуть раньше. Даже если вы запишете его в переменную и сравните ее с самой собой, получите false. Вот такое специфическое значение.

В этом есть определенный смысл. По своей сути NaN – это результат, который не определен или не имеет смысла. И один такой результат не может быть равен другому.

Например, квадратный корень из отрицательного числа не определен, так же как и его логарифм, и попытка преобразования строки в число.

Math.sqrt(-1) // NaN
Math.log(-5) // NaN
parseInt("string") // NaN

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

Не следует при этом забывать, что NaN в JavaScript является числом:

Когда бесконечность – это предел

Феномен

Math.max() > Math.min() // false

Объяснение

Понять это неравенство очень просто – достаточно вывести на консоль значение каждой стороны отдельно:

Сложнее понять, почему метод Math.max без аргументов возвращает минус бесконечность, а Math.min – плюс бесконечность. Впрочем, здесь тоже все довольно логично.

Для Math.min минимальным значением в наборе становится самое большое возможное число, которое меньше или равно каждому члену набора. В непустом множестве такое число ограничено меньшим из его членов. Но если множество пустое, то для этого числа нет никаких ограничений – и возвращается бесконечность. В пустом наборе нет члена больше, чем бесконечность.

Аналогичные рассуждения приводят нас к заключению, что минус бесконечность – вполне логичный результат вызова Math.max без аргументов.

Когда пытаешься помочь

Неявное приведение типов (type coercion) в JavaScript – самое благодатное поле для появления непониманий и неожиданностей. Правил преобразования – много, ситуаций – еще больше, ну как тут разобраться. Язык очень старается облегчить жизнь разработчику, но частенько, наоборот, усложняет ее.

Феномен

[] + {} // '[object Object]'
{} + [] // 0

Объяснение

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

Array.prototype.toString просто объединяет все значения массива в строку. Так как массив пустой, возвращается пустая строка.

Для обычного объекта метод toString() возвращает строку [object Object].

В итоге получается "" + "[object Object]" -> "[object Object]".

Во втором выражении плюс ведет себя совсем по-другому. Фигурные скобки в начале он принимает за отдельно стоящий блок инструкций, пустой блок, поэтому игнорирует его. Остается лишь часть + []. Здесь плюс является простым унарным оператором, который неявно приводит значение к числу. Пустой массив приводится к нулю.

Феномен

1 < 2 < 3 // true
3 > 2 > 1 // false

Объяснение

JavaScript начинает разбирать выражение слева направо. В первом примере сначала обрабатывается сравнение 1 < 2 и возвращается true. Теперь мы имеем true < 3. Чтобы решить эту задачку интерпретатор приводит булево значение (true) к числовому (1). 1 меньше 3, так что на выходе получается true.

Разберемся точно так же со вторым выражением:

  • Выполнение первого неравенства: 3 > 2 -> true.
  • Теперь имеем true > 1.
  • Для выполнения полученного неравенства нужно привести типы – 1 > 1, что, разумеется, ложно.

Феномен

const a = {
  i: 1,
  toString: function () { 
    return a.i++; 
  }
}
a == 1 && a == 2 && a == 3 // true

Объяснение

Практический смысл этой конструкции мало понятен, однако в коде порой встречаются и более страшные монстры. Если JavaScript разработчик не до конца отдавал себе отчет, создавая этот фрагмент, он может столкнуться с необычным поведением. На самом же деле тут нет ничего таинственного.

  • a – это объект;
  • При сравнении объекта с числом интерпретатор JavaScript пытается привести его к примитивному значению и использует для этого метод toString().
  • При каждом вызове переопределенный метод toString() возвращает значение свойства a.i и увеличивает его на единицу.
  • Таким образом, в первом равенстве a.i равно единицы, а во втором уже двойке, так как вызванный метод toString() успел его увеличить.
  • Вуаля! Все три равенства выполняются с истинным результатом.

Когда никто не читает документацию

Феномен

['1', '7', '11'].map(parseInt) // [1, NaN, 3]

Объяснение

Вы, вероятно, ожидали, что функция parseInt, переданная в перебирающий метод массива map, просто превратит строки в числа. Но что-то пошло не так. Уже догадались, что именно?

Смотрите, в таком виде выражение отработает абсолютно правильно:

Проблема в количестве аргументов в сигнатуре каждой из функций.

Метод Array.prototype.map передает в коллбэк для каждого элемента массива не один, а сразу 3 параметра:

  • значение текущего элемента;
  • его индекс;
  • и весь исходный массив целиком.

Таким образом, вот что передается в функцию обратного вызова для каждого элемента массива:

  • '1', 0, ['1', '7', '11']
  • '7', 1, ['1', '7', '11']
  • '11', 2, ['1', '7', '11']

Именно эти аргументы шаг за шагом передаются в функцию parseInt, которая является коллбэком в нашем примере.

Теперь обратимся к документации этой функции и выясним, что она принимает не один параметр (сама строка для парсинга), а два (строка и основание системы счисления в диапазоне от 2 до 36). MDN web docs предупреждает:

Всегда указывайте этот параметр (основание системы), чтобы исключить ошибки считывания и гарантировать корректность исполнения и предсказуемость результата. Когда основание системы счисления не указано, разные реализации могут возвращать разные результаты.

С такой ошибкой мы и столкнулись в этом феномене – в функцию parseInt передавалось неожиданное основание системы счисления для парсинга.

  • Первый элемент. Строка – '1', основание – 0. При неопределенном основании JavaScript предположил, что мы хотим работать с десятичной системой и распарсил строку правильно.
  • Второй элемент. Строка – '7', основание – 1. В системе с таким основанием не может быть цифры 7, возвращается NaN.
  • Третий элемент. Строка – '11', основание – 2. В двоичной системе число 11 – это вовсе не привычные нам 11, а всего лишь 3.

JavaScript: все объяснимо

Язык JavaScript нас вовсе не обманывает. Наоборот, он пытается сделать жизнь разработчика немного легче с помощью неявного приведения типов и скрытия особенностей арифметики чисел с плавающей точкой.

Но иногда разработчики сами мешают языку, создавая странный код, пользуясь плохими практиками, забывая о некоторых компромиссах или отказываясь читать документацию.

Узнайте JavaScript поближе, и загадок станет гораздо меньше 🙂

Сталкивались с другими "странностями" JavaScript? Расскажите о них.

javascript - Как выполнить умножение подхватывая числа из формы?

Stack Overflow на русском

Loading…

  1. 0
  2. +0
    • Тур Начните с этой страницы, чтобы быстро ознакомиться с сайтом
    • Справка Подробные ответы на любые возможные вопросы
    • Мета Обсудить принципы работы и политику сайта
    • О нас Узнать больше о компании Stack Overflow
    • Бизнес Узнать больше о поиске разработчиков или рекламе на сайте

Отправить ответ

avatar
  Подписаться  
Уведомление о