[JS] #6 빌트인 Number, String

simoniful·2021년 4월 28일
0

ES6 JS - Basic

목록 보기
6/18
post-thumbnail

Number

JS 엔진에서 숫자(IEEE-754)

  • 자바스크립트는 IEEE-754에 정의된 64비트 배정도(double precision) 실수형 표현 방법을 사용하여 부동 소수점으로 수를 처리합니다.
  • 64비트로 최소값과 최대값을 처리합니다.
  • 정수와 실수를 구분하지 않습니다.(1은 1.0으로 처리하고, 1과 1.2간 연산이 가능합니다)

부동소수점 방식

  • 실수를 컴퓨터상에서 근사하여 표현할 때 소수점 위치를 고정하지 않고 그 위치를 나타내는 수를 따로 적는 것 입니다.

  • 유효숫자를 나타내는 가수(假數)와 소수점의 위치를 풀이하는 지수(指數)로 나누어 표현한다.

  • 지수(Exponent)는 소수점 자리수를 계산을 위한 것, 가수부(Mantissa)는 실제 값을 나태내는 부분이라고 이해하면 된다.

64비트 구성

  • 사인(부호) 비트
    63: 1비트, 값이 0이면 양수, 1이면 음수
  • 지수(exponent)
    52~ 62: 11비트
  • 가수(fraction)
    0~51: 52비트 + 1(사인 비트): 53비트

값을 구하는 방법

Number(7).toString(2);
// "111"

비트 값은 0 아니면 1입니다. 2^n승 값을 더해 값을 구합니다. 예를 들면 정수 7은 0비트 부터 1, 1, 1로 1(2^0) + 2(2^1) + 4 = 7 입니다.

Number상수

  • safe integer란 지수(e)를 사용하지 않고 나타낼 수 있는 값으로 위 표를 보면 2의 64승이 아닌 2의 53승입니다.
  • Number.MAX_SAFE_INTEGER: safe integer 최대값
  • Number.MIN_SAFE_INTEGER: safe integer 최소값
    console.log(Number.MAX_SAFE_INTEGER);
    console.log(Math.pow(2,53)-1);
    console.log(Number.MIN_SAFE_INTEGER);
    console.log(-(Math.pow(2,53)-1));
    // 9007199254740991
    // 9007199254740991
    // -9007199254740991
    // -9007199254740991

진수, EPSILON

Number.EPSILON

  • 2.2204460492503130808472633361816E-16
  • 혹은 2^-52승으로 아주 작은 값을 나타냅니다.

사용 사례

  • 미세한 값 차이 형태

    const total = 0.1 + 0.2;
    console.log(total);
    console.log(total === 0.3);
    // 0.30000000000000004
    // false

    ⇒ 0.3이 나올것 같지만 실제로 출력해보면 0.30000000000000004이 출력하기에 false판정입니다. 이는 JS가 부동 소수점 처리를 하기 때문(IEEE-754 준수)인데 이처럼 미세한 값 차이로 일치하지 않을 때 EPSILONE을 사용합니다.

  • 미세한 값 차이를 같은 값으로 간주

    const value = Math.abs(0.1 + 0.2 - 0.3);
    console.log(value < Number.EPSILON);
    // true

    ⇒ 값 차이가 EPSILON 보다 작은 경우 이 값을 무시하고, 근사값으로 간주합니다.

  • 0/0으로 NaN가 되는 것을 방지

    console.log(0 / 0); 
    const value = 0 / (0 + Number.EPSILON);
    console.log(value);
    // NAN
    // 0

    ⇒ 0 / 0은 NaN이지만 0 + Number.EPSILON처럼 작은 값을 더해 나누면 0이되서 그 뒤 연산을 이어서 할 수 있습니다.

진수

  • Binary (2진수)
    • 0b0101, 0B0101 형태로 작성합니다.
    • 숫자 0 다음에 b/B작성 후 나머지 값들 작성
      const value = 0B111;
      console.log(value);
      // 7
  • Octal (8진수)
    • 0O0105 형태로 작성합니다.
    • 숫자 0 다음에 영문 o/O작성 후 이어서 0~7작성
    • ES3는 첫 자리에 영문 o/O작성
      const value = 0o111;
      console.log(value);
      // 73

