공부 완료 (9/19 ~10/20)
기억하고 싶은 내용을 적습니다.
마지막 100쪽을 남기고, 집안일의 이유로 10일 가량 공부를 못하여 예상보다 늦게 마무리가 되었다.
자바스크립트에 대한 딥한 내용을 알 수 있었고, 1회독으로는 내 것으로 만들지 못한다는 것을 알고 있다.
꾸준히 다시 돌려보면서 자바스크립트와 좀 더 친해질 수 있기를...
9장
-
자바스크립트 엔진은 불리언 타입이 아닌 값을 Truthy값, Falsy 값으로 구분
Falsy : false, undefined, null, 0, -0, NaN, ''
Truthy : Falsy 외의 모든 값
-
옵셔널 체이닝 연산자 (?.) / ES11
좌항 피연산자가 null, undefined인 경우, undefined 반환.
그 외에는 우항의 프로퍼티 참조.
-
null 변합 연산자 (??) / ES11
좌항 피연산자가 null, undefined인 경우, 우항의 피연산자 반환
그 외에는 좌항의 피연산자 반환.
(변수에 기본값 설정 시 유용)
10장
- 객체는 프로퍼티의 집합이며, 프로퍼티는 키와 값으로 구성된다.
- 메서드는 객체 프로퍼티 값에 들어간 함수를 의미한다.
11장
- 원시 타입
- 변경 불가능한 값
원시 값 자체를 변경할 수 없다는 것이지 변수 값을 변경할 수 없다는 것은 아님.
- 변수에 실제 값 저장
- 원시 값 복사
사실은 값을 전달하는 것이 아닌 메모리 주소를 전달한다. 전달 된 메모리 주소를 통해 메모리 공간에 접근하면 값을 참조할 수 있다. 하지만 결국 서로 간섭을 할 수는 없다.
- 객체 타입
- 변경 가능한 값
- 변수에 참조 값 저장
- 참조 값 복사
복사 된 식별자와 동일한 객체를 공유한다.
12장
- 함수 : 매개변수, 인수, 반환값으로 이루어짐.
- 함수 선언문에서 js 엔진은 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성, 거기에 함수 객체를 할당한다. 함수는 이름으로 호출되는 것이 아닌, 함수 객체를 가리키는 식별자로 호출된다.
- 함수 선언문은 "표현식이 아닌 문"이고, 함수 표현식은 "표현식인 문"이다.
- 함수 호이스팅
- 함수 선언문이 코드의 선두로 끌어올려진 것 처럼 동작하는 js 고유의 특징
- 함수 선언문 : 함수 호이스팅 발생. 암묵적으로 생성된 식별자는 함수 객체로 초기화
- 함수 표현식 : 변수 호이스팅 발생. var, let 등 키워드로 선언된 변수는 undefined로 초기화
- 함수 호출 전에 반드시 함수를 선언해야 한다는 규칙을 무시하기 때문에,
함수 선언문 대신 함수 표현식을 사용할 것을 권장한다.
- 콜백 함수
- 콜백 함수 : 매개변수를 통해 다른 함수의 내부로 전달되는 함수
- 고차 함수 : 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수
- 콜백 함수는 고차함수에 의해 호출되며, 이때 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다.
따라서 콜백 함수를 호출하지 않고 함수 자체를 전달해야 한다.
- 순수 함수와 비순수 함수
- 외부 상태에 의존/변경 되지 않는 함수를 순수 함수, 그렇지 않은 함수를 비순수 함수라고 한다.
- 비순수 함수가 많아지면 상태 변화를 추적하기 어렵고, 코드의 복잡성을 증가시키기 때문에 순수 함수를 사용하는 것이 좋다.
13장
- 스코프(scope) : 식별자(변수, 함수, 클래스 등...)가 유효한 범위
- 스코프 체인 : 모든 스코프는 하나의 계층적 구조로 연결됨
- 변수를 참조할 때 js 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.
- 실행 컨텍스트의 렉시컬 환경을 단방향으로 연결하여, 물리적인 실체로 존재한다.
- 상위 스코프에서 유효한 변수는 하위 스코프에서 자유롭게 참조 할 수 있지만, 반대는 불가능.
- 함수 레벨 스코프 : 코드 블록이 아닌 "함수"에 의해서만 지역 스코프가 생성됨
- 블록 레벨 스코프 : 모든 코드 블록이 지역 스코프를 만듦
- 동적 스코프 : 함수를 호출한 시점에 상위 스코프 결정
- 정적 스코프, 렉시컬 스코프 : 함수를 정의한 시점에 상위 스코프 결정
14장
- 전역 변수의 생명 주기는 애플리케이션의 생명 주기와 같고, 지역 변수의 생명 주기는 함수의 생명 주기와 일치한다.
- 호이스팅은 스코프 단위로 동작한다. 지역 변수의 호이스팅은 지역 변수의 선언이 지역 변수 스코프를 선두로 끌어올린 것 처럼 동작한다.
- 전역 변수의 문제점
- 암묵적 결합 : 모든 코드가 전역 변수를 참조하고 변경할 수 있다.
- 긴 생명 주기
- 스코프 체인 상에서 종점에 존재 : 검색 속도가 가장 느리다.
- 네임스페이스 오염 : 다른 파일 내에 동일한 이름으로 전역 변수가 명명될 수 있다.
- 전역 변수의 사용을 억제하는 방법
- 즉시 실행 함수 사용
- 네임스페이스 객체를 생성하여 변수를 프로퍼티로 추가
- 모듈 패턴 : 관련이 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈을 만든다.
- ES6 모듈 : 파일 자체의 독자적인 모듈 스코프를 제공
(IE 및 구형 브라우저에서 동작하지 않기 때문에 ES6 모듈 기능을 사용하는 것 보다 모듈 번들러를 사용하는 것이 일반적임.)
15장
var 키워드 문제점
- 변수 중복 선언 허용
- 함수 레벨 스코프
- 변수 호이스팅
- 전역 객체
window의 프로퍼티
let 키워드
- 변수 중복 선언 금지
- 블록 레벨 스코프
- 변수 호이스팅: 호이스팅이 발생하지 않는 것 처럼 동작.
"선언 단계"와 "초기화 단계"가 분리되어 진행된다.
- 전역 객체의 프로퍼티가 아닌, 개념적 블록(전역 렉시컬 환경의 선언적 환경 레코드??) 내에 존재
const 키워드
- 반드시 선언과 동시에 초기화해야 한다.
- 재할당 금지
- 상수 : 변경할 수 없는 원시 값을 할당한 경우, 할당된 값을 변경할 방법은 없다.
- 객체 : 객체를 할당한 경우, 값을 변경할 수 있다.
=> const는 재할당을 금지할 뿐 "불변"을 의미하지는 않는다.
16장
- 내부 슬롯, 내부 메서드
- js 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티(pseudo property)와 의사 메서드(pseudo method).
- 이중 대괄호( [[...]] )로 감싼 것들.
- js 엔진 내부 로직이므로 직접 접근은 불가능하지만, 일부 간접 접근 수당을 제공함.
예) 모든 객체는 [[prototype]]이라는 내부 슬롯을 가진다. __proto__ 명령어를 통해 간접 접근 가능. object.__proto__
- 프로퍼티 어트리뷰트와 프로퍼티 디스크립터
- js 엔진은 프로퍼티를 생성할 때 상태를 나타내는 프로퍼티 어트리뷰트(property attribute)를 기본값으로 자동 정의한다.
- 프로퍼티의 상태
[[Value]] : 값 (value)
[[Writable]] : 값의 갱신 가능 여부 (writable)
[[Enumerable]] : 열거 가능 여부 (enumerable)
[[Configurable]] : 재정의 가능 여부 (configurable)
- 프로퍼티 어트리뷰트를 간접 접근하는 방법
Object.getOwnPropertyDescriptor(객체, '프로퍼티명') : 객체의 특정 프로퍼티의 상태를 반환.
Object.getOwnPropertyDescriptors(객체) : 객체의 모든 프로퍼티의 상태를 반환
=> 프로퍼티 디스크립터(property descriptor) 객체를 반환한다.
- 데이터 프로퍼티 (data property)
- 키와 값으로 구성된 일반적인 프로퍼티.
- 프로퍼티 어트리뷰트
[[Value]], value
[[Writable]], writable
[[Enumerable]], enumerable
[[Configurable]], configurable
- 프로퍼티가 생성될 때
[[Value]]는 프로퍼티 값으로 초기화 되며, [[Writable]], [[Enumerable]], [[Configurable]]의 값은 true로 초기화 된다.
- 접근자 프로퍼티 (accessor property)
- 자체적으로 값을 가지고 있지 않음.
- 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수로 구성됨.
- 프로퍼티 어트리뷰트
[[Get]], get
[[Set]], set
[[Enumerable]], enumerable
[[Configurable]], configurable
해당 부분 예시는 책 p224 참고
- 프로토타입
- 객체의 상위 객체의 역할을 하는 객체다.
- 프로토타입은 하위 객체에게 자신의 프로퍼티와 메서드를 상속한다.
- 프로토타입 체인
- 프로토타입이 단방향 링크드 리스트 형태로 연결되어 있는 상속 구조를 말한다.
- 프로퍼티 정의
- 새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나, 기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의 하는 것.
Object.defineProperty(객체, '프로퍼티명', 프로퍼티 디스크립터 객체)
- 객체 변경 방지
- 중첩 객체까지 영향을 주고 싶으면 재귀적으로 메서드 호출해야함.
- 객체 확장 금지
Object.preventExtensions
- 프로퍼티 추가 금지
Object.isExtensible 확장 가능 객체 여부 확인
- 객체 밀봉
Object.seal
- 읽기, 쓰기만 가능
Object.isSealed 밀봉 객체 여부 확인
- 객체 동결
Object.freeze
- 읽기만 가능
Object.isFrozen 동결 객체 여부 확인
17장
- 생성자 함수 (Construnctor)
new 연산자와 함께 호출하여 객체(인스턴스)를 생성하는 함수
- 생성자 함수의 역할
- 인스턴스를 생성
- 생성된 인스턴스를 초기화(인스턴트 프로퍼티 추가 및 초기값 할당)
- 인스턴스 생성 과정
- 암묵적으로 빈 객체, 인스턴스가 생성되고, 이 인스턴스는
this에 바인딩 된다.
- 인스턴스를 초기화 한다. 프로퍼티, 메서드 등을 추가하고 값을 할당한다.
- 인스턴스가 바인딩 된
this가 암묵적으로 반환된다.
- 만약, 명시적 반환 값이 있으면
this 반환이 무시된다.
- 명시적 반환 값이 원시 값이라면
this가 반환된다.
- 명시적 반환은 생성자 함수의 기본 동작을 훼손하기 때문에
return 문을 반드시 생략해야 한다.
- 함수가 가진 내부 슬롯 :
[[Environment]], [[FormalParameters]]
- 함수가 가진 내부 메서드 :
[[Call]], [[Construct]]
- 함수 객체는 모두 callable 하다.
- constructor 여부는 함수 정의 방식에 따라 다르다.
- 생성자 함수와 일반 함수
- 생성자 함수 (constructor)
- 함수 선언문, 표현식, 클래스
new 연산자와 함께 함수를 호출. [[Construct]] 호출
this : 인스턴스 내부
- 일반적으로 파스칼 케이스로 명명한다.
- 일반 함수 (non-constructor)
- 메서드(축약), 화살표 함수
new 연산자 없이 함수를 호출. [[Call]] 호출
this : 전역 객체 window
new.target
- 생성자 함수가 new 연산자 없이 호출되는 것을 방지하기 위해 사용. 함수 자신을 가리킨다.
- 만약, 일반 함수로 호출되면
new.target은 undefined다.
new.target을 사용할 수 없는 상황이라면 스코프 세이프 생성자 패턴을 사용하면 된다. this instanceof 함수명
- String, Number, Boolean 생성자 함수는 new 연산자와 함께 호출했을 때 객체를 생성하여 반환하지만, new 연산자 없이 호출하면 문자열, 숫자, 불리언 값을 반환한다. 이를 통해 데이터 타입을 변환하기도 한다.
18장
- 일급 객체
- 리터럴 생성 가능. 런타임 생성 가능
- 변수나 자료구조에 저장 가능
- 함수의 매개변수에 전달 가능
- 함수의 반환값으로 사용 가능
- 함수
- 일급 객체이다.
- 함수 객체의 프로퍼티 :
arguments, caller, length, name, prototype
__proto__는 Object.prototype 객체의 프로퍼티를 상속받은 것. 접근자 프로퍼티. 모든 객체가 사용 가능.
arguments
- arguments 객체를 프로퍼티 값으로 가진다.
- 인수들의 정보를 담고있는 iterable, 유사 배열 객체
- 유사 배열 객체? 배열 형태로 데이터를 담고 있지만 실제 배열은 아님. 배열 메서드 사용 불가.
- 함수 내부에서 지역 변수처럼 사용된다.
- 부족하거나 초과되더라도 모든 인수는 암묵적으로 보관된다.
- 키 : 인수의 순서, 값 : 인수 값
callee : arguments 객체를 생성한 함수
length : 인수의 개수
caller : 자신을 호출한 함수. 비표준 프로퍼티
length : 선언한 매개변수의 개수
- 인자의 개수를 가리키는
arguments의 length와는 다르다.
name : 함수의 이름. ES6부터 표준화 프로퍼티
- ES5 : 익명 함수일 때, 빈 문자열
- ES6 : 익명 함수일 때, 식별자 이름
prototype : 생성자 함수로 호출될 때, 생성할 인스턴스의 프로토타입 객체를 가리킨다. constructor만 소유할 수 있음.
19장
- 객체지향 프로그래밍
- 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임
- 객체 : 상태 데이터와 동작을 하나의 논리적인 단위로 묶은 복합적 자료구조.
- 자바스크립트는 프로토타입 기반의 객체지향 프로그래밍 언어이다.
- 상속
- 어떤 객체의 프로퍼티, 메서드를 다른 객체가 상속받아 그대로 사용할 수 있는 것.
- 자바스크립트는 프로토타입을 기반으로 상속을 구현한다.
- 프로토타입
- 객체 간 상속을 구현하기 위해 사용된다.
- 모든 객체는 하나의 프로토타입을 가지며, 모든 프로토타입은 생성자 함수와 연결되어있다.
- 객체는 내부 슬롯
[[Prototype]]에 직접 접근 불가, __proto__ 접근자 프로퍼티로 간접 접근 가능
- 프로토타입은 자신의
constructor 프로퍼티로 생성자 함수에 접근 가능, 생성자 함수는 자신의 prototype 프로퍼티로 프로토타입에 접근 가능

