모던 자바스크립트 Deep Dive (2)

📖 정리

  • 이 글은 '모던 자바스크립트 Deep Dive'를 읽으면서 새롭게 알게된 내용을 정리하기 위해 쓴 글 입니다.

7장 연산자

  • 연산자는 하나 이상의 표현식을 대상으로 산술, 할당, 비교, 논리, 타입, 지수 연산 등을 수행해 하나의 값을 만든다.

    • 이때 연산의 대상을 피연산자라고 한다.
    • 피연산자는 값으로 평가될 수 있는 표현식이여야 한다.
    • 그리고 피연산자와 연산자의 조합으로 이뤄진 연산자 표현식도 값으로 평가될 수 있는 표현식이다.
    • 연산자는 피연산자를 연산하여 새로운 값을 만드는 역할을 한다.
  • 숫자 타입이 아닌 피연산자에 단항 연산자를 사용하면 피연산자를 숫자 타입으로 변환하여 반환한다. 이때 피연산자를 변경하는 것은 아니고 숫자 타입으로 변환한 값을 생성해서 반환한다.

    let x = 1;
    console.log(+x); // 1
    console.log(x); // "1"
  • +연산자는 피연산자 중 하나 이상이 문자열인 경우 문자열 연결 연산자로 동작한다.

    • 다른 하나가 문자열이 아닌 경우 암묵적 타입 변환 또는 타입 강제 변환이 일어난다.
  • 할당문은 값으로 평가되는 표현식인 문으로서 할당된 값으로 평가된다.

    var a, b, c;
    // 연쇄 할당, 오른쪽에서 왼쪽으로 진행
    a = b = c = 0;
    // 값으로 평가되는 표현식인 문이기 때문에 아래와 같이 동작
    var x = 10;
    console.log((x = 10)); // 10
  • == 동등 비교 연산자는 좌항과 우항의 피연산자를 비교할때 먼저 암묵적 타입 변환을 통해 타입을 일치시킨 후 같은 값인지 비교한다.

  • === 일치 비교 연산자는 좌항과 우항의 피연산자가 타입도 같고 값도 같은 경우에 한하여 true를 반환한다.

    • 일치 비교 연산자에서 유일하게 자신과 일치하지 않는 값은 NaN 하나 뿐인다.
    • NaN을 조사하려면 빌트인 함수 Number.isNaN을 사용한다.
  • typeof 연산자로 null 값을 연산해보면 null이 아닌 object를 반환한다.

8장 제어문

  • 제어문은 조건에 따라 코드 블록을 실행하거나 반복 실행 할 때 사용한다.

  • 블록문은 0개 이상의 문을 중괄호로 묶은 것으로, 코드 블록 또는 블록이라고 한다.

    • 자바스크립트는 블록문을 하나의 실행 단위로 취급한다.
    • 블록문은 문의 종료를 의미하는 자체 종결성을 가지기 때문에 블록문의 끝에는 세미콜론을 붙이지 않는다.

9장 타입 변환과 단축 평가

  • 값의 타입은 개발자의 의도에 따라 다른 타입으로 변환할 수 있다.

    • 개발자가 의도적으로 값의 타입을 변환하는 것을 명시적 타입 변환 또는 타입 캐스팅이라 한다.
    • 개발자의 의도와는 상관없이 표현식을 평가하는 도중에 바뀌는 경우를 암묵적 타입 변환 또는 타입 강제 변환 이라고 한다.
  • 자바스크립트 엔진은 산순 연산자 표현식을 평가하기 위해 산술 연산자의 피연산자 중에서 숫자 타입이 아닌 피연산자를 숫자 타입으로 암묵적 타입 변환한다.

  • 자바스크립트 엔진은 불리언 타입이 아닌 갓을 Truthy 값, Falsy 값으로 구분한다. Falsy 값은 아래와 같다.

    • false
    • undefined
    • null
    • 0, -0
    • NaN
    • 빈문자열('')
  • 명시적 타입 변환

    • 문자열 타입으로 변환
      • String 생성자 함수를 new 연산자 없이 호출하는 방법
      • Object.prototype.toString 매서드 사용
      • 문자열 연결 연산자를 이용하는 방법
    • 숫자 타입으로 변환
      • Number 생성자 함수를 new 연산자 없이 호출하는 방법
      • parseInt, parseFloat 함수를 이용하는 방법(문자열만 해당)
      • +단항 산술 연산자를 이용하는 방법
      • *산술 연산자를 이용하는 방법
    • 불리언 타입으로 변환
      • Boolean 생성자 함수를 new 연산자 없이 호출하는 방법
      • !부정 논리 연산자를 두 번 사용하는 방법
  • 단축 평가

    • 논리합 또는 논리곱 연산자 표현식은 언제나 2개의 피연산자 중 어느 한쪽으로 평가된다.
      • 논리합 연산자는 논리 연산의 결과를 결정한 첫 번째 피연산자를 반환한다.
      • 논리곱 연산자는 논리 연산의 결과를 결정한 마지막 피연산자를 반환한다.
  • 옵셔널 체이닝 연산자

    • ES11(ECMAScript2020)에서 도입된 옵셔널 체이닝 연산자 ?. 은 좌항의 피연산자가 null 또는 undefined인 경우 undefined를 반환하고, 그렇지 않으면 우항의 프로퍼티 참조를 이어간다.
  • null 병합 연산자

    • ES11(ECMAScript2020)에서 도입된 null 병합 연산자 ?? 는 좌항의 피연산자가 null 또는 undefined인 경우 우항의 피연산자를 반환하고, 그렇지 않으면 좌항의 피연산자를 반환한다.
      • 변수에 기본값을 설정할 때 유용하다.

