본문 바로가기
책/javascript & typescript

YOU DON'T KNOW JS 타입과 문법, 스코프와 클로저 1부

by 밤톨엽 2023. 1. 30.

개요

YOU DON'T KNOW JS 타입과 문법, 스코프와 클로저 책을 읽고 정리하게 되었다.
개인적으로 자바스크립트에 대한 사용법과 어느 정도 경험을 해본 사람들이 읽으면 좋은 책으로 느껴졌다.


목차

CHAPTER 1 타입

  • 1.1 타입, 그 실체를 이해하자
  • 1.2 내장 타입
  • 1.3 값은 타입을 가진다
    • 1.3.1 값이 없는 vs 선언되지 않은
    • 1.3.2 선언되지 않은 변수
  • 1.4 정리하기

CHAPTER2 값

  • 2.1 배열
    • 2.1.1 유사 배열
  • 2.2 문자열
  • 2.3 숫자
    • 2.3.1 숫자 구문
    • 2.3.2 작은 소수 값
    • 2.3.3 안전한 정수 범위
    • 2.3.4 정수인지 확인
    • 2.3.5 32비트 (부호 있는) 정수
  • 2.4 특수 값
    • 2.4.1 값 아닌 값
    • 2.4.2 Undefined
    • 2.4.3 특수 숫자
    • 2.4.4 특이한 동등 비교
  • 2.5 값 vs 래퍼런스
  • 2.6 정리하기

타입

우선 자바스크립트 같은 동적 언어는 타입 개념이 없다고 생각하는 개발자가 많다고 한다. 하지만, 자바스크립트에도 어떤 값을 다른 값과 분별할 수 있는, 고유한 내부 특성의 집합(사전적 의미)이라고 할 수 있는 타입이 존재한다.

특히, 자바스크립트는 강제로 타입변환이 일어나는 사례가 많은데 타입별로 내재된 특성을 제대로 알고 있으면 값을 다른 타입으로 변환되는 상황이나 자바스크립트를 이해하는데 도움이 될 것이다.

내장 타입

자바스크립트에는 7가지 내장 타입이 있다.

  • null
  • undefined
  • boolean
  • number
  • string
  • object
  • symbol(ES6부터 추가)

여기서 object를 제외한 타입을 원시 타입이라고 한다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures

 

JavaScript data types and data structures - JavaScript | MDN

Programming languages all have built-in data structures, but these often differ from one language to another. This article attempts to list the built-in data structures available in JavaScript and what properties they have. These can be used to build other

developer.mozilla.org

값의 타입은 typeof 연산자로 알 수 있다.
하지만 해당 연산자를 사용해도 7가지 내장 타입과 1:1로 정확하게 떨어지지 않는다.

typeof 연산자
typeof 연산자

null

여기서 "null"은 "falsy" 한 유일한 원시 값이지만, typeof 연산자를 사용해 보면 "object"인 특별한 존재이다.

그래서 typeof로 null 값을 정확히 확인하려면 아래처럼 조건이 붙어야 한다.

var a = null;
(!a && typeof a === "object"); // true

fuctnion & array

함수도 "typeof" 연산자로 확인해 보면 "function"을 반환하는데 마치 "function"이 최상위 레벨의 내장 타입처럼 보일 수 있다. 하지만 실제 명세를 읽어보면 "object"의 "하위 타입"이다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function

 

Function - JavaScript | MDN

The Function object provides methods for functions. In JavaScript, every function is actually a Function object.

developer.mozilla.org

MDN의 문서를 참고해보면 아래처럼 함수에 대한 정의를 살펴볼 수 있다.

JavaScript의 Function은 다른 모든 객체처럼 속성과 메서드를 가질 수 있으므로 일급(first-class) 객체입니다. 다른 객체와 함수를 구별하는 것은, 함수는 호출할 수 있다는 점입니다. 간단히 말해, 함수는 Function 객체입니다.

배열의 경우는 "Key"를 문자열로 가지는 "object" 반대로 숫자 인덱스length property가 자동으로 관리되는 등의 추가 특성을 지닌 객체의 "하위 타입"이라 할 수 있다.

값은 타입

typeof 연산자를 사용하는 것은 이 변수에 들어있는 값의 타입은 무엇이냐고 묻는 것과 같다.

그리고 자바스크립트에서 값이 없는 변수의 경우 자동으로 "undefined" 타입의 값을 가지게 되며 선언하지 않은 변수를 참조할 경우 오류가 발생하는 것을 알 수 있다.

여기서 "typeof" 연산자의 주의점이 있는데 선언되지 않은 변수도 "undefined"로 결과를 반환하는 특이점이 있다.

undefined & reference error
undefined & reference error

"typeof" 연산자는 선언되지 않은 변수에 사용해도 오류가 없이 사용할 수 있는 장점이 있다.
(자바스크립트에서 선언되지 않은 변수를 참조하면 오류가 발생하므로 이후의 코드가 동작하지 않는다.)

우선 여러 값들 중 자바스크립트에서 배열, 문자열, 숫자는 독특한 특성을 가지고 있으니 살펴보도록 하자.

배열

자바스크립트의 배열은 어떤 타입의 값이라도 담을 수 있는 그릇으로 볼 수 있다.

array
array

책의 내용중에 배열 값에 delete 연산자를 적용하면 슬롯을 제거할 수 있다고 하지만, 마지막 원소까지 제거해도 length 속성 값까지 바뀌지 않기 때문에 주의할 필요성이 있다고 한다.

하지만, 실제 업무에서 배열을 다룰 때 생각을 해보면 배열 내장타입에서 제공하는 메서드를 기본적으로 많이 사용하고, 원본 배열을 복사해서 기존 데이터에 영향이 없도록 다양한 처리를 하고 있으며 delete 연산자를 사용할 일은 많지는 않다.