__proto__
- 간접적으로
[[Prototype]] 내부 슬롯의 값, 프로토타입에 접근할 수 있는 접근자 프로퍼티이다.
[[Get]], [[Set]] 프로퍼티 어트리뷰트로 구성된 접근자 프로퍼티이다.
- 객체가 직접 소유하는 프로퍼티가 아닌, Object.prototype의 프로퍼티이며, 상속을 통해 사용가능하다.
- 상호 참조에 의해 프로토타입이 생성되는 것을 방지하기 위해 접근자 프로퍼티를 통해 프로토타입에 접근한다.
프로토 타입 체인은 한쪽 방향으로만 흐르는 단방향 링크드 리스트로 구현되어야 하기 때문이다.
- => 모든 객체가
Object.prototype을 상속받는 것은 아니기 때문에 __proto__ 접근자 프로퍼티 대신 Object.getPrototypeOf 메서드와 Object.setPrototypeOf 메서드를 사용할 것을 권장한다.
- 함수 객체의 prototype 프로퍼티
- 함수 객체만 prototype 프로퍼티를 소유한다. 일반 객체는 x
- prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다.
- 생성자 함수로 호출 불가능한, non-constructor 메서드는 prototype 프로퍼티를 소유하지 않고 프로토타입도 생성하지 않는다.

