[JS-면접대비] 개념정리

Lee Jeong Min·2022년 1월 8일
59
post-thumbnail

면접대비로 JS를 다시한번 공부할 겸 블로그에 정리한 글 + 모던 deep dive책을 다시 한번 봐가면서 정리한 글입니다.

2장 - 자바스크립트란?

JS의 탄생

넷스케이프에서 웹 페이지 보조적인 기능을 위해 브라우저에서 동작하는 경량 프로그래밍 언어 도입
→ 브랜던 아이크의 자바스크립트

그러나 JScript의 출시로 인해 위기를 맞았지만 MS와 넷스케이프가 경쟁하면서 크로스 브라우징 이슈가 발생 이로 인해 JS의 필요성이 대두되어 ECMA인터내셔널에서 표준화된 JS인 ECMAScript의 탄생

Node.js

Node.js: 자바스크립트를 브라우저 이외의 환경에서 동작시킬 수 있는 런타임 환경(비동기 IO단일 스레드 이벤트루프 지원 → SPA에 적합)

JS와 ECMAScript

ECMAScript는 프로그래밍 문법의 핵심을 담당하고 자바스크립트는 일반적으로 프로그래밍 언어이면서도 클라이언트 사이드 Web API(DOM, BOM, XMLHttpRequest, Fetch)등을 아우르는 개념

JS특징

  • 웹 브라우저에서 동작하는 유일한 언어
  • 멀티 패러다임 언어
  • 프로토타입 기반 객체지향 언어

구형브라우저를 위한 바벨과 같은 트랜스파일러(컴파일러) 사용

컴파일: 한 언어로 작성된 소스 코드를 다른 언어로 변환

트랜스파일: 한언어로 작성된 소스 코드를 비슷한 수준의 추상화를 가진 다른 언어로 변환


4장 - 변수

변수

변수란 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 메모리 공간을 식별하기 위해 붙인 이름

식별자

식별자란 어떤 값을 구별할 수 있는 고유한 이름

실행 컨텍스트

실행컨텍스트를 통해 식별자와 스코프 관리

가비지 콜렉터

가비지 콜렉터란 실행컨텍스트가 종료되어 더이상 참조할 수 없는 값들을 mark-and-sweep 이라는 알고리즘으로 루트부터 시작하여 모든 객체를 돌면서 방문할 수 없는 곳(도달 가능성 기준으로 도달하지 못한곳)을 메모리에서 삭제한다.

호이스팅

변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징(var 변수만)

식별자 네이밍 규칙

식별자 네이밍 규칙으로 문자, 숫자, 언더스코어, 달러 사인을 사용할 수 있다. 대신 처음에 숫자로 시작하지는 못한다.


5장 - 표현식과 문

값이란 식이 평가되어 생성된 결과

리터럴

리터럴이란 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법

표현식

표현식이란 값으로 평가될 수 있는 문

문이란 프로그램을 구성하는 기본 단위이자 최소실행 단위

토큰

문법적인 의미를 가지고 더 이상 나눌 수 없는 코드의 기본 요소

표현식인 문과 표현식이 아닌문

→ 변수에 할당을 해보면 표현식인문과 표현식이 아닌문을 확인할 수 있다.

에버그린 브라우저

자동적으로 브라우저가 사용자에 대한 별도의 재설치를 요구하지 않고도 업데이트가 가능한 브라우저


6장 - 데이터 타입

원시타입

  • 숫자 타입(JS는 모든 수를 실수로 처리 - 배정밀도 64비트 부동 소수점)
  • 문자열 타입(템플릿 리터럴은 멀티라인 문자열, 표현식 삽입을 할 때 유용하게 사용!)
  • 불리언 타입
  • undefined 타입(개발자가 의도적으로 할당X. JS엔진이 변수를 초기화할 때 사용하는 값)
  • null 타입(개발자가 변수에 값이 없다는 것을 의도적으로 명시하는 것. 이를 통해 변수가 더이상 값을 참조하지 않고 메모리 공간에 가비지 컬렉션을 수행하게 됨)
  • 심벌 타입(변경 불가능한 원시 타입의 값, 다른 값과 중복 X)

객체타입

  • 객체
  • 함수
  • 배열

데이터 타입의 필요성

  • 값 저장 시, 확보해야 하는 메모리 크기 결정
  • 값을 읽을 시, 읽어들일 메모리 크기 결정
  • 값 해석 시, 어떻게 해석할 지 결정

정적 vs 동적

  • 정적타입: 데이터의 타입을 사전에 정의
  • 동적타입: 타입을 사전에 정의하지 않음

JS는 선언이 아닌 값의 할당에 의해 타입이 결정된다. 또한 언제든지 타입이 동적으로 변한다. 이로 인해 유연성은 높지만 변수 값을 추적하기 어려워 신뢰성이 떨어진다.