10장 객체 리터럴

  • 자바스크립트는 객체 기반의 프로그래밍 언어이며, 자바스크립트를 구성하는 거의 모든 것이 객체다. 원시 값을 제외한 나머지 값(함수, 배열, 정규 표현식 등)은 모두 객체다.

  • 원시 값은 변경 불가능한 값 이지만, 객체 타입의 값, 즉 객체는 변경 가능한 값이다.

  • 프로퍼티란 객체의 상태를 나타내는 값(data)을 말하며 메서드는 프로퍼티를 참조하고 조작할 수 있는 동작을 말한다.

  • 프로퍼티 키에 문자열이나 심벌 값 외의 값을 사용하면 암묵적 타입 변환을 통해 문자열이 된다.

  • 이미 존재하는 프로퍼티 키를 중복 선언하면 나중에 선언한 프로퍼티가 먼저 선언한 프로퍼티를 덮어쓴다.

  • ES6에서는 프로퍼티 값으로 변수를 사용하는 경우 변수 이름과 프로퍼티 키가 동일한 이름일 때 프로퍼티 키를 생략할 수 있다. 이때 프로퍼티 키는 변수 이름으로 자동 생성된다.

  • ES6에서는 메서드를 정의할 때 function 키워드를 생략한 축약 표현을 사용할 수 있다.

    const obj = {
      name: 'Yoo',
      // 기존에는 sayHi: function() {
      sayHi() {
        console.log(`Hi ${this.name}`);
      },
    };

11장 원시 값과 객체의 비교

  • 원시 타입

    • 원시 타입의 값, 즉 원시 값은 변경 불가능한 값이다.
    • 원시 값을 변수에 할당하면 변수(확보된 메모리 공간)에는 실제 값이 저장된다.
    • 원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달된다. 이를 값에 의한 전달이라 한다.
    • 출처
  • 객체 타입

    • 객체 타입의 값, 즉 객체는 변경 가능한 값이다.
    • 객체를 변수에 할당하면 변수(확보된 메모리 공간)에는 참조 값이 저장된다.
    • 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달된다. 이를 참조에 의한 전달이라 한다.
    • 출처
  • 자바스크립트의 문자열은 원시 타입이며, 변경 불가능하다. 이는 문자열이 생성된 이후에는 변경될 수 없음을 의미한다.

  • 문자열은 유사 배열 객체이면서 이터러블이므로 배열과 유사하게 각 문자에 접근할 수 있다.

    유사 배열 겍체란 마치 배열처럼 인덱스로 프로퍼티 값에 접근할 수 있고 length 프로퍼티를 갖는 객체를 말한다. 원시 값을 객체처럼 사용하면 원시 값을 감싸는 래퍼 객체로 자동 변환된다.

  • 자바스크립트 객체는 프로퍼티 키를 인덱스로 사용하는 해시 테이블이라고 생각할 수 있다. 대부분의 자바스크립트 엔진은 해시테이블과 유사하지만 높은 성능을 위해 일반적인 해시 테이블 보다 더 나은 방법으로 객체를 구현한다.

  • V8 자바스크립트 엔진에서는 프로퍼티에 접근하기 위해 동적 탐색 대신 히든 클래스 라는 방식을 사용해 성능을 높힌다. 히든 클래스는 자바와 같이 고정된 객체 레이아웃(클레스)과 유사하게 동작한다. 참고