- 객체의
__proto__ 접근자 프로퍼티와 함수 객체의 prototype프로퍼티는 결국 동일한 프로토타입을 가리킨다.
생성자함수.prototype === 인스턴스객체.__proto__
- 프로토타입과 생성자 함수는 항상 쌍으로 존재한다.
- 객체 생성 방식과 프로토타입의 결정
- 프로토타입은 추상연산
OrdinaryObjectCreate에 전달되는 인수에 의해 결정된다. 이 인수는 객체가 생성되는 시첨에 객체 생성 방식에 의해 결정된다.
- 객체 리터럴 :
Object.prototype
- Object 생성자 함수 :
Object.prototype
- 생성자 함수 :
생성자함수명.prototype 생성자 함수의 prototype 프로퍼티에 바인딩 된 객체
사용자 정의 생성자 함수이기에 프로토타입의 프로퍼티는 constructor 뿐이다.
- 프로토타입 체인
- 객체 -
생성자함수명.prototype - Object.prototype
- 객체의 프로퍼티에 접근 할 때, 해당 객체에 존재하지 않는다면
[[Prototype]] 내부 슬롯의 참조를 따라 부모 프로토타입의 프로퍼티를 순차적으로 검색한다.
Object.prototype은 프로토타입 체인의 종점이다. Object.prototype의 프로토타입, 즉 [[Prototype]] 내부 슬롯의 값은 null이다.
- 프로토타입 체인은 js가 객체지향 프로그래밍의 상속과 프로퍼티 검색을 구현하는 매커니즘이다.
- 스코프 체인의 경우, 식별자 검색을 위한 매커니즘이다.
me.hasOwnProperty('name')
- 스코프 체인에서 me 식별자 검색
- me 객체 프로토타입 체인에서
hasOwnProperty 메서드 검색
- 스코프 체인과 프로토타입 페인은 서로 협력하여 식별자와 프로퍼티를 검색하는 데 사용된다.
- 오버라이딩 : 상위 클래스가 가진 메서드를 하위 클래스가 재정의
- 오버로딩 : 함수 이름은 같으나 매개변수의 타입/개수가 다른 메서드. js는 지원하지 않으나
arguments로 구현 가능
- 프로퍼티 섀도잉 : 상속 관계에 의해 프로퍼티가 가려지는 현상
- 프로퍼티를 삭제하는 경우, 인스턴트 프로퍼티를 삭제하더라도 프로토타입 프로퍼티는 남아있으므로 프로토타입 프로퍼티가 호출된다.
instanceof 연산자
객체 instanceof 생성자함수 : 생성자 함수의 prototype에 바인딩 된 객체가 객체의 프로토타입 체인 상에 존재하는지 여부 확인
(constructor 프로퍼티가 가리키는 생성자 함수를 찾는 것이 아님.)
- 직접 상속 :
Object.create 메서드와 __proto__ 접근자 프로퍼티를 사용하여 직접 상속할 수 있으나 프로토타입 체인의 종점에 위치하는 객체를 생성할 수 있어서 권장하는 방법이 아니다.
Object.prototype.hasOwnProperty(...) 와 같이 간접적으로 호출하는 것이 좋다.
- 정적 프로퍼티/메서드
- 인스턴스를 생성하지 않아도, 생성자 함수로 참조/호출 할 수 있는 프로퍼티/메서드.
- 인스턴스가 호출한 인스턴스 메서드, 프로토타입 메서드 내에서 this는 인스턴스를 가리킨다. 메서드 내에서 this를 사용하지 않는다면 그 메서드는 정적 메서드로 변경할 수 있다.
- 정적 메서드 예 :
Object.is(), Object.keys, ...
- 프로토타입 메서드 예시 :
Object.prototype.hasOwnProperty(), ...
- 프로퍼티 존재 확인 연산자
in 연산자 (key in object) : 객체 고유 프로퍼티 뿐만 아니라 상속받은 프로퍼티도 확인. ES6에서 도입된 Reflect.has와 동일.
Object.prototype.hasOwnProperty : 객체 고유 프로퍼티만 확인.
- 프로퍼티 열거
for ... in 문
- 프로토타입 체인 상에 존재하는 모든 프로퍼티 중에서
[[Enumerable]]이 true인 프로퍼티를 순회하며 열거한다.
- 프로퍼티 키가 심벌인 것은 열거하지 않는다.
- 순서를 보장하지 않는다.
- 배열에는 일반적인 for문이나
for...of 문, Array.prototype.forEach 메서드를 사용하기를 권장한다.
- Object 고유 메서드
- 객체 자신의 고유 프로퍼티만 열거할 때 권장한다.
Object.keys : 열거 가능한 프로퍼티 키를 배열로 반환
Object.values : 열거 가능한 프로퍼티 값을 배열로 반환
Object.entries : 열거 가능한 프로퍼티 키와 값의 쌍의 배열을 배열로 반환
[["name", "Lee"], ["address", "Seoul"]]
21장
- 자바스크립트 객체의 분류
- 표준 빌트인 객체 : ECMAScript 사양에 정의된 객체
- 호스트 객체 : 자바스크립트 실행 환경에서 추가로 제공하는 객체
- 사용자 정의 객체 : 사용자가 직접 정의한 객체
- 래퍼 객체(wrapper object) : 원시값인 문자열, 숫자, 불리언 값에 대해 객체처럼 접근하면 생성되는 임시 객체 (
null, undefined는 래퍼 객체를 생성하지 않는다.)
- 전역 객체(global object) : 자바스크립트 엔진에 의해 가장 먼저 생성되는 최상위 객체.
- 빌트인 전역 프로퍼티 :
Infinity, NaN, undefined
- 빌트인 전역 함수 :
eval(code) : 사용하면 안됨.
isFinite(value) : 유한수 검사
isFinite(null) == isFinite(0) //true
isNaN(value) : NaN 검사. 인수가 숫자가 아니면 숫자 타입 변환 후 검사
parseFloat(string) : 문자열을 실수로 해석하여 반환
parseInt(string, radix) : 문자열을 정수로 해석하여 반환. 두 번째 인수로 몇진법인지 전달할 수 있다. default 10진수.
encodeURI(uri) : uri의 문자들을 이스케이프 처리한다.
decodeURI(encodedURI) : 인코딩 된 uri를 이스케이프 처리 이전으로 디코딩 한다.
encodeURIComponent(uriComponent) : uri 구성 요소의 문자들을 이스케이프 처리한다.
decodeURIComponent(encodedURIComponent) : 인코딩 된 uri 구성 요소를 이스케이프 처리 이전으로 디코딩 한다.
- 암묵적 전역 : 선언되지 않은 변수를 사용할 때, 자바스크립트 엔진은 전역 객체의 프로퍼티로 동적 생성하여 마치 전역 변수처럼 동작하는 것.
- 변수 선언 없이 전역 객체의 프로퍼티로 추가되었을 뿐이기에,
- 변수가 아님.
- 변수 호이스팅이 발생하지 않음.
- 프로퍼티 이기에 delete 연산자로 삭제할 수 있음.
22장
this : 자신이 속한 객체, 자신이 생성할 인스턴스를 가리키는 자기 참조 변수.
- 객체 리터럴 메서드 내부 : 메서드를 호출한 객체를 가리킨다.
- 생성자 함수 내부 : 생성할 인스턴스를 가리킨다.
=> js의 this는 호출되는 방식에 따라 동적으로 결정된다. this 바인딩은 함수 호출 시점에 결정된다.
- 함수 호출 방식에 따른
this 바인딩
- 일반 함수 호출 : "전역 객체"가 바인딩 된다. => 일반 함수에서의 this는 의미가 없다.
- 콜백 함수가 일반 함수로 호출되어도 콜백 함수 내부 this에 전역 객체가 바인딩 된다.
- 상위 객체와 this 바인딩을 일치하려면 ?
- 상위 this를 변수에 담거나
- this를 명시적으로 바인딩 할 수 있는데 메서드를 사용하거나
- 화살표 함수를 사용한다.
- 메서드 호출 : 메서드를 소유한 객체가 아닌 "호출한 객체"에 바인딩된다.
- 프로토타입 메서드에서 사용된 this도 동일하다.
- 생성자 함수 호출 : "인스턴스"가 바인딩 된다.
Function.prototype.apply/call/bind 메서드에 의한 간접 호출 : 메서드 "첫 번째 인수로 전달한 객체"가 바인딩 된다. 모든 함수가 상속받아 사용할 수 있다.
Function.prototype.apply(this객체, [인수1, 인수2 ...]) : this 바인딩 객체와 인수 리스트 배열을 사용하여 함수 호출
Function.prototype.call(this객체, 인수1, 인수2 ...) : this 바인딩 객체 뒤에 ,로 구분한 인수 리스트을 사용하여 함수 호출
Function.prototype.bind(this객체) : 함수를 호출하지 않고, this로 사용할 객체만 전달한다. 중첩 함수나 콜백 함수의 this가 불일치할 때 사용된다.
23장 실행 컨텍스트
- ECMAScript code의 타입
- 전역 코드 : 전역 변수를 관리하는 전역 스코프 생성, 전역 실행 컨텍스트 생성
- 함수 코드 : 지역 스코프 생성, 지역 변수/ 매개변수, arguments 객체 관리. 함수 실행 컨텍스트 생성
- eval 코드 : eval 실행 컨텍스트 생성
- 모듈 코드 : 모듈별로 독립적인 모듈 스코프 생성. 모듈 실행 컨텍스트 생성
- 자바스크립트 엔진은 소스코드를 "소스코드의 평가"와 "소스코드의 실행" 과정으로 나누어 처리한다.
- 소스코드 평가
- 실행 컨텍스트를 생성
- 선언문만 번저 실행하여
- 실행 컨텍스트가 관리하는 스코프에 등록
- 소스코드 실행 (= 런타임 실행)
- 변수나 함수의 참조를 스코프에서 검색하여 취득
- 실행 결과를 다시 스코프에 등록
- 실행 컨텍스트
- 식별자를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 매커니즘.
- 모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다.
- 렉시컬 환경 : 식별자와 스코프 관리
실행 컨텍스트 스택 : 코드 실행 순서 관리
- 실행 컨텍스트 스택
- 코드 평가시 생성된 실행 컨텍스트를 스택 구조로 관리한다.
- 코드가 실행되는 시간의 흐름에 따라 실행 컨텍스트가 추가되고 제거된다.
- 최상위에 존재하는 실행 컨텍스트는 언제나 현재 실행 중인 코드의 실행 컨텍스트이고, 이것을 실행 중인 실행 컨텍스트라고 부른다.
- 렉시컬 환경
- 식별자, 식별자에 바인딩된 값, 상위 스코프에 대한 참조를 기록하는 자료구조.
- 컴포넌트
- 환경 레코드(Environment Record)
식별자를 등록하고, 식별자에 바인딩 된 값을 관리하는 저장소
- 외부 렉시컬 환경에 대한 참조(Outer Lexical Environment Reference)
해당 실행 컨텍스트를 생성한 소스코드를 포함하는 상위 코드의 렉시컬 환경. 스코프 체인을 구현한다.
실행 컨텍스트의 생성과 식별자 검색 과정
var x = 1;
const y = 2;
function foo (a) {
var x = 3;
const y = 4;
function bar (b) {
const z = 5;
console.log(a + b + x + y + z);
}
bar(10);
}
foo(20); // 42
1. 전역 객체 생성
- 빌트인 전역 프로퍼티, 빌트인 전역 함수, 표준 빌트인 객체, 호스트 객체
- 전역 객체도 프로토타입 체인의 일원이기에
Object.prototype을 상속.
2. 전역 코드 평가
- 전역 실행 컨텍스트 생성
- 전역 렉시컬 환경 생성
- 전역 환경 레코드 생성
- 객체 환경 레코드 생성 :
var 키워드로 선언한 전역변수, 함수 선언문으로 정의한 전역 함수, 빌트인 전역함수, 표준 빌트인 객체 관리 => BindingObject를 통해 전역 객체의 프로퍼티와 메서드가 된다.
- 선언적 환경 레코드 생성 :
let, const 키워드로 선언한 전역변수. => 전역 객체의 프로퍼티가 되지 않음. 초기화 단계에 도달하기 전 까지 해당 변수는 일시적 사각지대에 빠진다. 
- this 바인딩 : 전역 환경 레코드의
[[GlobalThisValue]] 내부 슬롯에 this가 바인딩 된다.
- 외부 렉시컬 환경에 대한 참조 결정 : 상위 스코프