7장 - 연산자

비교연산자

  • ==(데이터 타입 바꾸어서 비교)
  • ===(타입과 값도 같은 경우 true, 그러나 NaN은 false반환)
  • Obejct.is 메서드(+0과 -0 true로 나옴)

삼항 조건 연산자

삼항 조건 연산자 표현식은 값으로 평가할 수 있는 표현식인 문이다.

typeof 연산자

피연산자의 데이터 타입을 문자열로 반환 → 그러나 null과 array를 반환하지 않음.(이를 통해 완전하게 객체의 타입이 무엇인지 확인하는것은 어려움


9장 - 타입 변환 단축 평가

타입 변환

타입 변환이란 개발자가 의도적으로 값의 타입을 변환시키는 것(명시적 타입변환이라 한다.)

JS엔진에 의해 암묵적으로 타입 자동변환 되는 것을 암묵적 타입변환이라 한다.

Falsy 값 종류

  • false
  • +0, -0
  • undefined
  • null
  • ‘’(빈 문자열)
  • NaN

단축평가

논리곱 연산자와 논리합 연산자는 피연산자 타입을 Boolean 값으로 변환하지 않고 그대로 반환하는 것

옵셔널 체이닝 연산자

?. 좌항이 null 또는 undefined이면 undefined를 반환하고 그렇지 않으면 우항의 프로퍼티 값 참조

널 병합 연산자

?? 좌항이 null 또는 undefined 이면 우항의 피연산자를 반환하고 그렇지 않으면 좌항의 피연산자를 반환한다.

isNaN과 Number.isNaN

isNaN(is not a number)은 숫자인지 아닌지를 판별하는 것

Number.isNaN(is NaN)은 NaN 그 자체인지 아닌지를 판별


10장 - 객체 리터럴

원시타입과 객체타입

원시타입은 단 하나의 값

객체타입은 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료구조

객체

객체란 0개 이상의 프로퍼티로 구성된 집합이고 프로퍼티는 key와 value로 구성된다.

자바스크립트의 객체 생성 방법

  • 객체 리터럴({})
  • Object 생성자 함수(new Object)
  • 생성자 함수
  • Object.create 메서드
  • 클래스(ES6)

메서드란?

프로퍼티 값이 함수인 경우 이것을 메서드라고 부른다.

프로퍼티 축약 표현이란?

프로퍼티키와 프로퍼티 값의 이름이 동일할 때 프로퍼티키 생략이 가능하다.


11장 - 원시 값과 객체의 비교

원시타입(불변성, 데이터의 신뢰성 보장)

  • 변경 불가능
  • 메모리에 실제 값 저장
  • 원시 값이 복사되어 전달(값에 의한 전달)

객체타입(프로퍼티 접근을 위해 히든클래스 방식)

  • 변경 가능한 값
  • 메모리에 참조 값
  • 원본의 참조 값이 복사되어 전달된다.(참조에 의한 전달)
  • 두 개의 식별자가 하나의 객체를 공유할 수 있다.

결국 메모리에 저장된 값을 복사해서 전달한다는 면에선 동일(원시 값? or 참조 값)

불변이라는 의미가 메모리에 저장된 값이 변하지 않는다는 의미이며 변수에 할당 시에 완전히 새로운 값이 만들어져 재할당 되기 때문에 데이터의 신뢰성이 보장된다.

얕은 복사 깊은 복사

객체를 복사할 때 1단계 까지만 복사하는 것을 얕은 복사라고하며 내부에 있는 모든 값들을 참조 값이 아닌 완전히 복사할 때 깊은 복사라고 한다.

객체안에 내부에 중첩된 객체가 있는 경우 얕은 복사 진행 시 참조 값으로 복사되는 것이 1단계 까지만 복사하는 것이다.

얕은복사 방법: object.assign, 전개연산자

깊은복사 방법: 재귀함수, lodash

함수의 호출 방식

call by value: 값에 의한 호출(함수 안에서 인자의 값이 변경되어도 외부 변수의 값은 변하지 않음)

  • 원시 값을 복사해서 전달

call by reference: 참조에의한 호출(함수안에서 인자의 값이 변경되면 아규먼트로 전달된 객체의 값이 변경)

  • 참조 값을 전달 → 안에 값 바뀌면 밖의 값도 바뀜

call by reference, call by value in JS

C와 C++과 같은 포인터가 있는 언어에서는 이 개념이 그대로 적용된다고 생각하지만 JS의 경우 값에 의한 전달(call by sharing이라고도 하지만 공식적인건 X)만 적용되어 실제 객체를 파라미터로 넘겼을 때 참조값에 존재하는 동일한 값이 복사되어 전달되기 때문이다.


12장 - 함수

함수 사용 이유

  • 코드의 재사용
  • 유지보수의 편의성
  • 코드의 신뢰성
  • 코드의 가독성

JS에서 함수는 일급객체!

함수 정의 방법

  • 함수 선언문
  • 함수 표현식
  • Function 생성자 함수
  • 화살표 함수

함수 선언문의 경우 JS엔진이 생성된 함수를 호출하기 위해 함수 이름과 동일한 식별자를 암묵적으로 생성하여 함수객체를 할당하여 호출할 수 있다.

함수 형태

  • 즉시 실행함수 (단 한번만 호출, 클로저 문법 시 보통 같이 사용)
  • 재귀함수(탈출 조건 필요!)
  • 중첩함수(이 또한 클로저와 연관)
  • 콜백 함수(함수의 외부에서 콜백 함수를 전달받은 것이 고차함수)
  • 순수함수, 비순수함수
    • 부수효과가 없는 함수 → 순수 함수
    • 외부 상태에 의존하거나 외부 상태를 변경하는 함수 → 비순수 함수

함수형 프로그래밍이란 순수 함수를 통해 외부 상태를 변경하는 부수효과를 최소화해서 불변성을 지향하는 프로그래밍 패러다임

객체를 불변하게 만들려면 Object.freeze() 라는 메서드를 이용하여 깊은 객체 동결을 재귀함수로 구현하여 불변한 객체를 만들 수 있다.


13장 - 스코프

스코프

스코프란 식별자가 유효한 범위를 말한다.

렉시컬 환경

코드가 어디서 실행되며 주변에 어떤 코드가 있는지를 말한다.

정적 스코프 vs 동적 스코프

정적 스코프: 어디서 정의했는지에 따라 상위스코프 결정

동적 스코프: 어디서 호출했는지에 따라 상위스코프 결정

함수의 상위스코프는 언제나 자신이 정의된 스코프이고, 함수가 호출될 때마다 함수의 상위스코프를 참조할 필요가 있기 때문에 내부슬롯 Environment에 상위 스코프를 기억한다.


14장 - 전역 변수의 문제점

호이스팅 동작 특징

호이스팅은 스코프 단위로 동작!

전역 변수의 문제점

  • 암묵적 결합: 모든 코드가 전역 변수 참조하고 변경가능
  • 긴 생명 주기: 메모리 리소스를 오랜 기간 소비
  • 스코프 체인 상의 종점에 존재: 전역 변수의 검색 속도가 가장 느림
  • 네임 스페이스 오염

15장 - let, const 키워드와 블록레벨 스코프

Var 변수

es6이전 변수를 선언하기 위해 이 키워드를 사용

  • 변수 중복 선언 허용 가능
  • 함수레벨 스코프
  • 변수 호이스팅 발생

let, const

es6에 도입된 문법으로 아래와 같은 특징

let

  • 변수 중복 선언 불가
  • 블록레벨 스코프
  • 변수 호이스팅이 발생하지 않는 것처럼 동작 → TDZ(일시적 사각지대)
  • 전역객체가 아닌 선언전 레코드 환경에서 관리

const

  • 선언과 동시에 초기화
  • 재할당이 불가능

16장 - 프로퍼티 어트리뷰트

__proto__ 접근자 프로퍼티 (프로토타입 내부 슬롯 접근이 가능함)

getOwnPropertyDescriptor & getOwnPropertyDescriptors

defineProperty & defineProperties

객체 변경 방지

Object.preventExtensions (프로퍼티 추가 금지)

확인 메서드: Object.isExtensible

Object.seal(객체 밀봉 - 읽기와 쓰기만 가능)

확인 메서드: Object.isSealed

Object.freeze(객체 동결 - 읽기만 가능)

확인메서드: Object.isFrozen

객체 동결 재귀 함수

function deepFreeze(target) {
  if(target && typeof target === 'object' && !Object.isFrozen(target)) {
    Object.freeze(target);
    
    // 모든 프로퍼티 순회
    Object.keys(target).forEach(key => deepFreeze(target[key]));
  }
  return target;
}

deepFreeze(객체);

17장 - 생성자 함수에 의한 객체 생성

생성자 함수의 인스턴스 생성 과정

  1. 빈 객체(인스턴스)를 생성하고, this를 바인딩 시켜준다.
  2. 코드가 실행되면서 this에 바인딩 되어 있는 인스턴스를 초기화 시켜준다.
  3. 완성된 인스턴스가 바인딩된 this를 반환시킨다.

생성자 함수에서 다른 객체를 반환하면 명시된 객체가 반환되고 원시값은 암묵적으로 this가 반환된다. → 따라서 내부에선 return문 반드시 생략!

모든 함수 객체는 callable 이지만 constructor일 수도 있고 non-constructor일 수도 있다.

  • constructor: 함수 선언문, 함수 표현식, 클래스
  • non-constructor: 메서드(ES6의 메서드 축약표현), 화살표함수

non-constructor를 new와 같이 호출하면 TypeError 발생!

new.target → 함수 자신을 가리킨다. 이를 사용하여 생성자 함수 역할을 제한할 수 있음

new 연산자 없이 일반 함수로서 호출된 함수 내부의 new.target은 undefined이다.

if(!new.target) { return new Circle(radius); }

스코프 세이프 생성자 패턴

if(!this instanceof Circle) { return new Circle(radius); } 

18장 - 함수와 일급 객체

일급 객체의 조건

  • 변수나 자료구조에 저장할 수 있다.
  • 함수의 매개변수에 전달할 수 있다.
  • 함수의 반환값으로 사용할 수 있다.

hasOwnProperty 메서드 → 인수로 전달받은 프로퍼티 키가 객체 고유의 프로퍼티 키인 경우에만 true이고 프로토타입 상속으로 받은 키는 false 반환

for(const key in o) {
  if(o.hasOwnProperty(key)) {
    console.log(key);
  }
}

이렇게 사용하는 것 보다 Object.hasOwnProperty.call(o, key)) 로 사용하는 것이 더 좋다고한다. o가 이 메서드를 가지고 있지 않을 수도 있기 때문!