Number 함수

isNaN()

Number.isNaN(value)

주어진 값의 유형이 Number이고 NaN이면 true 아니면 false를 반환합니다.글로벌 오브젝트의 isNaN()와 비교했을 때 형변환, 데이터 타입 확인에서 차이가 있습니다.

console.log(Number.isNaN("ABC"), isNaN("DEF")); //false true  ---(1)
console.log(Number.isNaN(NaN), isNaN(NaN));     //true true   ---(2)
console.log(Number.isNaN(0 / 0), isNaN(0 / 0)); //true true   ---(3)
console.log(Number.isNaN("100"), isNaN("200")); //false false ---(4)
  • (1): 글로벌 오브젝트의 isNaN()는 "DEF" 값 타입이 Number가 아닌 것을 체크합니다. "DEF"가 String 타입이기에 true가 반환됩니다.
    Number.isNaN("ABC")는 값이 NaN인 것을 체크합니다. 아니기에 false가 반환됩니다.
  • (2): 값이 NaN이므로 true가 반환됩니다.
  • (3): 0/0은 값이 NaN이므로 true가 반환됩니다.
  • (4): 글로벌 오브젝트의 isNaN()은 "200" 값을 숫자로 변환 후 그 결과로 비교합니다.
    Number.isNaN("100")는 값이 NaN인 것을 체크합니다. 아니기에 false가 반환됩니다.
  • NaN체크 방법
    • NaN === NaN 결과가 false이므로 사용 불가
    • isNaN(), 글로벌 오브젝트
    • Number.isNaN()
    • Object.is(NaN,NaN):true

isInteger()

Number.isInteger(value)

파라미터 값으로 받은 value가 정수인지 확인하려는 값으로 반환 타입은 Boolean입니다. 파라미터 값이 정수이면 true아니면 false를 반환합니다.

  • 정수로 인식
    console.log(Number.isInteger(0));
    console.log(Number.isInteger(1.0));
    console.log(Number.isInteger(1.01));
    // true
    // true
    // false

    ⇒ 1.0은 정수이고 1.01은 소수입니다.

  • 정수가 아닌 것으로 인식
    console.log(Number.isInteger("12"));
    console.log(Number.isInteger(true));
    // false
    // false

    ⇒ "12"는 숫자로 변환하면 Number가 맞지만 Number.isIteger()는 치환하지 않고 값 그대로 판단하기에 false가 반환됩니다.

isSafeInteger()

Number.isSafeInteger(testValue)

파라미터인 testValue가 안전한 정수인지 확인하며 Boolean타입으로 반환합니다. 파라미터 값이 safe 정수, 즉 -(2의 53승 -1) ~ (2의 53승 -1) 사이이면 true, 아니면 false를 반환합니다.

  • true로 인식하는 경우
    const isSafe = Number.isSafeInteger;
    console.log(isSafe(7.0));
    console.log(isSafe(Number.MAX_SAFE_INTEGER));
    console.log(isSafe(Number.MIN_SAFE_INTEGER));
    // true
    // true
    // true

    ⇒ 7.0은 정수이며, 값 범위에 속하므로 true

  • false로 인식하는 경우
    const isSafe = Number.isSafeInteger;
    console.log(isSafe(7.1));
    console.log(isSafe("100"));
    console.log(isSafe(NaN));
    console.log(isSafe(Infinity));
    // false
    // false
    // false
    // false

    ⇒ 7.1은 정수가 아닙니다.
    ⇒ 값을 Number로 변환하여 체크하지 않습니다.

isFinite()

isFinite(testValue)

파라미터 값이 유한한지 확인하는 함수로 유한 값이면true 아니면 false를 반환합니다. 데이터 타입을 변환하여 판단하는 글로벌 오브젝트의 isFinite()와 결과가 다릅니다.

const num = Number.isFinite, global = isFinite;
console.log(num(100), global(200));
console.log(num("70"), global("80"));
console.log(num(true), global(true));
console.log(num(NaN), global(NaN));
console.log(num(undefined), global(undefined));
// true true
// false true
// false true
// false false
// false false

