Почему parseInt возвращает NaN с картой Array #?

Из Сеть разработчиков Mozilla:

[1,4,9].map(Math.sqrt)

будет давать:

[1,2,3]

Почему тогда это:

['1','2','3'].map(parseInt)

дать это:

[1, NaN, NaN]

Я тестировал Firefox 3.0.1 и Chrome 0.3, и, как отказ от ответственности, я знаю, что это не кроссбраузерная функциональность (без IE).

Я обнаружил, что следующие действия принесут желаемый эффект. Однако это все еще не объясняет ошибочное поведение parseInt.

['1','2','3'].map(function(i){return +i;}) // returns [1,2,3]

Для ленивых: используйте .map(parseFloat), потому что он принимает только один параметр.

user669677 31.08.2013 15:29

Или используйте .map(Number).

Nikolai 22.09.2013 21:26

вы можете arr.map (Math.floor), если вам нужны целые числа без функции, созданной вручную.

dandavis 03.10.2014 02:57

@Nikolai user669677 отличные предложения! Я бы поддержал это в ответе

BiAiB 30.09.2015 15:48

может ли кто-нибудь объяснить, почему parseInt правильно анализирует первое число и делает ошибку не для первого индекса

bawa g 03.04.2018 10:33

См. Также это отличное объяснение здесь: wsvincent.com/javascript-parseint-map

Wilt 10.12.2018 21:22

ответ здесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

chharvey 27.01.2019 22:59
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
299
7
39 414
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Держу пари, что со вторым параметром parseInt, radix, происходит что-то странное. Почему он ломается при использовании Array.map, а не при прямом вызове, я не знаю.

//  Works fine
parseInt( 4 );
parseInt( 9 );

//  Breaks!  Why?
[1,4,9].map( parseInt );

//  Fixes the problem
[1,4,9].map( function( num ){ return parseInt( num, 10 ) } );

parseInt предполагает восьмеричное число только в том случае, если предоставленная строка начинается с символа 0.

Alnitak 04.11.2008 19:56

О, да ... верно. Он пытается «угадать» основание системы счисления на основе входных данных. Прости за это.

Peter Bailey 04.11.2008 19:59
Ответ принят как подходящий

Функция обратного вызова в Array.map имеет параметры три:

Из того же Страница Mozilla, с которым вы связались:

callback is invoked with three arguments: the value of the element, the index of the element, and the Array object being traversed."

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

В этом случае вы по очереди вызывали parseInt с основанием 0, 1 и 2. Первый - это то же самое, что и отсутствие параметра, поэтому он был задан по умолчанию на основе ввода (в данном случае с основанием 10). База 1 - это невозможная числовая база, а 3 - недопустимое число в базе 2:

parseInt('1', 0); // OK - gives 1
parseInt('2', 1); // FAIL - 1 isn't a legal radix
parseInt('3', 2); // FAIL - 3 isn't legal in base 2 

Итак, в этом случае вам понадобится функция-оболочка:

['1','2','3'].map(function(num) { return parseInt(num, 10); });

или с синтаксисом ES2015 +:

['1','2','3'].map(num => parseInt(num, 10));

(В обоих случаях лучше всего, чтобы явно предоставлял основание системы счисления для parseInt, как показано, потому что в противном случае он угадывает основание системы счисления на основе ввода. В некоторых старых браузерах начальный 0 заставлял его угадывать восьмеричное, что, как правило, было проблематичным. все равно угадайте шестнадцатеричный, если строка начинается с 0x.)

map передает второй аргумент, который (во многих случаях) портит параметр radix parseInt.

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

['10','1','100'].map(_.partial(parseInt, _, 10))

Или без подчеркивания:

['10','1','100'].map(function(x) { return parseInt(x, 10); });

другое (рабочее) быстрое исправление:

var parseInt10 = function(x){return parseInt(x, 10);}

['0', '1', '2', '10', '15', '57'].map(parseInt10);
//[0, 1, 2, 10, 15, 57]

Вы можете использовать стрелочную функцию ES2015 / ES6 и просто передать номер в parseInt. Значение по умолчанию для системы счисления будет 10.

[10, 20, 30].map(x => parseInt(x))

Или вы можете явно указать систему счисления для лучшей читаемости вашего кода.

[10, 20, 30].map(x => parseInt(x, 10))

В примере выше основание системы счисления явно установлено на 10

Вы можете решить эту проблему, используя Число в качестве функции итерации:

var a = ['0', '1', '2', '10', '15', '57'].map(Number);

console.info(a);

Без оператора new для преобразования типа можно использовать Number. Однако он отличается от parseInt: он не анализирует строку и возвращает NaN, если число не может быть преобразовано. Например:

console.info(parseInt("19asdf"));
console.info(Number("19asf"));

parseInt ИМХО следует избегать именно по этой причине. Вы можете обернуть его, чтобы сделать его более безопасным в следующих случаях:

const safe = {
  parseInt: (s, opt) => {
    const { radix = 10 } = opt ? opt : {};
    return parseInt(s, radix);
  }
}

console.info( ['1','2','3'].map(safe.parseInt) );
console.info(
  ['1', '10', '11'].map(e => safe.parseInt(e, { radix: 2 }))
);

lodash / fp ограничивает итерационные аргументы до 1 по умолчанию, чтобы избежать этих ошибок. Лично я нашел эти обходные пути, чтобы создавать столько ошибок, сколько их можно избежать. Внесение parseInt в черный список в пользу более безопасной реализации, на мой взгляд, является лучшим подходом.

Другие вопросы по теме