parseIntがArray#mapでNaNを生成するのはなぜですか?


291

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]

15
レイジーの場合:.map(parseFloat)1つのパラメーターしかとらないため、使用してください。

63
またはを使用します.map(Number)
ニコライ

2
手巻きの関数のない整数が必要な場合は、arr.map(Math.floor)を使用できます。
dandavis 2014年

@ニコライuser669677素晴らしい提案!私はそれをアンサーで賛成します
BiAiB

parseIntが最初の数値を正しく解析し、最初のインデックス以外でエラーを
起こす

回答:


478

のコールバック関数にArray.map3つのパラメーターがあります。

リンクした同じMozillaページから:

コールバックは3つの引数で呼び出されます:要素の値、要素のインデックス、およびトラバースされるArrayオブジェクト。

したがって、parseInt実際に2つの引数が必要な関数を呼び出す場合、2番目の引数は要素のインデックスになります。

この場合、parseInt基数0、1、2を順番に呼び出してしまいました。1つ目は、パラメーターを指定しない場合と同じであるため、入力に基づいてデフォルト設定されます(この場合は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が8進数を推測し、問題が発生する傾向がありました。文字列がで始まる場合は16進数を推測し0xます。)


25

map(多くの場合)parseIntの基数パラメータをめちゃくちゃにしている2番目の引数に沿って渡しています。

アンダースコアを使用している場合は、次のことができます。

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

またはアンダースコアなし:

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


18

この問題は、Numberをiteratee関数として使用して解決できます。

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

console.log(a);

新しい演算子がなければ、Numberを使用して型変換を実行できます。ただし、parseIntとは異なります。文字列を解析せず、数値を変換できない場合はNaNを返します。例えば:

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


11

私はそれがparseIntの2番目のパラメーターである基数で起こっているファンキーなものであることを賭けます。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 ) } );

1
parseIntは、指定された文字列が0文字で始まる場合にのみ8進数と見なします。
Alnitak

そうだね…そうだ。入力に基づいて基数を「推測」しようとします。申し訳ありません。
Peter Bailey、

3

矢印関数ES2015 / ES6を使用して、数値をparseIntに渡すだけです。基数のデフォルト値は10になります

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

または、コードを読みやすくするために基数を明示的に指定できます。

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

上記の例では、基数は明示的に10に設定されています


1

別の(有効な)クイックフィックス:

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

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

0

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 }))
);

lodash / fpは、これらの問題を回避するために、デフォルトで引数を1に繰り返します。個人的に私はこれらの回避策が回避するバグをできるだけ多く作成することを発見しました。parseInt安全な実装を支持してブラックリストに登録することは、より良いアプローチだと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.