함수는 오브젝트에 속해야 하므로 Number와 관련된 것은 Number 오브젝트의 함수를 사용하고 글로벌 오브젝트의 함수는 글로벌 사용이 목적입니다.


String

Unicode, ES5호환성

Unicode

  • 유니코드는 U+0031형태입니다.

  • 코드 포인트(code point)

    • 0031이 코드포인트이고 문자 코드라고도 부릅니다.
    • 코드 포인트로 문자/이모지 등을 표현합니다.
    • 4자리 이상의 UTF-16진수 형태입니다.
  • 110만개 정도가 표현 가능합니다.

    • U+0000 ~ U+10FFFF
  • 평면(plane)

    • 유니코드는 코드포인트 범위를 17개의 평면들로 나누어 정리해 두었습니다.
    • 각각의 평면들은 약 6만 5천자로 이루어집니다.
    • 첫 번째 plane
      • BMP(Basic Multillingual Plane)라고 부릅니다.
      • 일반적인 문자(영문자, 숫자)가 여기에 속합니다.
      • 한글의 코드 포인트도 여기에 속합니다.
    • 첫 번째 plane을 제외한 plane
      • Supplementary plane, Astral plane이라고 부릅니다.
      • 5자리 이상의 코드 포인트를 표현할 수 있습니다.
      • ES6+ 에서 지원합니다.

Escape Sequence

  • 이스케이프 시퀀스(Escape Sequence)

    const escape = "\x31\x32\x33";
    console.log(escape);
    console.log("\\");
    // 123
    // \
    • 역슬래시와 16진수로 값을 작성합니다.
    • 이를 16진수 이스케이프 시퀀스라 부릅니다.
      ⇒ 역슬래시가 에디터에 "\" 형태로 표시됩니다.
      ⇒ x를 소문자로 작성하며 역슬래시를 한 번 더 쓰면 escape문법이되어 역슬래시 표현이 가능합니다.
  • 유니코드 이스케이프 시퀀스(Unicode Escape Sequence)

    const escape = "\x31\x32\x33";
    console.log(escape);
    const unicode = "\u0034\u0035\u0036";
    console.log(unicode);
    // 123
    // 456
    • 이스케이프 시퀀스를 유니코드로 작성한 형태입니다.
    • UTF-16진수로 U+0000에서 U+FFFF까지 사용 가능합니다

ES5 호환성

const unicode = "\u0034\u0035\u0036";
console.log(unicode);
const es6 = "\u{34}\u{35}\u{36}";
console.log(es6);
console.log("\u{1f418}");
// 456
// 456
// 🐘
  • ES5 문제점
    • U+FFFF보다 큰 코드를 어떻게 작성할 것인가?
    • 유니코드 코드 포인트 이스케이프
      • 코드 포인트 값에 관계없이 사용할 수 있는 형태가 필요합니다.
      • \u{31}, \u{1f418}형태
  • 호환성 대책
    const pair = "\uD83D\uDC18";
    console.log(pair);
    // 🐘
    • Surrogate pair
      • \u{1f418}형태를 ES5에서 사용 불가
      • ES5에서는 두 개의 유니코드 이스케이프 시퀀스를 연결하여 사용합니다. 이를 Surrogate pair라고 합니다.
    • Surrogate pair 계산 방법
    • 유니코드 사용의 참조 사항

Unicode 함수

fromCodePoint()

String.fromCodePoint(num1[, ...[, numN]])

유니코드의 코드 포인트에 해당하는 문자를 반환하는 함수

  • 파라미터: 코드 포인트, num1[,...[,numN]]
  • 반환: 코드 포인트에 해당하는 문자로 변환하여 반환

  • 파라미터에 다수의 코드 포인트 작성이 가능합니다.
    const point = String.fromCodePoint;
    console.log(point(49, 50, 51));
    console.log(point(44032, 44033));
    console.log(point(0x31, 0x32, 0x33));
    console.log(point(0x1F418));
    // 123
    // 가각
    // 123
    // 🐘

    ⇒ 문자를 연결하여 반환
    ⇒ 49, 50, 51은 코드 포인트를 10진수로 작성한 형태
    ⇒ 0x31, 0x32, 0x33은 코드 포인트를 16진수로 작성한 형태

  • ES5의 fromCharCode()사용
    console.log(String.fromCharCode(0x1f418));
    console.log(String.fromCharCode(0xD83D, 0xDC18));
    // 
    // 🐘

    ⇒ 0x1f418(아스트랄 코드포인트)를 지원하지 않아 제대로 출력이 안됩니다.
    ⇒ Surrogate pair로 작성

