자바스크립트 조망하기

11hertz·2024년 2월 19일

YDKJSY

목록 보기
2/9
post-thumbnail

2.1 파일은 프로그램입니다

JS에서는 파일 각각이 별도의 프로그램
파일 각각을 프로그램으로 봐야 하는 것이 중요한 이유는 오류 처리와 관련
JS는 파일을 프로그램으로 취급
파일 하나에만 오류가 있어도(파싱/컴파일/실행) 다음 파일이 처리되지 않을 수 있음
각 파일이 제대로 작동하는지 확인하고, 오류 발생 시 우아한 처리가 중요

독립적 .js 파일 여러 개를 하나의 프로그램으로서 작동시키는 유일한 방법은 전역 스코프를 사용해 파일간 상태 공유 및 공통 사용 기능 접근 가능하게 하는 것
전역 스코프 네임스페이스에서 여러 .js 파일이 조합되면 런타임에서 하나의 애플리케이션으로 작동

ES6 이후 JS는 독립형 JS 프로그램 포맷 외에 모듈 포맷도 지원
모듈 또한 파일 기반
파일을 import 문이나 <script type="module"> 태그를 통해 읽는 경우 하나의 모듈로서 처리
JS는 각 모듈을 별도로 처리
한 모듈에서 다른 모듈을 불러오면 런타임에서 두 모듈이 상호작용할 수 있음
파일 하나를 고유한 작은 프로그램이라 생각해야 함

2.2 값

프로그램에서 정보의 가장 기본적인 단위는 값이며 값에는 데이터가 저장됨
JS에서 값은 크게 원시 타입(Primitive Type)과 객체 타입(Object Type)으로 분류
JS에서는 리터럴(Literal)을 사용해 프로그램에 값 주입

원시 타입에는(String, Number, BigInt, Boolean, Null, Undefined, Symbol) 등이 있음

문자열은 문자를 모아놓은 집합으로 단어나 문자를 표현하는 용도
문자열의 범위를 정하기 위해 큰 따옴표, 작은 따옴표, 백틱 사용 가능
개인의 취향이나, 코드 가독성과 유지 보수를 위해 일관성 있는 표기법을 사용해야 함
보간이 필요한 경우에만 백틱을 사용하고, 보간이 필요 없는 경우에는 큰 따옴표나 작은 따옴표 중 하나를 일관되게 사용하는 것이 좋음

JS에는 문자열 말고 불리언, 숫자와 같은 원시 리터럴값 사용 가능

숫자 중 아주 큰 정수를 나타낼 때는 원시 타입 BigInt 사용

null, undefined라는 원시 타입도 지원
대부분의 경우 두 타입 모두 값의 비어 있음(존재하지 않음)을 나타내는 데 사용

Symbol 타입값은 사람이 추측할 수 없게 만든 특수한 숨김 값
객체에서 특정한 키를 만들 때 주로 사용
일반적인 JS 프로그램에서 Symbol을 직접 사용하지는 않으며, 주로 라이브러리 및 프레임워크에서 사용

2.2.1 배열과 객체

JS에는 원시 타입 말고 객체 타입도 존재
배열은 특수한 유형의 객체. 객체 내 정렬된 데이터에 숫자 인덱스가 매겨짐
배열에는 원시 타입, 객체 타입 상관 없이 모든 타입의 값이 들어갈 수 있음
객체는 배열보다 좀 더 일반적인 데이터 타입이며 정렬되지 않은 키-값 쌍을 모아놓은 컬렉션
배열은 인덱스라는 숫자를 통해 요소에 접근하는 반면, 객체는 요소 위치를 알려주는 문자열(키 혹은 프로퍼티)을 사용해 요소에 접근
객체에서 원하는 정보에 접근하는 방식은 온점 사용 방법, 대괄호 사용 방법이 있음

2.2.2 값의 타입

typeof 연산자를 사용해 원시 타입과 객체 타입 값을 구분
값의 타입을 변경하는 것을 JS에서는 타입 강제 변환이라 함
변수에 할당하거나 어딘가에 넘길 때 원시값과 객체의 작동 방식에는 차이가 있음

2.3 변수 선언과 사용