19장 - 프로토타입

프로토타입과 객체지향

JS → 프로토타입 기반 객체지향 프로그래밍 언어(상속을 구현하는 메커니즘)

객체 지향은 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임이다.

__proto__ 접근자 프로퍼티

  • 모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 prototype에 간접적으로 접근이 가능
  • 이 프로퍼티는 상속을 통해 사용되며 객체가 소유한 프로퍼티가 아닌 Object.prototype의 프로퍼티이다.
  • 직접 프로토타입 내부슬롯에 접근하면 순환참조가 발생하여 무한루프에 빠질 수 있는데 이를 사용하여 접근하면 순환참조 되지 않게 타입에러를 발생 시킴
  • 대신 이를 직접 사용하기보다 Object.getPrototypeOf 메서드나 Object.setPrototypeOf 메서드 사용 권장

리터럴 표기법에 의해 생성된 객체의 생성자 함수와 프로토타입

가상적인 생성자 함수를 가지며 프로토타입과 생성자 함수는 단독으로 존재할 수 X → 언제나 쌍으로!

ex) object, array, function, regexp

프로토타입의 생성시점

생성자 함수가 생성되는 시점에 생성!

빌트인 생성자 함수또한 마찬가지

객체 생성 방식과 프로토타입 결정

추상 연산 OrdinaryObjectCreate에 전달되는 인수에 의해 결정된다.