codePointAt()

String.prototype.codePointAt()

대상 문자열에서 파라미터에 작성한 인덱스 번째 문자를 유니코드 코드포인트로 변환하여 반환합니다.

  • 파라미터: 유니코드로 변환할 문자열의 인덱스
  • 반환: 코드 포인트 값

  • 인덱스 번째 문자를 유니코드 코드포인트로 반환
  • 코드 포인트는 UTF-16으로 인코딩된 값
const result = "가나다".codePointAt(2);
console.log(result);
console.log(typeof result);
console.log("가나다".codePointAt(3));
console.log(String.fromCodePoint(result));
// 45796
// number
// undefined
// 다
  1. const result = "가나다".codePointAt(2);
    • 문자열 "가나다"에서 3번째의 코드포인트를 구해 반환합니다.
    • 반환된 코드 포인트 타입은 number입니다.
  2. 인덱스 번째에 문자가 없으면 undefined를 반환합니다.
  3. codePointAt(2)의 값은 45796이고 fromCodePoint(45796)의 값은 "다"입니다.

Q. String.fromCodePoint(50)와 "123".codePointAt(1)의 형태가 다른데 그 이유는 무엇일까요?

  • String.fromCodePoint(50)은 직접 호출하는 함수의 형태로 다수의 파라미터를 작성합니다

  • "123".codePointAt(1)은 String.prototype.codePointAt() 호출, prototype을 사용한 메소드 형태로 파라미터에 인덱스 하나만 작성합니다.

  • codePointAt()은 값을 구하는 대상이 있지만, fromCodePoint()은 대상이 없습니다.

  • 이는 유니코드와 문자열을 서로 인코딩과 디코딩을 하기위한 목적으로 설계되었다고 생각하였습니다.

  • fromCodePoint()은 String 빌트인에서 직접 호출하여 사용하는 함수 형태입니다. 이는 파라미터에 작성한 유니코드 값을 문자열로 변환하는 것에 초점이 맞추어져 있으며, 즉 디코딩의 목적으로 사용하라는 의미 같습니다.

  • fromCodePoint( )은 다수의 파라미터를 작성합니다. [50, 60, 70].fromCodePoint() 형태로 작성하면, 빌트인 String 오브젝트가 아니라 빌트인 Array 오브젝트에 fromCodePoint()가 있어야 하는데, 이것은 문자열 처리 시맨틱이 Array 처리 시맨틱으로 바뀌게 됩니다.
    이를 방지하기 위해 "506070".fromCodePoint() 형태로 작성하면 값을 구분할 수 없습니다.

  • codePointAt()은 생성한 String 오브젝트에 대하여 프로토 타입에 내장된 메소드를 사용하는 형태입니다. 생성한 오브젝트에 초점이 맞추어져 있으며, 즉 인코딩의 목적으로 사용하라는 의미 같습니다.

normalize()

String.prototype.normalize()

대상 문자열을 파라미터에 지정한 유니코드 정규화 형식으로 변환 및 반환하는 함수입니다.

  • 파라미터: 정규화 형식. 디폴트: NFC

  • 반환: 변환된 문자열

  • 문자열을 지정한 유니코드 정규화 형식으로 변환

    console.log("ㄱ".codePointAt().toString(16));
    console.log("ㅏ".codePointAt().toString(16));
    console.log("\u{3131}\u{314F}");
    const point = "\u{3131}\u{314F}";
    console.log(point.normalize("NFC"));
    console.log(point.normalize("NFD"));
    console.log(point.normalize("NFKD"));
    console.log(point.normalize("NFKC"));
    // 3131
    // 314f
    // ㄱㅏ
    // ㄱㅏ
    // 가
    // 가

    ⇒ ㄱ과 ㅏ 의 코드 포인트를 16진수로 구합니다.
    ⇒ ㄱ과 ㅏ의 코드 포인트를 연결하여 작성합니다.
    ⇒ "ㄱㅏ"로 표시되지만 제대로 연결이 되진 않았습니다.
    ⇒ NFC와 NFD는 단지 연결하여 어색하지만 NFKD와 NFKC는 모아 쓴형태로 표시됩니다.

  • 유니코드 정규화 형식


