Почему ['1', '7', '11'].map(parseInt) возвращает [1, NaN, 3]

JavaScript

Перевести

оригинальныйmedium.com/dailyjs

Джаваскрипт странный. не доверяют мне? Попробуйте использовать map и parseInt для преобразования массива строк в целое число. Запустите консоль (F12 в Chrome), вставьте следующее и нажмите Enter.

['1', '7', '11'].map(parseInt);

В итоге мы получаем не массив целых чисел, например [1, 7, 11], а массив длинных чисел, например [1, NaN, 3] . Чтобы понять, что происходит, мы сначала обсудим некоторые концепции Javascript. Если вам нужна сводка (TLDR), я включил краткую сводку в конце этой истории.

Правда и ложь

Вот простой оператор if-else в Javascript:

if (true) {
    // 永远都会运行
} else {
    // 永远不会运行
}

В этом случае условие оператора if-else истинно, поэтому блок операторов if-block всегда выполняется, а блок операторов else-block игнорируется. Это простой пример, потому что true — логическое значение. Что, если мы сделаем нелогическое значение условием?

if ("hello world") {
    // 他会运行吗?
    console.log("Condition is truthy");
} else {
    // 还是运行这个?
    console.log("Condition is falsy");
}

Попробуйте запустить этот код в консоли браузера (F12 в Chrome). Вы должны обнаружить, что блок операторов if-block работает. Это связано с тем, что строковый объект "hello world" является истинным.

Каждый объект Javascript является либо истинным, либо ложным при помещении в логический контекст. Например, операторы if-else будут преобразовывать объекты Javascript в true или false. Итак, какие объекты истинны, а какие ложны? Вот простое правило:

Javascript возвращает false, когда следующие значения помещаются в логический контекст

false, 0 ("" пустая строка), null, undefined и NaN.

база (база)

0 1 2 3 4 5 6 7 8 9 10

Когда мы считаем от 0 до 9, каждое число (0-9) имеет свой знак. Однако, как только мы достигнем 10, нам понадобятся два разных символа (1 и 0) для представления числа. Это потому, что основание (или основание) нашей десятичной системы счисления равно 10.

Основание — это наименьшее число, которое может быть представлено только несколькими символами. Разные системы счета имеют разные основания, поэтому одно и то же число может относиться к разным числам в системе счета.

10进制    二进制    16进制
0         0         0
1         1         1
2         10        2
3         11        3
4         100       4
5         101       5
6         110       6
7         111       7
8         1000      8
9         1001      9
10        1010      A
11        1011      B
12        1100      C
13        1101      D
14        1110      E
15        1111      F
16        10000     10
17        10001     11

Например, глядя на таблицу выше, мы видим, что одно и то же число 11 может обозначать разные числа в разных системах счета. Если основание (основание) равно 2, значит число 3. Если основание (основание) равно 16, значит число 17.

Вы могли заметить, что в нашем примере, когда на входе 11, parseInt возвращает 3, что соответствует двоичному столбцу в таблице выше.

параметр функции

Функции в Javascript можно вызывать с любым количеством аргументов, даже если они не равны количеству объявленных аргументов функции. Отсутствующие параметры рассматриваются как неопределенные, а избыточные параметры игнорируются (но сохраняются в объекте параметров, подобном массиву).

function foo(x, y) {
    console.log(x);
    console.log(y);
}
foo(1, 2);      // logs 1, 2
foo(1);         // logs 1, undefined
foo(1, 2, 3);   // logs 1, 2

функция карты()

Мы почти на месте!

Map — это метод в прототипе Array, который возвращает новый массив с результатом передачи каждого элемента исходного массива в функцию. Например, следующий код умножает каждый элемент массива на 3.

function multiplyBy3(x) {
    return x * 3;
}
const result = [1, 2, 3, 4, 5].map(multiplyBy3);
console.log(result);   // logs [3, 6, 9, 12, 15];

Теперь предположим, что я хочу регистрировать каждый элемент с помощью map() (без оператора return). Я должен иметь возможность использовать console.log в качестве аргумента для map()...  

[1,2,3,4,5] .map(console.log);

Происходят очень странные вещи. Каждый вызов console.log регистрирует индекс и полный массив, а не только значение.

[1, 2, 3, 4, 5].map(console.log);
// 上面的例子相当于
[1, 2, 3, 4, 5].map(
    (val, index, array) => console.log(val, index, array)
);
// 而不是这样
[1, 2, 3, 4, 5].map(
    val => console.log(val)
);

Когда функция передается в map(), для каждой итерации функции передаются три аргумента: currentValue, currentIndex и полный массив. Вот почему за каждую итерацию записываются три записи.

Теперь у нас есть все детали, необходимые для разгадки этой тайны.

разгадать тайну

ParseInt имеет два параметра: строку и систему счисления (основание). Если предоставленная система счисления (база) пуста или ложна, по умолчанию база (база) устанавливается равной 10.

parseInt('11');                => 11
parseInt('11', 2);             => 3
parseInt('11', 16);            => 17
parseInt('11', undefined);     => 11 (radix(进制) 为假)
parseInt('11', 0);             => 11 (radix(进制) 为假)

Теперь давайте запустим наш пример шаг за шагом.

['1', '7', '11'].map(parseInt);       => [1, NaN, 3]
// 第一次迭代: val = '1', index = 0, array = ['1', '7', '11']
parseInt('1', 0, ['1', '7', '11']);   => 1

Поскольку 0 является ложным, база (база) устанавливается на значение по умолчанию 10. parseInt() принимает только два аргумента, поэтому ['1', '7', '11'] будут игнорироваться. Строка «1» в базе 10 (основание) представляет число 1.

// 第二次迭代: val = '7', index = 1, array = ['1', '7', '11']
parseInt('7', 1, ['1', '7', '11']);   => NaN

В базовой (базовой) 1 системе символа «7» не существует. Как и в первой итерации, последний параметр игнорируется. Итак, parseInt() вернул NaN.

// 第三次迭代: val = '11', index = 2, array = ['1', '7', '11']
parseInt('11', 2, ['1', '7', '11']);   => 3

В базовой (базовой) 2 (двоичной) системе символ «11» представляет число 3, а последний аргумент игнорируется.

Аннотация (TLDR)

['1', '7', '11'].map(parseInt) не работает должным образом, потому что map передает три аргумента в функцию parseInt() на каждой итерации. Второй параметр, index, передается в parseInt как параметр системы счисления (шестнадцатеричный). Поэтому каждая строка в массиве анализируется с использованием другой базы (базы). «7» анализируется как база (база) 1, которая является NaN, «11» анализируется как база (база) 2, ее значение равно 3, а «1» анализируется как база по умолчанию (база) ) равна 10, потому что его индекс 0 является ложным.

Я не знаю, все ли вы понимаете