사용자 정의 함수는 constructor 프로퍼티만 가지고 프로토타입을 만들기 때문에 메서드들을 직접 구현해주어야함.

프로퍼티 존재 확인

in 연산자, Reflect.has, hasOwnProperty 프로퍼티 키가 객체 고유의 프로퍼티 키인 경우 true 반환

프로퍼티 열거

for..in(enumerable이 true이고 상속받은 프로토타입의 프로퍼티까지 보여줌)

객체 고유만 보려면 Object.keys, values, entries 를 사용!


21장 - 빌트인 객체

자바스크립트 객체의 분류

  • 표준 빌트인객체: ECMAScript 사양에 정의된 객체
  • 호스트 객체: 브라우저(WepAPI), Node.js(노드 제이에스 고유 API)
  • 사용자 정의 객체: 사용자가 직접 정의한 객체

원시값과 래퍼객체

문자열, 숫자, 불리언 값에 객체처럼 접근하면 생성되는 임시 객체를 래퍼객체라고 하고 이 과정이 끝나고 다시 원시값으로 되돌린다. (Number, String, Boolean의 메서드들을 사용할 수 있게 해줌)

전역 객체

어떤 객체보다 먼저 생성되는 특수한 객체 → globalThis라는 ECMAScript 표준 전역 객체 통일 식별자가 등장


22장 - this

this

자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수이다.

this 바인딩은 함수 호출 방식에 의해 동적으로 결정!

  1. 일반함수호출 → 전역 객체 or undefined(use strict모드에서)
  2. 메서드 호출 → 메서드를 호출한 객체
  3. 생성자 함수 → 생성자 함수가 생성할 인스턴스
  4. apply/call/bind → 메서드의 첫 번째 인수로 전달할 객체

bind 메서드는 일반적으로 메서드의 this와 내부 중첩, 콜백함수의 this가 불일치하는 문제를 해결하기 위해 사용


23장 - 실행 컨텍스트

실행 컨텍스트

실행 컨텍스트는 식별자를 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 메커니즘