시작/끝복제

startsWith()

String.prototype.startsWith()

대상 문자열이 첫 번째 파라미터의 문자열로 시작하면 true 아니면 false를 반환합니다.

  • 파라미터: 비교문자열, 비교 시작 인덱스(default: 0)
  • 반환: 시작하면 true 아니면 false

  • 대상 문자열이 첫 파라미터의 문자열로 시작 여부 확인
  • startsWith()는 정규 표현식 사용이 불가능
    const target = "ABC";
    console.log(target.startsWith("AB"));
    console.log(target.startsWith("BC"));
    console.log(/^AB/.test(target));
    // true
    // false
    // undefined

    ⇒ "AB"로 시작하기에 true를 반환하고 "BC"는 있지만 시작점이 아니기에 false를 반환합니다.

  • 두 번째 파라미터는 Optional 하며 비교 시작 인덱스를 작성합니다.
    const target = "ABC";
    console.log(target.startsWith("BC", 1));
    // true

    ⇒ BC는 중간에 있지만 시작 인덱스가 1이므로 true를 반환합니다.

endsWith()

String.prototype.endsWith()

대상 문자열이 첫 번째 파라미터의 문자열로 끝나면 true, 아니면 false를 반환합니다.

  • 파라미터: 비교 문자열, 사용 문자열 길이(default: 전체)

  • 반환: 끝나면 true, 아니면 false

  • 대상 문자열이 첫 파라미터의 문자열로 끝나는지 여부 확인

  • endsWith()는 정규 표현식 사용이 불가능

    const target = "ABC";
    console.log(target.endsWith("BC"));
    console.log(target.endsWith("AB"));
    console.log(/BC$/.test(target);
    // true
    // false
    // true
  • 두 번째 파라미터는 선택이며 사용할 문자열 길이를 지정합니다.

    const target = "ABC";
    console.log(target.endsWith("AB", 2));
    // true

repeat()

String.prototype.repeat()

대상 문자열을 파라미터에 작성한 수만큼 복제, 연결하여 반환합니다

  • 파라미터: 복제할 수(default: 0)
  • 반환: 복제하여 만든 문자열

대상 문자열을 작성한 수만큼 복제, 연결

const target = "ABC";
console.log(target.repeat(3));
console.log(target.repeat(0));
console.log(target.repeat());
console.log(target.repeat(2.7));
// ABCABCABC
// ""
// "" 
// ABCABC

⇒ repeat(3): ABC를 3번 복제하고 연결하여 반환합니다.
⇒ 파라미터를 작성하지 않거나 0을 작성하면 빈 문자열을 반환합니다.
⇒ 2.7에서 0.7을 무시하고 2를 사용합니다.

includes()

대상 문자열에 첫 번째 파라미터의 문자열이 있으면 true없으면 false를 반환.

  • 파라미터: 존재 여부 비교 문자열, 비교 시작 인덱스(default: 0)

  • 반환: 존재하면 true, 아니면 false

  • 대상 문자열에 첫 파라미터의 문자열 존재 여부

  • 첫 번째 파라미터가 숫자면 문자열로 변환하여 체크합니다.

    const target = "123";
    console.log(target.includes("1"));
    console.log(target.includes(12));
    console.log(target.includes("13"));
    // true
    // true
    // false
  • 두 번째 파라미터를 작성하면 비교 시작 인덱스

  • includes()는 정규 표현식 사용이 불가능

    const target = "ABC";
    console.log(target.includes("A", 1));
    try{
    	result = target.includes(/^A/);
    } catch(e){
    	console.log("정규표현식 사용 불가");
    }
    // false
    // 정규표현식 사용 불가

길이 늘리기, 공백 삭제

padStart()

String.prototype.padStart()

첫 번째 파라미터 값 만큼 길이를 늘리고 늘어난 끝에 대상 문자열을 설정한 후, 앞의 남은 공간에 두 번째 파라미터를 채웁니다.

  • 파라미터: 늘릴 길이 값, 설정할 값(Optional)

  • 반환: 길이를 늘리고 문자열을 채운 결과

  • 두 번째 파라미터에 채울 문자열 작성

    console.log("ABC".padStart(10, "123"));
    console.log("ABC".padStart(6, "123456"));
    console.log("ABCDE".padStart(3, "123"));
    console.log("ABC".padStart(6).length);
    // 1231231ABC
    // 123ABC
    // ABCDE
    // 6
    1. console.log("ABC".padStart(10, "123"));
      • "ABC"를 10자리로 늘린 뒤 마지막 8,9,10 번째에 "ABC"설정, 이 후 남은 자리를 "123"으로 차례대로 채웁니다.
    2. console.log("ABC".padStart(6, "123456"));
      • 6자리 끝에 ABC를 설정후 남은 3자리에 왼쪽부터 차례대로 채웁니다.
    3. console.log("ABCDE".padStart(3, "123"));
      • 전체 길이가 대상 문자열보다 작을 경우 길이를 줄이지 않고 대상 문자열을 반환합니다.
    4. console.log("ABC".padStart(6).length);
      • 두 번째 파라미터를 작성하지 않으면 남은 앞에 빈 문자열을 채웁니다.

padEnd()

String.prototype.padEnd()

첫 번째 파라미터 값만큼 길이를 늘리고 늘어난 앞에 대상 문자열을 설정한 후, 뒤의 남은 공간에 두 번째 파라미터를 채웁니다.

  • 파라미터: 늘릴 길이 값, 설정할 값(Optional)

  • 반환: 길이를 늘리고 문자열을 채운 결과

  • 두 번째 파라미터에 채울 문자열 작성

    console.log("ABC".padEnd(10, "123"));
    console.log("ABC".padEnd(6, "123456"));
    console.log("ABCDE".padEnd(3, "123"));
    console.log("ABC".padEnd(6).length);
    // ABC1231231
    // ABC123
    // ABCDE
    // 6
    1. console.log("ABC".padEnd(10, "123"));
      • "ABC"를 10자리로 늘린 뒤 1,2,3 번째에 "ABC"설정, 이 후 남은 자리를 "123"으로 차례대로 채웁니다.
    2. console.log("ABC".padEnd(6, "123456"));
      • 6자리 앞에 ABC를 설정 후 남은 3자리에 왼쪽부터 차례대로 채웁니다.
    3. console.log("ABCDE".padEnd(3, "123"));
      • 전체 길이가 대상 문자열보다 작을 경우 길이를 줄이지 않고 대상 문자열을 반환합니다.
    4. console.log("ABC".padEnd(6).length);
      • 두 번째 파라미터를 작성하지 않으면 남은 앞에 빈 문자열을 채웁니다.

trimStart()

String.prototype.trimStart()

문자열 앞의 공백 삭제

  • 파라미터: 없음
  • 반환: 삭제한 결과

  • 앞의 공백 삭제
    const value = "  123";
    console.log(value.length);
    console.log(value.trimStart().length);
    const split = "a, b, c".split(",");
    for(let value of split) {
      console.log(`${value}, ${value.length}`);
      console.log(value.trimStart().length);
    };
    // 5
    // 3
    // a, 1
    // 1
    //  b, 2
    // 1
    //  c, 2
    // 1

trimStart()

String.prototype.trimEnd()

문자열 끝의 공백 삭제

  • 파라미터: 없음
  • 반환: 삭제한 결과

  • 끝의 공백 삭제
    const value = "123  ";
    console.log(value.length);
    console.log(value.trimStart().length);
    // 5
    // 3
profile
소신있게 정진합니다.

0개의 댓글