3. 전역 코드 실행
- 전역 코드가 순차적으로 실행.
- 식별자 결정 : 어느 스코프의 식별자를 참조하면 되는지 결정하는 것.
- 식별자 결정으로 위해 실행 중인 실행 컨텍스트에서 식별자를 검색하고, 만약 검색할 수 없다면 외부 렉시컬 환경에 대한 참조가 가리키는 렉시컬 환경인 상위 스코프로 이동하여 식별자를 검색한다.

4. foo 함수 코드 평가
- 함수 실행 컨텍스트 생성
- 함수 렉시컬 환경 생성
- 함수 환경 레코드 생성

- this 바인딩 : foo 함수는 일반 함수로 호출되었기에 this는 전역 객체를 가리킨다.

- 외부 렉시컬 환경에 대한 참조 : js는 함수를 어디에 정의했는지에 따라 상위 스코프를 결정한다. 즉, 자신이 정의된 상위 스코프를 기억하고, 상위 스코프를 함수 객체의 내부 슬롯
[[Environment]]에 저장한다.
5. foo 함수 코드 실행
- 실행 중인 실행 컨텍스트의 렉시컬 환경에서 식별자를 검색

6. bar 함수 코드 평가
- foo 함수 코드 평가와 동일하다.

7. bar 함수 코드 실행
- bar 함수의 소스 코드가 순차적으로 실행된다.