배열에서 실제 원소를 없애고 싶으면 Array.prototype.splice() 내장 메서드를 사용하자.

array remove
array remove

유사 배열

숫자 인덱스가 가리키는 값들의 집합을 유사 배열이라고 한다.

대표적으로 자바스크립트로 HTML DOM의 쿼리 작업을 실행하다 보면 유사배열 형태로 가져오는 것을 알 수 있다.

간단한 예시로 HTMLCollection 등을 예로 들 수 있겠다.

유사 배열은 내장 메서드를 사용할 수 없으므로 직접 반복문을 작성해서 순회하거나 "Array.from()" 혹은 "Array.slice()" 함수등을 사용해서 직접 배열로 만들어서 처리하는 방법도 있다.

문자열

문자열을 문자의 배열이라고 생각할 수 있는데, 문자열은 배열과 겉모습이 닮은 유사 배열이다. 그리고 배열과의 큰 차이점으로 문자열은 불변 값이고 배열은 가변 값이라는 차이점이 있다.

문자열이 불변 값이라는 것은 문자열 메서드는 그 내용을 바로 변경하지 않고 항상 새로운 문자열을 생성 후 반환한다는 특징을 가지고 있다.

반면에, 배열의 메서드는 그 자리에서 곧바로 원소를 수정하는 메서드가 대부분이다.

사실상 문자열을 다룰 때 유용한 대부분의 배열 메서드는 문자열에 쓸 수 없지만 불변 배열 메서드는 빌려 쓸 수 있다는 특징이 있다.

예시로, 문자열을 뒤집는 코드가 필요하다면 배열에는 "reverse()"라는 가변 메서드가 준비되어 있지만 문자열은 그렇지 않다.

문자열을 뒤집으려면 아래와 같은 코드가 필요하다.

문자열 뒤집기
문자열 뒤집기

숫자

자바스크립트에서 숫자 타입은 number가 유일하며 "정수", "부동 소수점 숫자"를 모두 아우른다. 사실 자바스크립트의 정수는 부동 소수점 값이 없는 값이다. (42.0 = 42와 같음)

자바스크립트 숫자 리터럴은 10진수로 표시하며 소수점 생략, 지수표현, 등등 외에도 여러 가지 표현 방법들이 있다.

만약, 숫자의 자릿수를 고정해서 나타내고 싶다면 소수점 이하자릿수를 고정해 주는 "toFixed()" 메서드를 사용하거나 유효 숫자 자릿수를 지정하는 "toPrecision()" 메서드를 사용할 수 있다.

toFixed(), toPrecision()
toFixed(), toPrecision()

작은 소수 값

자바스크립트에는 널리 알려진 이진 부동 소수점 숫자의 부작용 문제가 있다. (IEEE 754 표준을 따르는 모든 언어에서 공통적인 문제라고 한다.)

부동 소수점 더하기
부동 소수점 더하기

저런 부동 소수점을 처리하는 일반적인 방법으로는 미세한 반올림 오차를 허용 공차로 처리하는 방법이 있다.

저런 미세한 오차를 "머신 입실론(Machine Epsilon)"이라고 하는데 자바스크립트의 숫자 머신 입실론은 2^-52이다.
ES6부터는 "Number.EPSILON"으로 미리 정의되어 있다.

부동 소수점 비교
부동 수소점 비교

NaN

"NaN"은 글자 그대로 "숫자 아님(Not A Number)"이다. 주의할 점은 NaN은 어떤 NaN과도 동등하지 않은 반사성이 없는 유일무이한 값으로 취급된다.

내장함수 isNaN()을 활용하면 숫자인지 여부를 평가할 수 있는데 이것으로 숫자여부를 판단할 때는 주의해야 한다. (문자열도 NaN으로 보기 때문)

ES6부터는 "Number.isNaN()" 메서드를 지원하니 안전하게 NaN 여부를 체크하자.

isNaN
isNaN

값 vs 레퍼런스

자바스크립트에서는 포인터라는 개념 자체가 없고 참조하는 방법도 조금 다르다. (c++ 언어를 예시로 든다면)

우선적으로 자바스크립트는 어떤 변수가 다른 변수를 참조할 수 없다.

자바스크립트에서 레퍼런스는 값을 가리키며 10개의 레퍼런스가 있다면 이들은 저마다 항상 공유된 단일 값을 개별적으로 참고하고 있는 상태이다.

자바스크립트에는 값 또는 레퍼런스의 할당 및 전달을 제어하는 구문이 없고 값의 타입만으로 값-복사, 레퍼런스-복사를 선택해서 실행된다.

아래 타입들은 값-복사 방식으로 할당/전달된다.

  • string
  • number
  • boolean
  • null
  • undefined
  • symbol

아래 타입들은 레퍼런스-복사로 전달된다.

  • object
  • function
  • 합성 값

레퍼런스 복사

레퍼런스 복사
레퍼런스 복사

실제 데이터를 다루는 업무에서는 특히 원본 데이터를 다룰 때 배열, 객체등에 담아서 쓰는 경우가 많다.

특히 자바스크립트에서 기존 데이터를 합성 값(배열 같은)에 담아서 사용하다 보면 수정되어야 하지 않을 데이터가 수정되거나 파악하기 어려운 버그가 발생할 수 있다.

단편적인 예로 레퍼런스 값값-복사에 의해 효과적으로 전달하기 위해서는 손수 값의 사본을 만들거나, 깊은 복사를 지원하는 라이브러리를 활용해서 값을 사용하는 것이 좋은 방안이 될 수 있다.