12장 함수

  • 함수는 일련의 과정을 문으로 구성하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것이다.

  • 함수 내부로 입력을 전달받는 변수를 매개변수, 입력을 인수, 출력을 반환값이라 한다.

  • 함수 리터럴은 fucntion 키워드, 함수 이름, 매개변수 목록, 함수 몸체로 구성된다.

    • 함수 이름
      • 함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자다.
      • 함수 이름은 생략할 수 있다.
    • 매개변수 목록
      • 각 매개변수에는 함수를 호출할 때 지정한 인수가 순서대로 할당된다. 즉 매개변수 목록은 순서에 의미가 있다.
    • 함수 몸체
      • 함수가 호출되었을 때 일괄적으로 실행될 문들을 하나의 실행 단위로 정의한 코드 블록이다.
    • 리터럴은 값을 생성하기 위한 표기법이다. 따라서 함수 리터럴도 평가되어 값을 생성하며, 이 값은 객체다. 즉 함수는 객체다.
  • 함수 선언문(기본적인 fucntion을 통한 함수 정의)은 표현식이 아닌 문이다. 하지만 아래 코드를 보면 함수 선언문이 변수에 할당되는 것으로 보인다.

const add = function add(x, y) {
  return x + y;
};

console.log(add(2, 5)); // 7
  • 이렇게 동작하는 이유는 자바스크립트 엔진이 코드의 문맥에 따라 동일한 함수 리터럴을 표현식이 아닌 문인 함수 선언문으로 해석하는 경우와 표현식인 문인 함수 리터럴 표현식으로 해석하는 경우가 있기 때문이다.

    • 자바스크립트 엔진은 함수 이름이 있는 함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석하고, 함수 리터럴이 값으로 평가되어야 하는 문맥이면 함수 리터럴 표현식으로 해석한다.
  • 자바스크립트 엔진은 함수 선언문을 해석해 함수 객체를 생성한다. 이때 함수 이름은 함수 몸체 내부에서만 유효한 식별자이므로 함수 이름과 별도로 생성된 함수 객체를 가리키는 식별자가 필요하다.

    • 자바스크립트 엔진은 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고, 거기에 함수 객체를 할당한다.
    • 함수는 함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출한다.
    // 대략적인 의사코드로는 이렇게 생각하면 된다.
    const add = function add(x, y) {
      return x + y;
    };
    
    console.log(add(2, 5)); // 7
  • 함수 리터럴을 이용한 함수 표현식과 함수 선언문은 차이가 존재한다. 함수 생성 시점과 함수 호이스팅이 그것이다.

    • 함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출할 수 있다.
    • 모든 선언문의 경우는 런타임 이전에 먼저 실행되기 때문이다. 이를 함수 호이스팅이라 한다.
    • 하지만 함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출할 수 없다.
    • 이는 변수 할당문의 값은 할당문이 실행되는 시점인 런타임에 평가되기 때문에 그렇다.
  • 화살표 함수는 내부 동작이 간략화되어 있다.

    • 화살표 함수는 생성자 함수로 사용할 수 없다.
    • 기존 함수와 this 바인딩 방식이 다르다.
    • prototype 프로퍼티가 없으며 arguments 객체를 생성하지 않는다.
  • 함수를 호출하면 현재의 실행 흐름을 중단하고 호출된 함수로 실행 흐름을 옮긴다. 이때 매개변수에 인수가 순서대로 할당하고 함수 몸체 문들이 실행되기 시작한다.

    • 필요한 값을 함수 외부에서 함수 내부로 전달할 필요가 있는 경우 매개변수를 통해 인수를 전달한다.
      • 인수는 값으로 평가될 수 있는 표현식이여야 한다.
      • 인수는 함수를 호출할 때 지정하며, 개수와 타입에 제한이 없다.
      • 인수가 부족해서 인수가 할당되지 않은 매개변수의 값은 undefined이다.
      • 초과된 인수는 암묵적으로 arguments 객체의 프로퍼티로 보관된다.
    • 함수가 호출되면 함수 몸체 내에서 암묵적으로 매개변수가 생성되고 일반 변수와 마찬가지로 undefined로 초기화된 이후 인수가 순서대로 할당된다.
  • 함수형 프로그래밍에서는 어떤 외부 상태에 의존하지 않고 변경하지도 않는, 즉 부수 효과가 없는 함수를 순수 함수라고 한다.

    • 순수 함수는 동일한 인수가 전달되면 언제나 동일한 값을 반환하는 함수다.
    • 어떤 외부 상태에도 의존하지 않고 오직 매개변수를 통해 함수 내부로 전달된 인수에게만 의존해 값을 생성해 반환한다.
    • 외부 상태에는 전역변수, 서버 데이터, 파일, Console, DOM 등이 있다.