렉시컬 환경: 식별자와 스코프를 관리

실행컨텍스트 스택: 코드 실행 순서

반복문이 실행될 때마다 코드 블록을 위한 새로운 렉시컬 환경을 생성!


24장 - 클로저

클로저

클로저란 외부함수보다 중첩함수의 생명주기가 더 길고, 외부 함수의 변수를 참조하고 있는 함수를 클로저라고 한다.

주로 상태를 안전하게 은닉하고 특정 함수에게만 상태변경을 허용하기 위해 사용한다.

정보은닉을 하는 이유? → 결합도를 낮추고 응집도를 높이기 위함


25장 - 클래스

클래스

새로운 객체 생성의 메커니즘!

특징

  • new 연산자 없이 호출하면 에러
  • extends, super 키워드 제공
  • 호이스팅이 발생하지 않는것처럼 동작
  • 암묵적으로 strict mode
  • constructor, 프로토타입 메서드, 정적메서드 모두 enumerable 값이 false이다.
  • 일급 객체이다.

상속 클래스의 인스턴스 생성 과정

  1. 서브 클래스의 super 호출(자신이 직접 인스턴스 생성 X. 수퍼클래스에게 인스턴스 생성을 위임)
  2. 수퍼 클래스의 인스턴스 생성과 this 바인딩
  3. 수퍼클래스의 인스턴스 초기화
  4. 서브클래스 constructor로의 복귀와 this 바인딩
  5. 서브클래스의 인스턴스 초기화
  6. 인스턴스 반환

26장 - ES6 함수의 추가 기능

화살표 함수와 일반 함수의 차이

  • 화살표 함수는 인스턴스를 생성할 수 없는 non-constructor이다. 따라서 prototype 프로퍼티와 프로토타입을 생성하지 않는다.
  • 중복된 매개변수 이름을 선언할 수 없다. → strict mode에선 일반함수도 중복된 매개변수 사용 불가
  • 화살표 함수는 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않는다. → 스코프 체인을 통한 상위 스코프 요소 참조
const counter = {
  num: 1,
  increase: () => ++this.num
};

console.log(counter.increase()) // NaN

이 경우도 counter 객체안의 increase 메서드는 화살표 함수로 정의되어 있어 increase를 호출하면 객체를 가리키는 것이 아닌 전역을 참조하게 된다.

Rest 파라미터와 arguments객체

arguments객체는 유사배열 객체 → 배열 메서드 사용하려면 배열로 변환해야함

그러나 Rest파라미터는 일반 배열이기 때문에 배열메서드 바로 사용 가능


27장 - 배열

자바스크립트 배열은 배열이 아니다

일반적인 배열 → 밀집 배열(동일한 크기의 메모리 공간에 연속적으로 나열되어 있어서 offset으로 접근가능)

연속적으로 이어져 있지 않은 배열 → 희소배열

JS 배열은 요소를 위한 각각의 메모리 공간이 동일한 크기 X, 일반적인 배열의 동작을 흉내낸 객체

유사배열객체와 이터러블 객체

유사 배열 객체는 배열처럼 인덱스로 프로퍼티 값 접근 가능 → for문으로 순회 가능

이터러블 객체는 Symbol.iterator 메서드를 구현하여 for...of문, 스프레드 문법, 배열 디스트럭처링 할당의 대상으로 사용할 수 있다.

배열 고차 함수

고차 함수는 함수를 인수로 전달받거나 함수를 반환하는 함수를 말함

외부 상태의 변경이나 가변데이터를 피하고 불변성을 지향하는 함수형 프로그래밍에 기반을 둠

함수형 프로그래밍

  • 조건문과 반복문을 제거하여 복잡성을 해결하고 변수의 사용을 억제하여 상태변경을 피함
  • 순수 함수를 통해 부수효과를 최대한 억제함

forEach, filter, map, reduce

  • forEach: for문 대체할 수 있는 고차함수
  • map: 콜백 함수의 반환값들로 구성된 새로운 배열 반환
  • filter: 콜백 함수의 반환값이 true인 요소로만 구성된 새로운 배열 반환
  • reduce: 하나의 결과 값을 만들어 반환

33장 - 7번째 데이터 타입 Symbol

심벌

심벌이란 변경 불가능한 원시 타입의 값이다.

Symbol, Symbol.for, Symbol.keyFor

Symbol은 호출 시마다 유일무이한 심벌 값을 생성하지만 전역 심벌 레지스트리에서 관리 X

Symbol.for은 검색에 성공 시 검색된 심벌 값을 반환 또는 전역에서 중복되지 않은 심벌 값을 단 하나만 생성하여전역 심벌 레지스트리에 저장 후 새로운 심벌 값 반환.