- console 식별자 검색 : 스코프 체인에서 검색.
bar 함수 실행 컨텍스트 -> foo 함수 실행 컨텍스트 -> 전역 렉시컬 환경에서 객체 환경 레코드의 BindingObject를 통해 전역객체에서 찾을 수 있다.
- log 메서드 검색 : console 객체의 프로토타입 체인을 통해 검색. log는 console 객체의 고유 프로퍼티이다.
- 표현식
a + b + x + y + z의 평가 : 스코프 체인을 이용하여 식별자를 검색하고 값을 가져온다.
- console.log 메서드 호출 : 표현식이 평가되어 생성한 값을 메서드에 전달하여 호출한다.
8. bar 함수 코드 실행 종료
- 더는 실행할 코드가 없으므로 bar 함수 코드 실행 종료. foo 실행 컨텍스트가 실행 중인 실행 컨텍스트가 된다. (bar 함수 실행 컨텍스트가 제거되었다고 해서 bar 함수 렉시컬 환경까지 즉시 소멸되는 것은 아니다.)

9. foo 함수 코드 실행 종료
- 전역 실행 컨텍스트가 실행 중인 실행 컨텍스트가 된다.

10. 전역 코드 실행 종료
- 실행 컨텍스트 스택에 아무것도 남아있지 않게 된다.
실행 컨텍스트와 블록 레벨 스코프
let x = 1;
if (true) {
let x = 10;
console.log(x); // 10
}
console.log(x); // 1
let, const 키워드로 선언한 변수는 모든 코드 블록을 지역 스코프로 인정하는 블록 레벨 스코프를 따른다.
- if문의 코드 블럭이 실행되면 해당 블록을 위한 블록 레벨 스코프를 생성하고, 전역 렉시컬 환경을 교체한다.

- if문의 코드 블럭 실행이 종료되면 이전의 렉시컬 환경으로 되돌린다.

24장
- 클로저 : 중첩 함수가 상위 스코프의 식별자를 참조하고 있고 외부 함수보다 더 오래 유지되는 경우에 해당 중첩 함수를 클로저라고 한다.
- 자유 변수 : 클로저에 의해 참조되는 상위 스코프의 변수.
- 클로저란
- "함수가 자유 변수에 대해 닫혀있다."
- "자유 변수에 묶여있는 함수"
- 클로저는 상위 스코프 식별자 중 기억해야할 식별자만 기억하기 때문에 메모리 점유에는 문제가 없다.
- 클로저의 활용
- 상태가 의도치 않게 변경되지 않도록 안전하게 은닉하고 특정 함수에게만 상태 변경을 허용하여 상태를 안전하게 변경하고 유지하기 위해 사용
- 주의사항 : 함수를 호출하여 함수를 반환할 때, 반환된 함수는 자신만의 독립적인 렉시컬 환경을 갖기 때문에 함수 호출을 여러번 해서는 안된다. 렉시컬 환경을 공유하는 클로저를 만들어야 한다.
- 캡슐화 : 프로퍼티와 메서드를 묶은 것
- 정보은닉 : 객체의 특정 프로퍼티나 메서드를 감추는 것. 캡슐화의 목적. 객체 간의 상호 의존성인 결합도를 낮추는 효과가 있다.
25장 클래스
- 생성자 함수와의 다른 점
- new 연산자 없이 호출하면 에러 발생
- 상속을 지원하는 extends와 super 지원
- 호이스팅이 발생하지 않는 것 처럼 동작. 클래스 선언문 이전에 일시적 사각지대에 빠짐.
- 모든 코드에 암묵적으로 strict mode 지정
- 열거 불가능
- 클래스는 메서드만 선언 가능하다.
- constructor
- 인스턴스 생성 및 초기화.
- 내부의 this는 클래스가 생성한 인스턴스를 가리킨다.
- 최대 한 개만 존재. 생략 가능
- 암묵적으로 this 반환
- 프로토타입 메서드
- 클래스 몸체에 정의한 메서드는 기본적으로 프로토타입 메서드가 된다.
- 인스턴스로 호출한다.
- 인스턴스 프로퍼티를 참조할 수 있다.
- 내부 this는 인스턴스를 가리킨다.
- 정적 메서드
- 인스턴스를 생성하지 않아도 호출할 수 있는 메서드
- static 키워드를 붙이면 된다.
- 클래스에 바인딩 된 메서드이므로, 클래스가 평가되는 시점에 함수 객체가 되므로 별다른 생성 과정이 필요없다.
- 인스턴스로 호출할 수 없다.
- 인스턴스 프로퍼티를 참조할 수 없다.
- 내부 this는 클래스를 가리킨다.
- 클래스의 인스턴스 생성 과정
- 인스턴스 생성과 this 바인딩
- 암묵적으로 빈 객체(클래스가 생성한 인스턴스) 생성
- 생성된 인스턴스는 this에 바인딩
- 인스턴스 초기화
- 인스턴스에 프로퍼티를 추가
- 인수로 전달받은 초기값으로 인스턴스 프로퍼티 값을 초기화
- 인스턴스 반환
- 인스턴스가 바인딩된 this가 암묵적으로 반환
- 프로퍼티
- 인스턴스 프로퍼티
- constructor 내부에서 this에 추가하여 정의
- 언제나 public하다.
- 접근자 프로퍼티
- 자체적으로는 값이 없고 데이터를 읽거나 저장할 때 사용하는 getter 함수와 setter 함수로 구성되어있다.
- 상속에 의한 클래스 확장
- 클래스는 기존 클래스를 상속받아 새로운 클래스를 확장하여 정의할 수 있다.
- extends 키워드
- 상속받을 클래스를 정의
- extends 키워드 앞에는 반드시 클래스가 와야하고, 뒤에는 함수 객체로 평가될 수 있는 모든 표현식을 사용할 수 있다.
- super 키워드
- 수퍼클래스의 constructor를 호출한다.
- 수퍼클래스의 메서드를 호출할 수 있다.
- 주의점
- 서브클래스의 constructor를 생략하지 않는 경우 반드시 super를 호출해야 한다.
- super 호출 전에는 this를 참조할 수 없다.
- 반드시 서브클래스의 constructor에서만 호출.
- => 서브클래스는 직접 인스턴스를 생성하지 않고 수퍼클래스에게 인스턴스 생성을 위임하기 때문이다. super가 호출되지 않으면 인스턴스가 생성되지 않으며, this 바인딩도 할 수 없다.
26장
- ES6 이후 함수 구분

