[javascript] parseInt가 Array # map으로 NaN을 생성하는 이유는 무엇입니까?

로부터 모질라 개발자 네트워크 :

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



답변

의 콜백 함수 Array.map에는 세 가지 매개 변수가 있습니다.

링크 한 동일한 Mozilla 페이지 에서 :

콜백은 요소의 값, 요소의 색인 및 순회되는 Array 객체의 세 가지 인수로 호출됩니다. “

따라서 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으로 인해 8 진을 추측하게되어 문제가있었습니다. 문자열이로 시작하면 16 진수를 추측하십시오 0x.)


답변

map는 많은 인수에서 parseInt기수 매개 변수를 엉망으로 만드는 두 번째 인수를 전달 합니다.

밑줄을 사용하는 경우 다음을 수행 할 수 있습니다.

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

또는 밑줄없이 :

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


답변

iteratee 함수로 Number 를 사용하여이 문제를 해결할 수 있습니다.

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

console.log(a);

새 연산자가 없으면 Number를 사용하여 유형 변환을 수행 할 수 있습니다. 그러나 parseInt와 다릅니다. 문자열을 구문 분석하지 않고 숫자를 변환 할 수없는 경우 NaN을 반환합니다. 예를 들어 :

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


답변

parseInt의 두 번째 매개 변수 인 기수와 관련하여 펑키 한 것입니다. 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 ) } );


답변

화살표 기능 ES2015 / ES6을 사용하고 숫자를 parseInt에 전달하면됩니다. 기수의 기본값은 10입니다.

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

또는 코드의 가독성을 높이기 위해 기수를 명시 적으로 지정할 수 있습니다.

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

위의 기수에서 명시 적으로 10으로 설정


답변

또 다른 (작동) 빠른 수정 :

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

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


답변

parseInt이러한 이유로 IMHO는 피해야합니다. 다음과 같은 상황에서 더 안전하게 만들기 위해 랩핑 할 수 있습니다.

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안전한 구현을 선호하는 블랙리스트 는 더 나은 접근 방식이라고 생각합니다.