Symbol.keyFor은 전역 심벌 레지스트리에 저장된 심벌 값의 키를 추출할 수 있다.

Symbol은 for...in 문으로 찾을 수 없고 Object.getOwnPropertySymbols 메서드 사용시 프로퍼티 중 심벌을 찾을 수 있다.

Symbol.iterator

자바스크립트가 기본 제공하는 빌트인 심벌 값으로 Well-known Symbol이라고 하며 for...of 문으로 순회가 가능하며 이를 호출 하면 이터레이터(next()를 소유하고 있음) 를 반환하도록 되어있다.


34장 - 이터러블

이터레이션 프로토콜

ES6에서 도입된 순회 가능한 데이터 컬렉션을 만들기 위한 규칙이다.

  • 이터러블 프로토콜: for...of, 스프레드, 디스트럭처링 할당의 대상으로 사용 가능(호출 시 next()메서드를 가진 이터레이터 반환)
  • 이터레이터 프로토콜: 안의 next()메서드 호출 시 value와 done 프로퍼티를 갖는 이터레이터 리절트 객체를 반환! → 포인터 역할

이터레이션 프로토콜의 중요성

데이터 소비자와 데이터 공급자를 연결하는 인터페이스 역할 (전에는 다양한 방법으로 순회를 할 수 있었지만 일원화 하여 효율적으로 순회 방법 관리)

무한 이터러블 지연 평가

done 프로퍼티 생략 시 무한 이터러블 생성이 가능하다.

불필요한 데이터를 미리 생성하지 않고 필요한 데이터를 필요한 순간에 생성하여 빠른 실행속도, 불필요한 메모리 소비를 하지 않고 무한도 표현 가능하다.


38장 - 브라우저의 렌더링 과정

브라우저 렌더링 과정

  1. 브라우저가 HTML, CSS, JS 등 렌더링에 필요한 리소스를 요청하고 서버로부터 응답을 받는다.
  2. 브라우저의 렌더링엔진이 HTML, CSS를 파싱하여 DOM, CSSOM을 생성하고 이들을 결합하여 렌더트리를 생성한다. (화면에 렌더링 되지 않는 노드는 퐇마하지 않는다.)
  3. 파싱 중에 script 태그를 만나게되면 그때부터 js 엔진 js 코드를 파싱하여 ast(추상구문트리)를 만들고 바이트코드로 변환을 하여 실행시킨다. 이때 JS는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 이꼬, 변경된 DOM, CSSOM은 다시 렌더트리로 결합된다.
  4. 렌더 트리를 기반으로 HTML 요소의 레이아웃을 계산하고 브라우저 화면에 paint를 하게 된다.

layout 과정은 cpu가 paint과정은 gpu가 하기 때문에 비용측면에 있어서 layout과정이 더 높다.

HTTP 1.1과 HTTP2.0

  • HTTP/1.1은 기본적으로 커넥션 당 하나의 요청과 응답을 처리 → 리소스 동시 전송 불가, 리소스의 개수에 비례하여 응답시간이 증가
  • HTTP/2 는 커넥션당 여러개의 요청과 응답, 즉 다중 요청/응답이 가능해졌다.

레이아웃이 다시 실행되는 경우

  • JS에 의한 노드 추가 또는 삭제
  • 브라우저 창의 리사이징에 의한 뷰포트 크기 변경
  • HTML 요소의 레이아웃에 변경을 발생시키는 width/height, margin, padding, border, display, position, top/right/bottom/left 등의 스타일 변경

리플로우와 리페인트

무조건 리플로우가 발생해야 리페인트가 발생하는 것은 아니다.

리플로우의 비용 > 리페인트 비용

DOM 생성 완료후 script를 호출해야하는 이유

  • DOM이 완전하지 않은 상태에서 JS가 DOM 조작 시 에러가 발생할 수 있다.
  • JS 로딩/파싱/실행으로 인해 HTML 요소들이 렌더링에 지장받는 일이 발생하지 않아야 페이지 로딩 시간이 단축된다.

script태그의 async/defer 어트리뷰트

  • async: JS 파일의 로드가 비동기적으로 동시에 진행. 다 완료되면 실행
  • defer: 마찬가지로 비동기적으로 동시에 진행. HTML 파싱이 완료된 직후(DOM 생성이 완료된 이후)에 JS 실행이 진행된다.

39장 - DOM

DOM

DOM이란 문서 객체 모델로 HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API를 제공한다.

노드 객체의 타입

  • 문서노드
  • 요소노드
  • 어트리뷰트 노드
  • 텍스트 노드

이벤트를 발생시키는 객체

EventTarget 객체

HTMLCollection과 NodeList

