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

В Mozilla Developer Network:

[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]

Ответ 1

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

На той же странице Mozilla, с которой вы связались:

callback вызывается с тремя аргументами: значением элемента, индексом элемента и объектом Array. "

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

В этом случае вы в конечном итоге вызываете parseInt с помощью radix 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));

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

Ответ 2

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

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

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

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

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

Ответ 3

Я собираюсь сделать ставку на то, что это что-то фанковое происходит с параметром parseInt 2nd, 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 ) } );

Ответ 4

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

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

console.log(a);

Ответ 5

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

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

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

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

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

Ответ 6

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

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

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

Ответ 7

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

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

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