(ES6) 숫자형 을 보고 이 글을 보는 걸 추천한다.
목차 Number 객체(Global 객체) ES5까지 Number 객체는 거의 래퍼 객체 의 역할만을 수행했다. 하지만 ES6에 들어서면서 다양한 프로퍼티와 메소드들이 생기면서 래퍼 객체 이상의 역할을 수행하는 전역 객체와 같이 쓸 수 있게 되었다. 래퍼 객체는 원시 타입의 값을 객체로 다루기 위한 객체이며, 래퍼 객체의 진가는 prototype 프로퍼티를 통해 드러나게 된다. 래퍼 객체를 어떻게 사용하는지는 나중에 보도록 하고, 일단 Number 객체의 구조를 보도록 하자.
Properties *
표시는 ES6에서 새로 추가됨.
표준 프로퍼티들은 상수이다. 즉 변경이 불가능하다.1 2 Number .EPSILON = "asdf" ; console .log (Number .EPSILON );
1 2 3 console .log (Number .POSITIVE_INFINITY === Infinity ); console .log (Number .NEGATIVE_INFINITY === -Infinity ); console .log (isNaN (Number .NaN ));
Problem in ES 부동 소수점에 대한 이해 수의 표현범위가 다른 int와 float, 그리고 신뢰할 수 없는 부동소수점 1 2 3 4 5 6 console .log (Number .MIN_VALUE ); console .log (Number .MIN_VALUE - 1 ); console .log (Number .MIN_VALUE + 1 ); console .log (Number .MAX_VALUE ); console .log (Number .MAX_VALUE + 1 ); console .log (Number .MAX_VALUE + 1 === Number .MAX_VALUE - 1 );
Solution in ES6 1 2 3 4 5 6 7 8 console .log (Number .MIN_SAFE_INTEGER ); console .log (-(Math .pow (2 , 53 ) - 1 )); console .log (Number .MIN_SAFE_INTEGER !== Number .MIN_SAFE_INTEGER + 1 ); console .log (Number .MIN_SAFE_INTEGER - 1 !== Number .MIN_SAFE_INTEGER - 2 ); console .log (Number .MAX_SAFE_INTEGER ); console .log (Math .pow (2 , 53 ) - 1 ); console .log (Number .MAX_SAFE_INTEGER !== Number .MAX_SAFE_INTEGER - 1 ); console .log (Number .MAX_SAFE_INTEGER + 1 === Number .MAX_SAFE_INTEGER + 2 );
Polyfill 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 if (!Number .MIN_SAFE_INTEGER ) { if (!Object .create ) { Number .MIN_SAFE_INTEGER = -(Math .pow (2 , 53 ) - 1 ); } else { Object .defineProperty (Number , "MIN_SAFE_INTEGER" , { value : -(Math .pow (2 , 53 ) - 1 ) }); } } if (!Number .MAX_SAFE_INTEGER ) { if (!Object .create ) { Number .MAX_SAFE_INTEGER = Math .pow (2 , 53 ) - 1 ; } else { Object .defineProperty (Number , "MAX_SAFE_INTEGER" , { value : Math .pow (2 , 53 ) - 1 }); } }
Problem in ES 1 2 console .log (.1 + .2 ); console .log (0.1 + 0.2 === 0.3 );
ES에서는 위와 같이 소수점 계산에서 고질적인 문제를 안고 있다. 이는 아마 IEEE에서 제정한 부동소수점 표현 형식인 IEE754의 고질적인 문제 라고 보여진다.실수 표현 문제 발생 이유 or 오차 발생 이유
자바스크립트의 숫자는 십진 부동 소수점 숫자로 접근하는데 반해 그 내부 동작 원리는 이진 부동 소수점 숫자이기 때문에 오차가 발생한다.원문 보기 JavaScript’s numbers are usually entered as decimal floating-point numbers, but they are internally represented as binary floating-point numbers. That leads to imprecision.
위와 같은 문제는 IEE754를 사용하는 Java에서도 동일하게 발생한다.1 2 3 4 5 6 public class test { public static void main (String[] args) { System.out.println(0.1 + 0.2 ); System.out.println(0.3 == 0.1 +0.2 ); } }
어찌보면 0.00000000000000004 정도의 오차는 무시되도 되는 작은 숫자이다.
Solution in ES6 Number.EPSILON은 오차없이 나타낼 수 있는 가장 작은 양의 소수를 나타낸다. 이렇게 무시되어도 될 정도의 작은 오차를 구분하기 위해 등장한 프로퍼티이다.1 2 3 4 5 6 console .log (5e2 ); console .log (5e-2 ); console .log (0.5e2 ); console .log (Number .EPSILON ); console .log (Number .EPSILON .toFixed (20 ));
과연 0.0000000000000004는 무시돼도 될 정도로 작은 오차인지 살펴보자.1 2 3 4 5 console .log (0.0000000000000004 < Number .EPSILON );
즉 좌변에 있는 값이 우변에 있는 Number.EPSILON 보다도 작다면 무시해도 되는 오차다.
Usage 1 2 3 4 5 6 7 const isEqual = (formula, result ) => Math .abs (formula - result) < Number .EPSILON ; console .log (isEqual (0.1 + 1 - 2.2 , -1.1 )); console .log (isEqual (0.1 + 1 - 2.2 , -1.2 ));
Polyfill 1 2 3 4 5 6 7 8 9 if (!Number .EPSILON ) { if (!Object .create ) { Number .EPSILON = 2.220446049250313e-16 ; } else { Object .defineProperty (Number , "EPSILON" , { value : 2.220446049250313e-16 }); } }
숫자가 상속받는 프로퍼티와 메소들을 정의해놓은 프로퍼티이다. 표준 메소드 및 프로퍼티가 미리 정의돼있으며, 사용자가 직접 정의하려면 아래와 같이 하면 된다.1 2 3 4 Number .prototype .lastNum = function ( ) { return this % 10 ; }; console .log (12.0 .lastNum ());
Methods *
표시는 ES6에서 새로 추가됨.
메소드는 수정 가능하다.1 2 Number .isFinite = () => "a" ;console .log (Number .isFinite (123 ));
in ES 1 2 3 4 5 6 7 8 9 10 11 console .log (isFinite (0 )); console .log (isFinite (255 )); console .log (isFinite (-254 )); console .log (isFinite ("1" )); console .log (isFinite (NaN )); console .log (isFinite (Infinity )); console .log (isFinite (-Infinity )); console .log (isFinite (null )); console .log (isFinite ({})); console .log (isFinite (undefined )); console .log (isFinite ([]));
in ES6 1 2 3 4 5 6 7 8 9 10 11 console .log (Number .isFinite (0 )); console .log (Number .isFinite (255 )); console .log (Number .isFinite (-254 )); console .log (Number .isFinite ("1" )); console .log (Number .isFinite (NaN )); console .log (Number .isFinite (Infinity )); console .log (Number .isFinite (-Infinity )); console .log (Number .isFinite (null )); console .log (Number .isFinite ({})); console .log (Number .isFinite (undefined )); console .log (Number .isFinite ([]));
Polyfill 1 2 3 Number .isFinite = Number .isFinite || function (value ) { return typeof value === "number" && isFinite (value); }
1 2 3 4 5 6 7 8 9 10 11 12 console .log (Number .isInteger (0 )); console .log (Number .isInteger (255 )); console .log (Number .isInteger (-254 )); console .log (Number .isInteger (1.1 )); console .log (Number .isInteger ("1" )); console .log (Number .isInteger (NaN )); console .log (Number .isInteger (Infinity )); console .log (Number .isInteger (-Infinity )); console .log (Number .isInteger (null )); console .log (Number .isInteger ({})); console .log (Number .isInteger (undefined )); console .log (Number .isInteger ([]));
Polyfill 1 2 3 4 5 Number .isInteger = Number .isInteger || function (value ) { return typeof value === "number" && isFinite (value) && Math .floor (value) === value; };
Problem 1 console .log (NaN === NaN );
in ES 1 2 3 4 5 6 7 8 9 10 11 12 console .log (isNaN (0 )); console .log (isNaN (-Infinity )); console .log (isNaN ("1.1" )); console .log (isNaN (NaN )); console .log (isNaN ("NaN" )); console .log (isNaN ("a" )); console .log (isNaN (0 / 0 )); console .log (isNaN ({})); console .log (isNaN ([])); console .log (isNaN (undefined )); console .log (isNaN (null )); console .log (isNaN (/a/ ));
in ES6 1 2 3 4 5 6 7 8 9 10 11 12 console .log (Number .isNaN (0 )); console .log (Number .isNaN (-Infinity )); console .log (Number .isNaN ("1.1" )); console .log (Number .isNaN (NaN )); console .log (Number .isNaN ("NaN" )); console .log (Number .isNaN ("a" )); console .log (Number .isNaN (0 / 0 )); console .log (Number .isNaN ({})); console .log (Number .isNaN ([])); console .log (Number .isNaN (undefined )); console .log (Number .isNaN (null )); console .log (Number .isNaN (/a/ ));
Polyfill 1 2 3 4 5 6 7 8 Number .isNaN = Number .isNaN || function (value ) { return typeof value === "number" && isNaN (value); }; Number .isNaN = Number .isNaN || function (value ) { return value !== value; };
1 2 3 4 5 6 7 8 console .log (Number .isSafeInteger (3 )); console .log (Number .isSafeInteger (Math .pow (2 , 53 ))); console .log (Number .isSafeInteger (Math .pow (2 , 53 ) - 1 )); console .log (Number .isSafeInteger (NaN )); console .log (Number .isSafeInteger (Infinity )); console .log (Number .isSafeInteger ("3" )); console .log (Number .isSafeInteger (3.1 )); console .log (Number .isSafeInteger (3.0 ));
Polyfill 1 2 3 Number .isSafeInteger = Number .isSafeInteger || function (value ) { return Number .isInteger (value) && Math .abs (value) <= Number .MAX_SAFE_INTEGER ; };
Syntax 1 Number .parseInt (string[, radix])
Parameters string: 문자열 radix: 2~36진수, 10이 기본값. Example 1 2 3 4 5 6 7 8 9 10 11 12 console .log (Number .parseInt === parseInt ); console .log (Number .parseInt ("11" )); console .log (Number .parseInt ("11.11" )); console .log (Number .parseInt ("11A" )); console .log (Number .parseInt ("A11" )); console .log (Number .parseInt ("11A1" )); console .log (Number .parseInt ("11.A" )); console .log (Number .parseInt ("011" )); console .log (Number .parseInt ("11 0" )); console .log (Number .parseInt ("0xFF" )); console .log (Number .parseInt (true )); console .log (Number .parseInt (new Date ()));
Problem 1 2 3 4 console .log (Number .parseInt ("0b111" )); console .log (Number .parseInt ("0b111" , 2 )); console .log (Number .parseInt ("0o10" )); console .log (Number .parseInt ("0o10" , 8 ));
Solution 1 2 3 4 5 6 7 8 console .log (Number .parseInt ("111" , 2 )); console .log (new Number ("0b111" ).valueOf ()); console .log (Number ("0b111" )); console .log (+"0b111" ); console .log (Number .parseInt ("10" , 8 )); console .log (new Number ("0o10" ).valueOf ()); console .log (Number ("0o10" )); console .log (+"0o10" );
Polyfill 1 Number .parseInt = Number .parseInt || parseInt ;
1 2 3 4 5 6 7 8 9 10 11 12 console .log (Number .parseFloat === parseFloat ); console .log (Number .parseFloat ("11" )); console .log (Number .parseFloat ("11.11" )); console .log (Number .parseFloat ("11A" )); console .log (Number .parseFloat ("A11" )); console .log (Number .parseFloat ("11A1" )); console .log (Number .parseFloat ("11.A" )); console .log (Number .parseFloat ("011" )); console .log (Number .parseFloat ("11 0" )); console .log (Number .parseFloat ("0xFF" )); console .log (Number .parseFloat (true )); console .log (Number .parseFloat (new Date ()));
Polyfill 1 Number .parseFloat = Number .parseFloat || parseFloat ;
실수를 반올림 할 때 쓰인다.1 2 3 4 5 6 const num = 123.45678 ;console .log (num.toFixed ()); console .log (num.toPrecision ()); console .log (num.toString ()); console .log (num.toFixed (4 )); console .log (num.toPrecision (4 ));
숫자를 지수를 통해 표현할 때 쓰인다.1 2 3 4 5 6 let num = 7817.1278 ;console .log (num.toExponential ()); console .log (num.toExponential (2 )); console .log (num.toExponential (6 )); num = 0.1445 ; console .log (num.toExponential ());
숫자를 문자열로 바꿀 때 쓰인다.1 2 3 4 5 6 7 console .log (1.1 .toString ()); console .log (1.0 .toString ()); console .log (0b11 .toString ()); console .log (NaN .toString ()); console .log (Infinity .toString ()); console .log (-Infinity .toString ()); console .log (0.0 .toString ());
숫자 객체의 인스턴스에서 숫자값을 얻어올 때 쓰인다.1 2 3 console .log (new Number (11 ).valueOf ()); console .log (new Number (0b11 ).valueOf ()); console .log (new Number ({}).valueOf ());
Syntax 1 Number .prototype .toLocaleString ([locales [, options]]);
Parameters localesBCP 47 language tag language[-script][-region]*(-variant)*(-extension)[-privateuse] “en-US”, “en-CA”, “tlh-Kore-AQ-fonipa”, “ja-JP”, “zh-Hans-CN”, etc.
Options style: “currency”, “percent”, “decimal”(default) currency: Current currency & funds code list “USD”, “EUR”, “KRW”, “JPY”, “CNY”, etc. etc options.
Checking for support 1 2 3 4 5 6 7 const isSupportToLocaleString = ( ) => !!(Intl && typeof Intl === "object" && typeof Intl .NumberFormat === "function" ); if (isSupportToLocaleString ()) { } else { }
Usage 1 2 3 4 5 6 7 8 const num = 123456.789 ;console .log (num.toLocaleString ("en-US" )); console .log (num.toLocaleString ("zh-Hans-CN-u-nu-hanidec" )); console .log (num.toLocaleString ("en-US" , {style : "currency" , currency : "USD" })); console .log (num.toLocaleString ("en-UK" , {style : "currency" , currency : "EUR" })); console .log (num.toLocaleString ("tlh-Kore-AQ-fonipa" , {style : "currency" , currency : "KRW" })); console .log (num.toLocaleString ("ja-JP" , {style : "currency" , currency : "JPY" })); console .log (num.toLocaleString ("zh-Hans-CN" , {style : "currency" , currency : "CNY" }));
Number 함수 함수 Syntax Parameter value: 어떠한 데이터 타입의 값도 올 수 있다.
Usage 매개변수로 넘긴 값들을 숫자로 바꿀 때 사용한다.
Example 1 2 3 4 5 6 7 8 9 10 11 12 console .log (Number ("11" )); console .log (Number ("11.11" )); console .log (Number ("11A" )); console .log (Number ("A11" )); console .log (Number ("11A1" )); console .log (Number ("11.A" )); console .log (Number ("011" )); console .log (Number (true )); console .log (Number (new Date ())); console .log (Number ([0 , 1 ])); console .log (Number ({a : "b" })); console .log (Number (11 ));
생성자 Syntax Parameter value: 어떠한 데이터 타입의 값도 올 수 있다.
Structure 1 2 3 const objNum = new Number (11 );console .log (typeof objNum); console .dir (objNum);
__proto__ 1 2 const objNum = new Number (11 );console .log (Number .prototype === objNum.__proto__ );
숫자의 래퍼 객체(Number)에서 미리 정의해놓은 프로퍼티(prototype)이다. 이 프로퍼티에는 숫자의 표준 메소드와 프로퍼티가 정의돼있다. 숫자 객체의 인스턴스(new Number())는 숫자 래퍼 객체(Number)로부터 prototype 프로퍼티를 __proto__라는 이름으로 상속받는다.
Necessity The Secret Life of JavaScript Primitives ES에서 숫자 원시값의 프로퍼티와 메소드를 사용할 때 내부 동작 원리는 아래와 같다.1 2 3 4 5 6 7 8 9 11.1 .toString (); new Number (11.1 ).toString ();
Number ↔ String 1 2 3 4 5 6 const num1 = "10" ;const num2 = "10" ;const sum = num1 + num2; const sub = num1 - num2; const mul = num1 * num2; const div = num1 / num2;
String to Number Number.parseInt(string[, radix]) Number.parseFloat(string) new Number(string).valueOf() Number() +string, 1*string Number.parseInt(str[, radix]) 1 2 3 4 5 6 7 8 9 10 console .log (Number .parseInt ("11" )); console .log (Number .parseInt ("11.11" )); console .log (Number .parseInt ("11A" )); console .log (Number .parseInt ("A11" )); console .log (Number .parseInt ("11A1" )); console .log (Number .parseInt ("11.A" )); console .log (Number .parseInt ("011" )); console .log (Number .parseInt ("11 0" )); console .log (Number .parseInt ("0b11" )); console .log (Number .parseInt ("0o11" ));
Number.parseFloat(str) 1 2 3 4 5 6 7 8 9 10 console .log (Number .parseFloat ("11" )); console .log (Number .parseFloat ("11.11" )); console .log (Number .parseFloat ("11A" )); console .log (Number .parseFloat ("A11" )); console .log (Number .parseFloat ("11A1" )); console .log (Number .parseFloat ("11.A" )); console .log (Number .parseFloat ("011" )); console .log (Number .parseFloat ("11 0" )); console .log (Number .parseFloat ("0b11" )); console .log (Number .parseFloat ("0o11" ));
new Number(string).valueOf() 1 2 3 4 5 6 7 8 9 10 console .log (new Number ("11" ).valueOf ()); console .log (new Number ("11.11" ).valueOf ()); console .log (new Number ("11A" ).valueOf ()); console .log (new Number ("A11" ).valueOf ()); console .log (new Number ("11A1" ).valueOf ()); console .log (new Number ("11.A" ).valueOf ()); console .log (new Number ("011" ).valueOf ()); console .log (new Number ("11 0" ).valueOf ()); console .log (new Number ("0b11" ).valueOf ()); console .log (new Number ("0o11" ).valueOf ());
Number(string) 1 2 3 4 5 6 7 8 9 console .log (Number ("11" )); console .log (Number ("11.11" )); console .log (Number ("11A" )); console .log (Number ("A11" )); console .log (Number ("11A1" )); console .log (Number ("11.A" )); console .log (Number ("011" )); console .log (Number ("0b11" )); console .log (Number ("0o11" ));
+string, 1*string 1 2 3 4 5 6 7 8 9 console .log (+"11" ); console .log (+"11.11" ); console .log (+"11A" ); console .log (+"A11" ); console .log (+"11A1" ); console .log (+"11.A" ); console .log (+"011" ); console .log (+"0b11" ); console .log (+"0o11" );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 const iterations = 10000000 ;console .time ("Number.parseInt()" );for (let i=0 ; i<iterations; i++){ Number .parseInt ("1.1" ); } console .timeEnd ("Number.parseInt()" );console .time ("Number.parseInt() with radix" );for (let i=0 ; i<iterations; i++){ Number .parseInt ("1.1" , 10 ); } console .timeEnd ("Number.parseInt() with radix" );console .time ("Number.parseFloat()" );for (let i=0 ; i<iterations; i++){ Number .parseFloat ("1.1" ); } console .timeEnd ("Number.parseFloat()" );console .time ("new Number().valueOf()" );for (let i=0 ; i<iterations; i++){ new Number ("1.1" ).valueOf (); } console .timeEnd ("new Number().valueOf()" );console .time ("Number()" );for (let i=0 ; i<iterations; i++){ Number ("1.1" ); } console .timeEnd ("Number()" );console .time ("+string" );for (let i=0 ; i<iterations; i++){ +"1.1" ; } console .timeEnd ("+string" );console .time ("1*string" );for (let i=0 ; i<iterations; i++){ 1 *"1.1" ; } console .timeEnd ("1*string" );
Number to String Number.prototype.toString() String(number) “” + number Number.prototype.toString() 1 2 3 4 5 6 7 console .log (1.1 .toString ()); console .log (1.0 .toString ()); console .log (0b11 .toString ()); console .log (NaN .toString ()); console .log (Infinity .toString ()); console .log (-Infinity .toString ()); console .log (0.0 .toString ());
String(number) 1 2 3 4 5 6 7 console .log (String (1.1 )); console .log (String (1 )); console .log (String (0b11 )); console .log (String (NaN )); console .log (String (Infinity )); console .log (String (-Infinity )); console .log (String (0 ));
“” + number 1 2 3 4 5 6 7 console .log ("" + 1.1 ); console .log ("" + 1 ); console .log ("" + 0b11 ); console .log ("" + NaN ); console .log ("" + Infinity ); console .log ("" + -Infinity ); console .log ("" + 0 );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const iterations = 10000000 ;console .time ("Number.prototype.toString()" );for (let i=0 ; i<iterations; i++){ 1.1 .toString (); } console .timeEnd ("Number.prototype.toString()" );console .time ("String(number)" );for (let i=0 ; i<iterations; i++){ String (1.1 ); } console .timeEnd ("String(number)" );console .time ("\"\" + number" );for (let i=0 ; i<iterations; i++){ "" + 1.1 ; } console .timeEnd ("\"\" + number" );