둘다 유사 배열 객체이면서 이터러블 이지만 노드 객체의 상태변화를 실시간으로 반영하는 살아있는 객체이다. NodeList의 대부분은 과거 정적 상태를 유지하는 non-live객체로 childNodes 프로퍼티가 반환하는 Nodelist객체는 live객체이다.

안전하게 사용하려면 둘다 배열로 변환하여 사용하는 것을 권장한다.

DOM 조작

성능최적화를 위해 주의해서 다루어야 한다.

innerHTML

사용자로부터 입력받은 데이터를 그대로 넣으면 XSS(크로스 사이트 스크립팅 공격)에 취약하다.

HTML 새니티제이션

사용자로부터 입력받은 데이터에 의해 발생할 수 있는 크로스 사이트 스크립팅 공격을 예방하기 위해 잠재적 위험을 제거하는 기능 (DOMPurify와 같은 라이브러리 존재)

insertAdjacentHTML

innerHTML 프로퍼티보다 효율적이고 빠르지만 HTML 마크업 문자열을 파싱하므로 XSS 공격에 취약하다.

DocumentFragment

노드를 추가하는 경우 여러개의 노드를 한번에 컨테이너처럼 묶어서 사용하고 싶은 경우 이 노드를 사용한다.

→ 리플로우와 리페인트 한번만 실행


40장 - 이벤트

이벤트 드리븐 프로그래밍

프로그램의 흐름을 이벤트 중심으로 제어하는 프로그래밍 방식

이벤트가 발생하여 호출될 함수를 이벤트 핸들러

이벤트 핸들러 등록방법

  • 이벤트 핸들러 어트리뷰트(js와 html의 분리가 불가능)
  • 이벤트 핸들러 프로퍼티(js와 html 분리가 가능하지만 프로퍼티 하나의 이벤트 핸들러만 바인딩 할 수 있다는 점)
  • addEventListener 메서드 방식(이벤트 핸들러 프로퍼티에 바인딩 된 이벤트 핸들러에 아무런 영향 X → 여러개의 이벤트 핸들러 등록 가능)

이벤트 핸들러 제거

removeEventListener 메서드 사용

이벤트 전파

이벤트 타깃을 중심으로 DOM 트리를 통해 전파하는 것(캡처링, 타깃, 버블링)

이벤트 위임

동일한 자식 요소들이 많거나 계속적으로 추가된다고 할때 부모요소에 이벤트 위임을 하여 타깃 검사를 통해 이벤트를 발생시킴

DOM 요소 기본 동작 조작

중단하는 메서드: preventDefault

이벤트 전파방지: stopPropagation

stopimmediatePropagation → 같은 이벤트의 다른 핸들러에게도 이벤트 전달이 멈춰진다.


41장 - 타이머

디바운스와 스로틀

디바운스는 짧은 시간 간격으로 발생하는 이벤트를 그룹화해서 마지막에 한번만 이벤트 호출

→ resize 이벤트 처리나 버튼 중복 클릭 방지처리등에 사용

스로틀은 짧은 시간 간격으로 발생하는 이벤트를 그룹화해서 일정 시간 단위로 이벤트 핸들러가 최대 한 번만 호출되도록함.

→ scroll 이벤트 처리나 무한 스크롤 구현 등에 유용하게 사용된다.


42장 - 비동기 프로그래밍

동기처리와 비동기처리

JS엔진은 싱글스레드이기 때문에 2개 이상의 함수를 동시에 실행할 수 없고 블로킹이 발생한다.

비동기 처리는 다음과 같은 과정을 가진다.

  • setTimeout 함수가 콜스택에 추가된다.
  • setTimeout 함수가 실행되면서 브라우저가 제공하는 timer Web API를 호출한다.
  • 그 이후 일정 시간이 지나면 태스크 큐에 콜백함수가 들어가게 된다.
  • 이벤트 루프가 콜스택이 비어있는지를 확인하고 태스크큐에 있는 함수를 콜스택에 넣는다.
  • 콜스택에서 콜백함수를 실행시킨다.

비동기 처리의 단점

  • 콜백 헬을 발생시켜 가독성을 나쁘게 한다.
  • 비동기 처리 중 발생하는 에러의 예외처리 곤란하다.

이벤트 루프의 역할

  • 비동기 처리시 콜 스택을 확인하여 비어있는지 체크한다.
  • 화면 갱신이 필요한지 (스크롤 이동, 어떤 요소 클릭) 판단하여 렌더링 파이프라인으로 이동

43장 - Ajax

Ajax 통신의 장점

  • 필요한 데이터만 서버로부터 전송받아 효율적
  • 순간적으로 깜빡이는 현상 없음
  • 클라이언트 서버와 통신이 비동기적으로 동작해서 블로킹이 발생하지 않는다.

44장 - REST API

HTTP의 장점을 최대한 활용할 수 있는 아키텍처이다.