변수는 값을 담는 상자
변수를 사용하려면 변수 선언(생성)이 선행되어야 함
식별자라고도 부르는 변수는 다양한 문법으로 선언 가능하며 문법마다 작동 방식이 다름

let과 var로 선언한 변수는 접근 범위 측면에서 가장 큰 차이
let으로 선언한 변수는 var로 선언한 변수보다 접근 범위가 한정적
var로 선언한 변수는 접근 범위가 함수 스코프, let으로 선언한 변수는 블록 스코프
변수의 접근 범위를 블록으로 한정지으면, 프로그램내 변수의 영향 범위를 제한해 변수 이름 중복을 막는다는 측면에서 유용
var는 '좀 더 넓은 범위에서 사용할겁니다'를 나타낼 때 유용

const는 let과 유사하나 선언과 동시에 값을 할당해야 함
나중에 다른 값을 재할당할 수 없다는 점에서 차이
const는 간단한 원시값에 이름을 부여할 때 가장 적절
const를 사용하면 재할당과 값 변경 관련 혼란을 피하고 가독성이 좋아지는 효과가 있음

2.4 함수

JS 개발 시 함수보다 포괄적 개념인 프로시저를 프로그램에 녹여내기 위해 함수를 작성해야 함
프로시저는 한 번 이상 호출할 수 있고, 입력값이 있을 수 있으며 하나 이상의 출력값을 반환하는 구문의 모음을 의미

함수 선언문으로 정의한 함수는 함수 식별자와 실제 함수를 나타내는 값의 연관이 코드 실행 단계가 아닌 컴파일 단계에서 맺어짐
함수 표현식으로 선언한 함수는 함수 식별자와 실제 함수를 나타내는 값과 실행 단계 전에는 관계를 맺지 않음
JS에서 함수는 할당 가능하고 어디든 전달 가능한 값
매개변수를 통해 입력을 받고, 오로지 한 개의 값만 반환 가능
여러 개 반환 시, 객체나 배열로 감싸서 반환해야 함
함수는 값이므로, 함수를 객체의 프로퍼티로 할당 가능

2.5 비교

프로그램은 값을 비교해 정체와 값 사이의 관계를 파악한 후 의사 결정을 내림
JS에도 비교를 가능하게 하는 몇 가지 메커니즘이 있음

2.5.1 같음에 대한 고찰

JS에서 같음을 비교할 때는 '정확하게' 일치하는 지를 따지기도 하지만 '아주 유사' 하다거나 '교환 가능' 한지와 같이 좀 더 넓은 관점에서 비교하는 때도 있음
일치 비교와 동등 비교의 차이를 알고 있어야 함
일치 연산자(===)는 대부분 예상대로 작동하나 NaN이나 -0과 함께 사용 시, 예상과 다르게 작동
따라서 일치 연산자는 NaN이나 -0과 함께 사용해서는 안 됨
NaN의 경우는 Number.isNaN()을 -0의 경우에는 Object.is()를 사용
'===' 연산자 만으로는 아주 정확하게 비교를 할 수 없음
원시 타입이 아닌 객체끼리 비교할 때는 상황이 조금 더 복잡
일치 비교는 값의 본질이나 내용을 비교
비교 대상이 객체인 경우에는 본질이나 내용이 아닌 구조적 일치를 비교
JS에서는 객체끼리 비교할 때 비교 연산자가 구조적 일치를 판단하지 않고 독자성 일치를 비교
JS에서 객체는 참조에 의해 고정되며 참조 복사본을 사용하여 할당 및 전달
참조(독자성)를 대상으로 일치 비교가 일어남
JS에는 객체 구조가 같은지 비교할 방법이 없음
JS에서는 같은 것을 참조하는지만 비교 가능
객체 구조가 같은지 확인하려면 직접 코드를 짜서 확인해야 함

2.5.2 강제 변환