- ES6 이후 메서드 : 메서드 축약 표현으로 정의된 함수. 자신을 바인딩한 객체를 가리키는 내부 슬롯
[[HomeObject]]를 갖는다.
const obj = {
x: 1,
// foo는 메서드
foo() { return this.x },
// bar는 일반 함수
bar: function() { return this.x; }
}
- 화살표 함수
const foo = (a) => a + a;
- 함수 자체의 this 바인딩을 갖지 않는다. 상위 스코프의 this를 참조하여 이를 렉시컬 this 라고 한다.
- super, arguments 또한 자체 바인딩을 가지지 않고 상위 스코프의 것을 참조한다.
- Rest 파라미터
const foo(x, y, ...rest) { }
- 함수에 전달된 인수들의 목록을 배열로 전달받는다.
- 단독으로 마지막 파라미터에서만 사용한다.
- 함수 객체의 length 프로퍼티에 영향을 주지 않는다.
- 기본값 지정이 불가능하다.
27장 배열
- 밀집 배열 : 하나의 데이터 타입, 연속적
- 희소 배열 : 동일하지 않은 메모리 공간, 불연속적
- 자바스크립트의 배열 : 인덱스를 프로퍼티 키로 가지며, length 프로퍼티를 가지는 배열의 동작을 흉내 낸 특수한 객체이다.
- 배열 생성
- 배열 리터럴
[0, 1, 2]
- Array 생성자 함수
new Array(인수 ...)
- 인수 1개, 숫자 : length 프로퍼티 값. 희소 배열
- 인수 x : 빈 배열
- 인수 2개 이상 : 해당 인수를 요소로 가진 배열
Array.of(요소 ...)
Array.from(...)
- 유사 배열 객체, 이터러블 객체를 인수로 받는다.
- 두 번째 인수로 콜백 함수를 통해 값을 만들어 요소를 채울 수 있다.
31장 정규식
- 정규식 사용법 :
/패턴/플래그
- 플래그
- i : ignore case, 대소문자 구분하지 않고 검색
- g : global, 모든 문자열 전역 검색
- m : multi line, 행이 바뀌어도 검색
- 패턴
. : 임의의 문자 1개
{m,n} : 앞선 패턴이 최소 m번, 최대 n번 반복되는 문자열
{n} : 앞선 패턴이 n번 반복되는 문자열. {n,n}과 동일
{n,} : 앞선 패턴이 최소 n번 이상 반복되는 문자열
+ : 앞선 패턴이 최소 한번 이상 반복되는 문자열. {1,}과 동일
? : 앞선 패턴이 최대 한번(0포함) 이상 반복되는 문자열.
|, [] : or. 분해되지 않은 단어 레벨 검색 시 + 함께 사용.
[]내부 - : 범위 지정
\d : 숫자. [0-9]
\D : 숫자가 아닌 문자. [^0-9]
\w : 알파벳, 숫자, 언더스코어_. [A-Za-z0-9_]
\W : 알파벳, 숫자, 언더스코어_가 아닌 문자. [^A-Za-z0-9_]
[]내부 ^ : not
[]외부 ^ : 문자열의 시작
$ : 문자열의 마지막
- 예시
- 숫자로만 이루어진 문자열 :
/^\d+$/
- 하나 이상의 공백으로 시작하는지 검사 :
/^[\s]+/
- 아이디로 사용 가능한지 검사 :
/^[A-Za-z0-9]{4,10}$/
- 핸드폰 번호 검사 :
/^\d{3}-\d{3,4}-\d{4}$/
- 특수 문자 포함 여부 검사 :
/[^A-Za-z0-9]/gi
33장 Symbol
- Symbol
- ES6에 도입된 원시 타입
- 유일한 프로퍼티 키를 만들기 위해 사용한다.
- 다른 값과 절대 중복되지 않는 유일무이한 값
- 불리언 타입 외엔 암묵적 타입변환이 일어나지 않는다.
Symbol('description') : 키를 지정할 수 없어 전역 심벌 레지스트리에 등록, 관리하지 않는다.
Symbol.for('key') : 전역 심벌 레지스트리 검색된 값 반환, 존재하지 않다면 새로 생성하여 저장한 후 저장한 값 반환.
Symbol.keyFor() : 전역 심벌 레지스트리에 저장된 심벌 키 추출.
- Well-known Symbol : 자바스크립트가 기본 제공하는 빌트인 심벌 값.
(예, 이터러블은 Symbol.iterator를 키로 갖는 메서드를 가진다.)
- 심벌 값으로 프로퍼티 키를 만들면 다른 프로퍼티 키와 절대 충돌하지 않는다.
=> 표준 빌트인 객체를 확장할 때 사용하면 어떤 프로퍼티 키와도 충돌할 위험이 없이 안전하게 확장할 수 있다.
- Symbol 도입 이유
- 중복되지 않는 상수 값 생성
- 기존에 작성된 코드에 영향을 주지 않고 새로운 프로퍼티를 추가하기 위해
=> 하위 호환성을 보장하기 위함.
34장 이터러블
- 이터레이션 프로토콜 : 순회 가능한 자료구조를 만들기 위해 정의한 규칙
- 이터러블 프로토콜
- 이터러블 : 이터러블 프로토콜을 준수한 객체. 순회할 수 있음
- 이터레이터 프로토콜
- 이터러블의
Symbol.iterator 메서드를 호출하면 이터레이터 반환
- next 메서드 소유 : next 메서드를 호출하면 이터러블을 순회하며 value와 done 프로퍼티를 갖는 이터레이터 리절트 객체를 반환한다.
- value : 현재 순회중인 이터러블의 값
- done : 순회 완료 여부
- 이터레이터는 이터러블의 요소를 탐색하기 위한 포인터 역할을 한다.
for ... of
- 이터레이터의 next 메서드를 호출하여 이터러블을 순회하면서 이터레이터 리절트 객체의 value 값을 변수에 할당한다.
- 유사 배열 객체와의 차이점
- 유사 배열 객체
- 인덱스로 프로퍼티 접근 가능, length 프로퍼티 가짐.
for ... of 문으로 순회할 수 없다.
- 이터레이션 프로토콜의 필요성
- 데이터 소비자와 데이터 공급자를 연결하는 인터페이스 역할.
- 데이터 소비자 :
for ... of, 스프레드, 배열 구조 할당, Map/Set 생성자
- 데이터 공급자 : Array, String, Map/Set, DOM 컬렉션
- 지연 평가를 통해 데이터를 생성한다.
- 데이터가 필요한 시점에 next 메서드를 통해 데이터를 생성한다.
35장 ~ 36장
- 스프레드 문법
...
- 여러 값들의 집합을 펼쳐서 개별 값의 목록으로 만든다.
- 값들의 목록이지 값이 아니기에 변수에 할당할 수 없다.
- 기본 값 설정 가능. 할당 값 우선.
- 함수의 인수 목록으로 전달하거나, 배열 리터럴 요소로 사용하거나, 객체 리터럴의 프로퍼티로 사용할 수 있다.
- 유사 배열 객체는 스프레드 문법을 사용할 수 없다.
- Rest 파라미터는 목록을 배열로 받는 것. 스프레드와 정 반대 개념이기에 주의.
- 디스트럭처링 할당 (구조 분해 할당)
const [one, two, three] = arr;
- 배열의 각 요소를 배열로부터 추출하여 변수에 할당한다.
- 할당 기준은 배열의 인덱스. 객체의 경우 key에 해당한다.
- 변수 개수와 이터러블의 요소 개수가 반드시 일치할 필요는 없다.
- 기본 값 설정 가능. 할당 값 우선.
- 객체의 프로퍼티 키와 다른 변수 이름으로 할당받으려면 다음과 같이 표기
const { 프로퍼티키 : 변경할 변수 이름 } = 객체
- 함수의 매개변수에도 사용 가능
37장 Set, Map
- Set : 중복되지 않는 유일한 값들의 집합
new Set(이터러블);
size : 요소 개수 확인. getter만 존재하는 접근자 프로퍼티.
add(값) : 요소 추가. 새 요소가 추가된 Set 반환. 연속 호출(메서드 체이닝) 가능. NaN을 같은 요소로 생각하여 중복추가 하지 않음.
has(값) : 존재 여부 확인. 불리언 반환.
delete(값) : 요소 삭제. 삭제 성공 여부 불리언 반환. 연속 호출 불가능. 삭제하려는 요소 값을 인수로 전달.
clear() : 요소 일괄 삭제. undefined 반환.
forEach(값, 값, Set객체) : 요소 순회.
- Set 객체는 수학적 집합을 구현하기 위한 자료구조로, 집합 연산을 구현하는데 주로 사용된다.
- Map : 중복되지 않은 키와 값의 쌍으로 이루어진 컬렉션.
new Map([키-값] 으로 이루어진 이터러블);
- 중복된 키를 가진 요소가 있으면 값이 덮어씌어진다.
size, add(키, 값), has(키), delete(키), clear() : Set 객체와 동일.
get(키) : 요소 취득. 존재하지 않으면 undefined 반환.
forEach(값, 키, Map객체) : 요소 순회.
- Map 객체는 이터러블이면서 동시에 이터레이터인 객체를 반환하는 메서드를 제공한다.
keys(), values(), entries()
38장 브라우저의 렌더링 과정
- 브라우저의 파싱, 렌더링 과정
- 렌더링에 필요한 리소스를 요청하고 서버로 응답을 받는다.
- 렌더링 엔진은 응답된 HTML, CSS를 파싱하여 DOM, CSSOM을 생성하고 이를 결합하여 렌더 트리를 생성한다.
- 자바스크립트 엔진은 JS를 파싱하여 AST를 생성하고 바이트코드로 변환하여 실행한다. 만약, 이 과정에서 DOM API를 통해 DOM, CSSOM을 변경한다면 다시 렌더 트리로 결합된다.
- 렌더 트리를 기반으로 레이아웃을 계산(플로우)하고, 화면에 HTML 요소를 페인팅한다.
- 브라우저의 핵심 기능
- 필요한 리소스를 서버에 요청하고 응답받아 렌더링하는 것.
- HTTP 1.1 vs HTTP 2.0
- HTTP 1.1 : 커넥션당 하나의 요청과 응답만 처리
- HTTP 2.0 : 커넥션당 여러 개의 요청과 응답이 가능. 1.1보다 로드 속도가 50% 빠르다.
- 참고) 구글 HTTP/2 소개
- HTML 파싱과 DOM 생성 (렌더링 엔진)
- HTML은 문자열로 이루어진 순수 텍스트이므로, 브라우저가 이해할 수 있는 자료구조인 DOM(Document Object Model)로 변환하여 메모리에 저장해야 한다.
- 서버의 HTML 파일이 브라우저 요청에 의해 응답된다. 이때 메모리에 저장된 바이트(2진수)를 인터넷을 경유하여 응답한다.
- 응답 헤더에 담긴 meta 태그의 charset 어트리뷰트에 저장된 인코딩 방식으로 문자열이 변환된다.
- 문법적 의미를 갖는 코드의 최소 단위인 토큰으로 분해한다.
- 객체로 변환하여 DOM을 구성하는 기본 요소인 노드를 생성한다.
- HTML 요소는 중첩 관계를 가지고, 중첩 관계에 의해 부자 관계가 형성된다. 이 관계를 반영하여 모든 노드들을 트리 자료구조, DOM으로 구성한다.
- CSS 파싱과 CSSOM 생성 (렌더링 엔진)
- CSS도 HTML과 동일한 파싱 과정을 거치며 CSSOM(CSS Object Model)을 생성한다. (바이트 -> 문자 -> 토큰 -> 노드 -> CSSOM)
- 렌더 트리 생성 (렌더링 엔진)
- 렌더 트리
- 렌더링을 위하여 렌더링 되는 노드만으로 구성된 트리 구조의 자료구조.
- 각 HTML 요소의 레이아웃을 계산하고, 페인팅하는데 사용된다.
- 리플로우, 리페인팅을 하는 경우
- 스크립트에 의한 노드 추가 삭제
- 브라우저 창 리사이징, 뷰포트 크기 변경
- 레이아웃에 변경을 발생시키는 스타일 변경
- 자바스크립트 파싱과 실행 (자바스크립트 엔진)
- 자바스크립트 엔진은 코드를 파싱하여 CPU가 이해할 수 있는 저수준 언어로 변환하고 실행하는 역할을 한다.
- 토크나이징(tokenizing) : 문자열인 코드를 어휘 분석하여 토큰으로 분해한다.
- 파싱(parsing) : 토큰의 집합을 구문 분석하여 AST(Abstract Syntax Tree, 추상적 구문 트리) 생성. AST는 토큰에 문법적 의미와 구조를 반영한 트리 구조의 자료구조이다.
- 바이트코드 생성과 실행 : AST를 중간 코드인 바이트코드로 변환하고 인터프리터에 의해 실행된다.
- 브라우저는 동기적으로 파싱하고 실행한다. 때문에 script문은 body의 가장 아래에 위치시키는 것이 좋다.
- DOM이 만들어지지 않았는데 script문 내부에서 DOM API를 이용하여 DOM을 접근하게 되면 생성되지 않아 오류가 발생하는 경우가 생긴다.
- HTML 렌더링에 지장받는 일이 없어져 페이지 로딩 시간이 단축된다.
- script 태그의 비동기적 실행을 도와주는 어트리뷰트
- 파일 "로드"가 비동기적으로 동시에 진행된다.
- async : 로드 직후 "파싱과 실행"을 동기적으로 진행한다.
- defer : DOM 생성 완료 직후 "파싱과 실행"을 동기적으로 진행한다.
39장 DOM
- DOM(Document Object Model)
- HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API를 제공하는 트리 자료구조.
- 노드 객체들로 구성된 트리 자료구조. DOM 트리라고 부르기도 함.
- DOM API를 통해 HTML의 구조나 내용, 스타일 등을 동적으로 조작할 수 있다.
- 노드 객체
- 브라우저 환경에서 추가적으로 제공하는 호스트 객체
- 노드 객체의 상속 구조