restful → 이 기본원칙을 성실히 지킨 서비스 디자인

REST API의 구성

  • 자원
  • 행위
  • 표현

REST API설계원칙

  • URI는 리소스를 표현하는데 집중
  • 행위에 대한 정의는 HTTP 요청 메서드를 통해 하는 것

45장 - 프로미스

Promise

ES6에 등장한 문법으로 기존 비동기 처리의 단점을 보완하기 위해 등장하였다.

new 연산자와 함께 Promise를 호출하여 생성하고 resolve, reject 함수를 인수로 받는다.

프로미스 상태 정보를 우선 2가지로 나눌 수 있다.

pending: 비동기 처리전 수행되지 않은 상태

settled: 비동기 처리가 수행된 상태

settled 또한 2가지로 나눌 수 있다.

resolve(비동기 처리 성공), reject(비동기 처리 실패)

프로미스 후속 처리 메서드

then, catach, finally를 제공하며 마이크로태스크 큐에 저장된다.

또한 언제나 프로미스를 반환한다.

then의 두 번째 인수로 reject를 처리하는 것보다 catch로 처리하는 것이 비동기 처리에서 발생한 에러 뿐 아니라 then 내부에서 발생한 에러까지 잡아준다.

프로미스 정적 메서드

  • Promise.resolve, Promise.reject
  • Promise.all(여러 개의 비동기처리 병렬처리)
  • Promise.race(가장 먼저 fulfilled 상태가된 처리 결과를 resolve하고, reject 상태가 되면 에러를 reject하는 프로미스 반환)
  • Promise.allSettled(모두 settledt 상태가 되면 처리 결과를 배열로 반환)

마이크로 태스크 큐

프로미스의 후속 처리 메서드의 콜백함수가 담기는 곳

태스크 큐 → 비동기 함수의 콜백함수나 이벤트 핸들러가 존재하는 곳


46장 - 제너레이터와 async/await

제너레이터

ES6에서 도입되었으며 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재개할 수 있는 특수한 함수

특징

  • 함수 호출자에게 함수 실행의 제어권을 양도 가능
  • 함수 호출자와 함수 상태를 주고받을 수 있다
  • 제너레이터 함수 호출 시 제너레이터 객체 반환
function* genFunc() { yield 1; }

제너레이터 함수 호출 시 제너레이터 객체를 반환(이터러블이면서 동시에 이터레이터) next() 뿐만아니라 return, throw 메서드를 갖고 yield 표현식 까지만 실행하여 이 뒤에 오는 표현식의 평가 결과를 제너레이터 함수 호출자에게 반환한다.

이를 사용하여 비동기처리를 동기 처리처럼 구현할 수 있다.

예시

const async = generatorFunc => {
  const generator = generatorFunc();

  const onResolved = arg => {
    const result = generator.next(arg);

    return result.done ? result.value : result.value.then(res => onResolved(res));
  };
  return onResolved;
};

async(function* fetchTodo() {
  const url = 'https://jsonplaceholder.typicode.com/todos/1';

  const response = yield fetch(url);
  const todo = yield response.json();
  console.log(todo);
})();

async라는 함수에 제너레이터 함수를 전달받아 제너레이터 객체를 활용하여 동기적으로 구현한 모습이다.

Async/Await

ES8에서는 가독성 좋게 비동기 처리를 동기 처리처럼 동작할 수 있도록 async/await가 도입되었다.

async 함수는 언제나 프로미스를 반환하며 암묵적으로 반환값을 resolve하는 프로미스를 반환한다.

await 키워드는 항상 async내에서만 쓰이며, settled 상태가 되었을 때 프로미스를 resolve한 처리를 반환한다.

또한 명시적으로 호출이 가능하기 때문에 에러처리가 가능하다.(try ... catch문을 사용하여)

async함수 내에서 에러처리를 하지 않는다면 발생한 에러를 reject하는 프로미스를 반환하기 때문에 catch 후속 처리 메서드를 사용해 에러를 캐치할 수 있다.

profile
It is possible for ordinary people to choose to be extraordinary.

3개의 댓글

comment-user-thumbnail
2023년 1월 17일

딥다이브를 정리해놓으신 것같네요 너무 잘 읽었습니다.

답글 달기
comment-user-thumbnail
2023년 4월 4일

We at Escorts in Electronic, here in Bangalore, are proud to introduce a list of the best Indian escorts in the city. We have carefully selected these beautiful young girls and their outstanding service because we care about making your experience as enjoyable as possible.
https://www.thebangaloreescorts.in/escorts/electronic-city.html

답글 달기
comment-user-thumbnail
2023년 4월 13일

오 저도 딥다이브 책 보고있는데.. 정리 잘해놓으셨네요
저장해놓고 틈틈히 보겠습니다

답글 달기