강제 변환은 한 타입의 값이 다른 타입의 값으로 변하는 것을 의미
'==' 연산자와 '===' 연산자 모두 피연산자의 타입을 비교
피연산자가 같은 타입이라면 어떠한 차이도 없이 완전히 동일하게 작동
피연산자의 타입이 다른 경우 '==' 연산자는 비교 이전에 강제로 타입을 맞추는 작업을 수행한다는 점에서 차이가 있음
'==' 연산자는 강제 변환을 먼저 실행해 피연산자의 타입을 맞춘 이후에 '===' 연산자처럼 작동
'=='와 마찬가지로 '<', '>', '<=', '>=' 또한 피연산자의 타입이 같으면 '==='처럼 작동
타입이 다른 경우는 타입 강제 변환이 먼저 일어남 (대개 숫자형으로 변환)
비교 연산자는 피연산자 모두가 문자열인 경우를 제외하고는 수자 타입으로 타입을 변환해 비교
피연산자 모두가 문자열일 때는 사전처럼 알파벳 순으로 문자열을 비교

2.6 코드 구조화 패턴

JS 생태계 전반에 걸쳐 데이터와 행동 관점에서 코드를 구조화하는 패턴은 크게 클래스와 모듈 두 가지가 있음
클래스와 모듈은 상호 배타적인 패턴이 아니며, 많은 프로그램이 두 패턴 모두 사용
JS를 능숙하게 다루려면 두 패턴 모두를 이해하고 각 패턴의 적합한 쓰임새와 사용이 적절하지 않은 경우를 알고 있어야 함

2.6.1 클래스

클래스는 사용자가 정의한 데이터 타입으로 데이터와 이 데이터를 조작하는 동작이 들어감
다만 사용자 정의 데이터 타입이 어떻게 동작하는지 정의하긴 하지만 구체적인 값은 아님
프로그램에서 사용할 수 있는 구체적인 값이 필요하다면, new 키워드를 사용해 인스턴스를 만들어야 함
클래스의 동작(메서드)은 클래스만 가지고는 사용할 수 없음
인스턴스를 통해서만 호출이 가능
클래스 메커니즘을 사용하면 데이터와 데이터의 동작을 한 곳에 묶어 구조화 가능
클래스 없이도 동일한 결과물을 내주는 프로그램을 만들 수 있음
하지만 체계적이지 않고 가독성이 떨어지며, 유지 보수하기 어려운 프로그램을 만들 가능성이 높음

  • 상속
    클래스라는 독립적 논리적 공간에 데이터와 행동을 체계화할 수 있도록 만드는 강력한 도구
    자식 클래스는 부모 클래스의 데이터나 동작에 접근하거나 이를 사용하는 방식으로 부모 클래스와 협력

  • 다형성
    상속받은 메서드와 새롭게 정의한 메서드의 이름이 동일하고 공존할 수 있는 것

2.6.2 모듈

모듈 패턴은 클래스와 마찬가지로 논리적 단위 기준으로 데이터와 행동을 그룹화하는데 목적이 있음
클래스처럼 협력을 위해 다른 모듈의 데이터나 행동을 가져오거나 접근할 수 있음

  • 클래식 모듈
    최소한 한 번 이상 실행되는 외부 함수
    모듈 인스턴스 내부의 숨겨진 데이터를 대상으로 작동하는 함수가 있는 '인스턴스'를 반환

  • ES 모듈
    ES6에서 도입된 ES 모듈(ESM)은 클래식 모듈과 동일한 취지를 갖는 문법
    AMD, UMD, CommonJS의 주요 변형과 그 용례를 고려해 만들어짐
    구현 관점에서 ES 모듈과 클래식 모듈의 접근법에는 상당히 큰 차이가 있음
    ES 모듈에는 모듈을 정의하는 래핑 함수가 없음
    ES 모듈은 파일이라는 맥락에서 구현되며, ES 모듈은 항상 파일 기반
    ES 모듈을 사용할 때 모듈 API와 직접 상호작용하지 않음
    export 키워드를 사용해 변수나 메서드를 퍼블릭 API로 정의
    모듈 안에 있는 변수나 메서드라도 export 키워드가 붙어 있지 않으면 클래식 모듈에서처럼 숨김 상태가 됨
    ES 모듈을 인스턴스화 하지 않아도 import 키워드를 사용해 가져오기만 한다면 단일 인스턴스처럼 사용 가능
    프로그램 내에서 import 키워드를 사용해 처음 모듈을 가져온 순간 인스턴스가 생기고, 동일한 모듈을 다른 곳에서 import 할 떄는 이미 생성된 모듈의 참조만 가져옴

profile
Practice Makes Perfect!

0개의 댓글