- 노드 객체의 종류
- 문서 노드 : 루트 노드로서 document 객체를 가리킴. HTML 문서당 document 객체는 유일하고, DOM 트리의 노드들에 접근하기 위한 진입점 역할을 담당한다.
- 요소 노드 : HTML 요소를 가리키는 객체. 문서의 구조를 표현한다.
- 어트리뷰트 노드 : HTML 요소의 어트리뷰트를 가리키는 객체. 부모 노드와 연결되있지 않고 요소 노드에만 연결되어있다.
- 텍스트 노드 : HTML 요소의 텍스트를 가리키는 객체. 문서의 정보를 표현한다. 리프 노드이며, DOM 트리의 최종단이다.
- Common 노드, DocumentType 노드, DocumentFragment 노드 ...
- 노드 객체 주의점들
- NodeList는 non-live 객체로 동작하지만 childNodes 프로퍼티가 반환하는 NodeList 객체는 live객체로 동작한다. 노드 객체와 상관없이 안전하게 DOM 컬렉션을 사용하려면 배열로 변환하여 사용하는 것을 권장한다.
- 사용자로부터 입력받은 데이터를 그대로 innerText 프로퍼티에 할당하는 것은 크로스 사이트 스크립팅 공격(XSS)에 취약하다. 이를 예방하기 위해 HTML 새니티제이션을 사용하는 것도 좋다. (DOMPurify 라이브러리...)
- HTML 어트리뷰트와 DOM 프로퍼티는 대부분 1:1로 대응하지만, HTML 어트리뷰트는 초기 상태를 관리하고, DOM 프로퍼티는 최신 상태를 관리한다는 차이점이 있다. 그 외의 차이점은 p743.
42장 동기, 비동기
- 동기(Synchronous) : 순서대로 처리. 실행 순서가 보장되지만 블로킹이 됨.
- 비동기(Asynchronous) : 앞 태스크가 종료하지 않아도 다음 태스크가 실행되는 것. 블로킹이 발생하지 않지만 실행 순서가 보장되지 않음.
- 브라우저 환경

- 자바스크립트 엔진
- 콜 스택 : 실행 컨텍스트 스택
- 힙 : 객체가 저장되는 메모리 공간. 구조화 되어 있지 않은 것이 특징. 실행 컨텍스트는 힙에 저장된 객체를 참조한다.
- 브라우저
- 태스크 큐 : 콜백 함수, 이벤트 핸들러 등 비동기 함수가 일시적으로 보관되는 영역
- 이벤트 루프 : 콜 스택이 비어있고, 태스크 큐에 대기 중인 함수가 있다면 이벤트 루프가 순차적으로 태스크 큐에 있는 함수를 콜스택으로 이동시킨다.
태스크 큐에 일시 보관된 함수들은 비동기 처리 방식으로 동작.
- 자바스크립트는 싱글 스레드, 브라우저는 멀티 스레드로 동작한다.
43장 ajax
- ajax : 브라우저가 서버에 비동기 방식으로 데이터를 요청하고, 수신한 데이터로 웹페이지를 동적으로 갱신하는 프로그래밍 방식. WEB Api인 XMLHttpRequest 객체를 기반으로 동작한다.
- 필요한 데이터만 받아오기 때문에 불필요한 데이터 통신이 발생하지 않는다.
- 변경할 필요가 없는 부분은 다시 렌더링 하지 않는다.
- 비동기 방식으로 동작하기 때문에 블로킹이 발생하지 않는다.
- JSON : 클라이언트와 서버간에 HTTP 통신을 위한 텍스트 데이터 포맷
- XMLHttpRequest
※ 브라우저에서 제공하는 WEB Api 이므로 브라우저 환경에서만 정상적으로 실행된다.
- open : HTTP 요청 초기화
- setRequestHEader : 특정 HTTP 요청의 헤더 값을 설정
- Content-type : 전송할 데이터의 MIME 타입 표시
- send : HTTP 요청 전송
- GET : 쿼리 문자열로 서버 전송
(페이로드로 전달한 인수는 무시, requestBody는 null)
- POST : 페이로드를 request body에 담아 전송
(데이터가 객체인 경우 JSON.stringfy로 직렬화 하여 전달)
44장 REST API
- REST : HTTP 기반, 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍처.
- RESTful : REST의 기본 원칙을 지킨 서비스 디자인
- REST API : REST를 기반으로 서비스 API를 구현한 것
- REST API 구성
- 자원(URI), 행위(HTTP 요청 메서드), 표현(페이로드)
- REST API의 설계 원칙
- URI는 리소스를 표현해야 한다.
- 리소스를 식별하는 이름은 동사보단 명사를 사용한다.
- 리소스에 대한 행위는 HTTP 요청 메서드로 표현한다.
- 요청의 종류와 목적을 알리는 방법이다.
- GET, POST, PUT, PATCH, DELETE 5가지 요청 메소드를 주로 사용.
45장 프로미스
- 콜백 패턴의 단점
- 콜백 헬 : "비동기 함수" 내부의 비동기 코드는 "비동기 함수"가 종료된 후에 완료된다. 따라서 비동기 처리 결과에 대한 후속처리하는 콜백 함수를 전달한다. 이런 콜백 함수가 중첩되어 복잡도가 높아진다.
- 에러 처리의 한계 : 에러는 호출자 방향으로 전파된다. 따라서 콜백 함수에 대한 에러는 캐치하지 못한다.
=> 이러한 문제점들을 해결하고자 프로미스가 도입된다.
- 프로미스 : 비동기 처리 상태와 처리 결과를 관리하는 객체이다.
- 비동기 처리 상태
- 수행 전
- pending (대기)
- 수행 후 (settled)
- fulfilled (성공) : resolve 함수 호출
- rejected (실패) : reject 함수 호출
- 후속 처리 메서드
- then(성공 시 호출, 실패 시 호출)
- catch(실패 시 호출)
- finally(settled 상태가 되면 호출)
=> then으로 성공, 실패 모두 전달하는 것(then 성공일 때 호출되는 콜백 함수의 에러는 잡지 못함) 보다는 then으로 성공, catch로 실패를 전달하는 것이 가독성이 좋고 명확하다.
- 프로미스 체이닝
- 후속 처리 메서드는 프로미스를 반환하기 때문에 연속적으로 호출할 수 있다. 하지만 이 부분은 계속 호출하기보다는 saync/await를 활용하는 것이 좋다.
- 정적 메서드
- resolve : 인수를 resolve하는 프로미스 생성
- reject : 인수를 reject하는 프로미스 생성
- all
- 여러 비동기 처리를 병렬 처리할 때 사용.
- 모두 fulfilled 상태가 되면 모든 처리 결과를 배열에 저장하여 프로미스 반환.
- 처리 순서가 보장된다.
- 하나라도 rejected가 되면 즉시 종료한다.
- race
- 여러 비동기 처리를 병렬 처리한다.
- 가장 먼저 fulfilled가 된 프로미스 처리 결과를 resolve하는 프로미스 반환.
- 하나라도 rejected가 되면 즉시 종료한다.
- allSettled
- 여러 비동기 처리를 병렬 처리한다.
- 모두 settled 상태가 되면 처리 결과를 배열로 반환한다.
- 마이크로태스크 큐
- 프로미스의 후속 처리 메서드의 콜백 함수가 저장되는 곳.
- 마이크로태스크 큐는 태스크큐보다 우선순위가 높다.
- 따라서 프로미스의 콜백 함수가 일반 비동기 함수의 콜백 함수, 이벤트 핸들러보다 먼저 실행된다.
- fetch
fetch(url, [options])
- Response 객체를 래핑한 프로미스 객체를 반환한다.
- URL, HTTP 요청 메서드, HTTP 요청 헤더, 페이로드 등을 설정한 객체를 전달.
46장 제너레이터와 async/await
- async/await
- 비동기 처리를 동기 처리처럼 동작하도록 구현할 수 있다.
- 프로미스를 기반으로 동작한다.
- async
- 언제나 프로미스를 반환한다.
- 주의, 클래스의 constructor 메서드는 인스턴스를 반환해야하기 때문에 async의 메서드가 될 수 없다.
- await
- 반드시 async 함수 내부에서만 사용가능.
- settled 상태가 되면 프로미스가 resolve한 처리 결과를 반환.
- 에러처리
- try... catch문 사용 가능
- catch문을 사용한 에러처리를 하지 않으면 reject하는 프로미스를 반환한다. 이를 이용하여 후속처리 메서드를 사용하여 에러를 캐치할 수도 있다.