본문 바로가기

[자바스크립트]프론트엔드 질문 모음

선배님들께 듣거나 기술 면접 때 나올만한(나왔던) 지식 정리용입니다. 주기적으로 업데이트 치는 중입니다.

목차
1. function () {} 표현식과 화살표 함수(_ => {})의 차이점은?
2. 리액트가 DOM을 업데이트하는 과정
3. 3/24에 봤던 탈탈 털린 면접 질문들 (코어 자바스크립트 + 비동기 등)
4. Javascript에서 OOP 구현하기
5. 리액트 redux
6. 이벤트 위임이란?
7. Map과 Set, 객체와의 차이점
8. 5/4 오답노트

1. function () {} 표현식과 화살표 함수(_ => {})의 차이점은?

더보기

- thisBinding 유무: function (){} 은 실행 컨텍스트에 thisBinding 존재, 화살표 함수는 thisBinding이 없어서 호이스팅처럼 가장 가까운 this를 따라감

 

- args 유무: function(){}은 인자로 모든 인수들을 담고 있는 argument array를 가지지만 화살표함수는 argument object가 없음

 

- constructable: 

If a function is constructable, it can be called with new, i.e. new User(). If a function is callable, it can be called without new (i.e. normal function call).

일반 함수 표현식은 생성자 키워드로 인스턴스를 생성할 수 있지만 화살표 함수는 호출만 가능함

 

- generator 가능 여부: function ()은 제너레이터로 사용 가능, 화살표 함수는 불가능

 

- prototype 유무: 화살표 함수는 prototype 프로퍼티가 없음

출처: https://www.tutorialspoint.com/difference-between-regular-functions-and-arrow-functions-in-javascript

2. 리액트가 DOM을 업데이트하는 과정

더보기

- 컴포넌트가 리턴하는 엘리먼트들을 트리 형태로 만들어서 관리 (일반 객체로 저장)
- 업데이트가 발생 시, 변경된 컴포넌트들의 엘리먼트로 새로 트리를 그림
- 이전의 트리와 신규 트리를 diffing 알고리즘으로 비교해서 변경된 부분만을 실제 DOM에 반영

2-1. 기존의 diffing 알고리즘은 O(n^3)의 시간 복잡도를 가지는데 빠른 이유?

더보기

몇가지 가정을 통해 O(n)에 근접하게 줄임

 

가정 1. 다른 타입의 엘리먼트는 다른 트리를 생성

가정 2. key라는 특수한 프로퍼티가 같으면 같은 엘리먼트라고 인식

 

 

상황 1. <a>가 <b>로 변경

 

아예 싹 다 갈아 엎음

 

- 기존 트리 제거

- 새 트리 생성

 

 

상황 2. A 컴포넌트안의 엘리먼트의 타입이 달라짐 (attribute가 달라지는 등)

 

바뀐 부분만 업데이트

 

- 엘리먼트 attr 비교

- 변경된 부분만 업데이트

- A 내부의 자식 컴포넌트들또한 재귀적으로 반영

 

 

상황 3. A 컴포넌트의 props가 변경됨

 

재조정을 통해 바뀐 부분만 업데이트

 

- 컴포넌트 인스턴스는 유지

- 컴포넌트 라이프 사이클을 호출하면서 props 업데이트

- render() : 이전 트리와 신규 트리 비교하여 diffing 알고리즘 적용

2-2. 리액트가 반복적인 컴포넌트 정렬에 취약한 이유와 보완책은?

더보기

내부의 자식 컴포넌트들도 재귀적으로 비교를 수행할 때 이전과 다음 자식 엘리먼트들 또한 비교를 수행하기 때문에 어렵다.

보완책으로 key라는 특수한 프로퍼티는 서브 트리에 관계없이 고유한 값을 가지기 때문에 위치 이동과 관계없이 해당 엘리먼트는 같은 엘리먼트라는것을 인식할 수 있어 불필요한 업데이트를 줄일 수 있다.

2-3. 리액트에서 불변성을 준수하면서 얻는 장점은?

더보기

1. 변화가 일어날 법한 데이터는 모두 중앙에 존재한다. 따라서 에러 발생 가능성이 적어지고 디버깅이 쉬워진다.

2. 데이터 변화가 어떤 영향을 끼칠지 예상하기 쉬워진다. 우리가 모르는 요인으로 인해 함수가 바뀔 가능성이 적어지기 때문이다.

 

When a function does not mutate objects but just returns a new object, it’s called a pure function.

 

3. 자바스크립트는 객체를 새로 생성해서 교체하는 작업이 기존의 객체를 수정하는 작업보다 빠르기 때문에 라이브러리가 코드를 최적하하기 쉽다.

[출처]

https://meetup.toast.com/posts/110

https://flaviocopes.com/react-immutability/

3/24에 봤던 탈탈 털린 면접 질문들

더보기
  1. DOCTYPE 설명

     

    브라우저에 상관없이 일관된 레이아웃을 제공할 수 있게 해줌

     

    어떤 버전의 HTML이 랜더링될 것인가를 결정하는 표준

  2. DTD 설명

    HTML5, XHTML, HTML 세가지 문서 유형이 존재.

    해당 문서 형식을 따르게 지정하는 것을 말함.

    유형에 따라 마크업 문서의 요소와 속성들을 처리하는 기준이 되며, 유효성 검사에 사용함. DTD가 생략되면 비표준모드로 랜더링되어 크로스 브라우징이 어려워진다.

    HTML4 까지의 웹 문서들은 SGML(Standard Generalized Markup Language) 기반 문서(문서용 마크업 언어를 작성하기 위한 메타 언어)를 참조하기 때문에 DTD 참조가 필요하여 필요한 식별자가 포함된 긴 문자열을 작성해야 했으나, HTML5는 SGML 기반이 아니여서 DOCTYPE선언 하나만으로 간단히 html문서를 작성할 수 있다.


    DTD: 문서형 정의 (Document Type Definition)

  3. 자바스크립트의 데이터타입에 대해 설명

    기본형 / 참조형 데이터 타입이 존재 기본형이 불변한 원리와 참조형은 왜 불변하지 않은지에 대해 설명했었음 (코어 자바스크립트 1장)

    3-1. 참조형 타입의 종류는?

    Plain Object, Array, Function, Map, Set

  4. 변수 선언 방법의 차이에 대해 설명 (var, let, const)

    var: 재선언이 가능, 함수 스코프에서 호이스팅 됨. 선언문 이전에 참조 시 undefined.

    let, const : 재선언이 되지 않음, 블록 스코프 호이스팅은 되나, undefined로 초기화 되지 않아 선언문 이전에 참조 시 Reference Error 뜸.

    let과 const의 차이는 재할당 여부의 차이.

    4-1. TDZ 설명

    선언문 이전에 참조 시 참조에러가 뜨는 이유에 해당

    변수는 선언 > 초기화 > 할당 단계를 거쳐 생성되는데 var는 선언과 초기화가 한번에 일어나지만, let은 선언과 초기화가 따로 발생하기 때문에 변수 초기화가 안된 상태에서 참조하면 에러가 발생.

    TDZ가 필요한 이유: 동적 언어의 런타임 타입 체크를 위해 필요함

  5. 호이스팅 설명 (코어 자바스크립트 2장)

    함수 호출 수 실행 컨텍스트가 생성될 때 LexicalEnvironment > environmentRecord에 선언한 변수, 함수를 선두에 저장하는 것

    변수의 경우 선언만 끌어올리고 할당은 원래 위치에서 함. 함수의 경우, 선언문은 선언문 전체를 호이스팅하지만 함수 표현식의 경우 변수 호이스팅처럼 식별자만 호이스팅되고, 실제 할당은 원래 위치에서 함.

  6. 클로저 설명 (코어 자바스크립트 5장)

    어떤 외부 실행 컨텍스트 A의 변수 b를 A의 내부 실행 컨텍스트인 C에서 변수 b를 쓰고 싶을 때 실행컨텍스트 A가 콜스택에 존재하지 않아도 변수 b를 계속해서 참조하고 있어 GC가 이루어 지지 않는 것.

    정보 은닉, 외부 변수를 내부 함수에서 사용하고 싶을 때, 부분 적용 함수 등에서 활용.

    6-1. 직접 써본 적은?

    커링 함수에서 사용함

    6-2. 커링 함수 설명

    반복적으로 사용되는 매개변수를 인자로 넘겨 내부적으로 저장하여 클로저 함수를 리턴

  7. 이벤트 전파 (Delegation) 설명

    이벤트 버블링, 캡쳐링 두 종류가 있음

    버블링: 이벤트가 발생한 하위요소부터 트리 상 최상위 요소까지 이벤트가 전파됨

    캡쳐링: 최상위요소부터 이벤트가 발생한 하위요소까지 이벤트를 탐색해서 전파

    이벤트를 등록한 요소에만 이벤트를 발생시키고 싶다면 e.stopPropagation() 호출

  8. call, apply, bind 설명 (코어 자바스크립트 3장)

    call, apply: target this를 첫번째 인자로 넘겨 함수를 실행

    bind: target this를 첫번째 인자로 넘겨 해당 this를 바인딩한 새 함수를 리턴

    8-1. call, apply의 차이 설명

    실제 함수에 필요한 인자를 넘기는 방식이 다름

    call: 두번째 인자부터 함수에 넘길 인자를 표기

    apply: 두번째 인자로 인자들의 배열을 넘겨 표기

    8-2. 인자 표현 말고도 또 다른 차이점은?

    아직도 모르겠음. 더 리서치 하기

    인자 개수를 모를 경우, apply를 사용하는게 더 적합함.

    call의 경우, ES6의 나머지 연산자로 배열을 풀어서 인자로 넘길 수도 있음.

     

  9. 프로토타입 설명 (코어 자바스크립트 6장)

    어떤 생성자로 인스턴스를 생성하면 내부에 __proto__를 생성하여 생성자의 prototype을 참조하는 프로퍼티를 자동으로 생성함.

    따라서 해당 인스턴스는 Constructor의 식별자와 메소드를 사용할 수 있음

    9-1. 프로토타입 체인 설명

    __proto__ 내부에 __proto__가 연쇄적으로 이어져 있어 최상위 프로토타입인 Object.prototype까지 연결되어 있는 형태를 프로토타입 체인이라고 함.

    이 프로토타입을 검색해나가면서 필요한 데이터를 찾는 것을 프로토타입 체이닝이라고 함.

    9-2. 직접 써본 적은?

     

    객체를 생성할 때 Object.create()의 인자로 부모 생성자 함수를 사용

    Object.create() 메소드는 주어진 객체를 프로토타입 객체로 삼아 새 객체를 리턴하는 메소드

     

     

  10. Promise 설명

    Promise는 비동기 로직을 처리하기 위한 객체로 비동기 작업이 완료된 직후에 태스크를 수행하는 것을 보장하기 위해 사용

    Promise 인자로 콜백함수를 사용할 수 있고 그 콜백함수 인자에 resolve, reject가 사용됨

    10-1. Promise pending, fullfillment 설명

    pending: Promise를 호출만 하고 반환하지 않음

    fullfilled: Promise에서 비동기 작업을 완료한 후 결과값을 반환 (resolve), fullfilled 상태가 되면 then()을 통해 값을 받을 수 있음

    rejected: 비동기 처리가 실패하여 오류가 발생(reject), 실패한 결과값(오류)을 catch()로 받을 수 있음

    10-2. [추가] Promise Chaning 이란?

    then() 메소드를 호출하게 되면 새 Promise 객체를 반환할 수 있어 연속적으로 then을 연결할 수 있음.

    10-3. Promise 에러 핸들링 설명

    reject()를 통한 catch() 이용


    then의 두번째 인자 활용

    10-4. Promise를 지원하지 않는 환경에서 어떻게 Promise를 구현?

    - 비동기 제어는 어떻게 구현?

    아직 말로 설명할 방법을 못찾음. 코드로는 찾았으니 해보기

  11. 이벤트 루프 설명

    여러 개의 스레드를 사용하는 브라우저나 Node.js 구동 환경이 자바스크립트 엔진의 단일 콜스택과 함께 동작하여 비동기 작업을 처리하기 위해 사용되는 장치

    11-1. 비동기 제어 관점에서 설명


    예제: setTimeout 실행 -> 콜 스택에 setTimeout이 추가되었다가 바로 사라짐 -> setTimeout의 콜백함수는 태스크 큐에서 대기 -> 콜 스택이 비워지면 이벤트 루프에 의해 태스크큐에서 대기 중인 콜백 함수를 콜 스택에 추가

    따라서 이벤트 루프는 콜 스택이 비었는지, 태스크 큐에 비동기로 동작하는 태스크가 있는지 반복적으로 확인

    setTimeout, addEventListener, HttpRequest 등의 모든 비동기 함수들은 이벤트 루프 사용

    11-2. 마이크로 태스크 큐 설명

    마이크로 태스크 큐는 일반 태스크 큐보다 더 높은 우선 순위를 가지고 있어 이벤트 루프는 마이크로 태스크 큐가 비었는지 먼저 확인 후 비어있으면 일반 태스크 큐가 비었는지를 확인해 마이크로 태스크 큐에서 대기 중인 함수를 우선적으로 콜스택에 추가.

    Promise의 then()의 콜백은 마이크로 태스크에 들어감


    11-3. 마이크로 태스크 큐, 태스크 큐 말고 다른 큐들에 대한 설명


    job queue, render queue, animation queue

    job queue: ECMA2015부터 Promise를 위한 큐

    render queue: 브라우저가 html, javascript, css를 변환하는 과정 (랜더링 엔진의 동작 과정)

    동작 과정

    HTML, CSS -> 각각 파싱 -> HTML: DOM 트리 생성, CSS: 스타일 트리 생성 -> Attatchment(DOM과 시각정보를 연결)을 통해 랜더링 트리 생성 및 배치(위치 결정) 작업 -> 페인트(그리기) -> 구성(Composition)

     

    animation queue(animation frame): requestAnimationFrame API에 의해 호출되는 콜백 함수가 담김.

    MicroTask Queue > Animation Frame > Task Queue 순서로 확인하면서 콜스택에 추가

    [출처]


    https://d2.naver.com/helloworld/59361
    https://velog.io/@thms200/Event-Loop-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84#event-queue-job-queue

https://mygumi.tistory.com/321 

4. Javascript에서 OOP 구현하기

4-1. OOP를 설명해보기 + 자바스크립트 구현 사례

더보기

객체지향 프로그래밍이란 실 세상(real world)에서의 일들을 객체로 모델링하여 객체들간의 상호작용을 객체들의 메소드와 속성으로 표현할 수 있는 방법을 제공합니다.

 

대표적인 특징으로는 추상화, 상속, 다형성, 캡슐화를 들 수 있습니다.

 

추상화는 대상의 공통 기능이나 속성을 묶어 하나의 이름으로 정의하는 것을 말합니다. 객체를 생성하는 것에 해당합니다.

 

상속은 객체 간의 관계를 표현하기 위해 부모의 속성과 메소드를 자식이 물려받아 자식은 부모의 속성과 메소드를 그대로 사용하면서 자신의 고유한 속성을 가질 수 있는 것을 의미합니다.

 

다형성은 같은 형태의 함수가 다른 기능을 하는 것을 의미하는데, 상속받은 기능을 확장하거나 변경할 수 있는 특징을 말합니다.

 

캡슐화란, 외부로 데이터를 노출시키지 않고 싶을 때 외부의 직접적인 접근이 아닌 함수로 접근할 수 있도록 하는 것을 의미합니다.

 

1. 추상화에서 객체를 생성한다고 했는데 자바스크립트에서 객체 생성 방법은?

더보기

1. 추상화: 추상화란, 공통의 기능이나 속성을 묶어 이름을 정의하는 것을 말합니다.

OOP에서는 클래스를 정의하는 것이 곧 추상화를 의미하는데, 자바스크립트에서는 객체를 정의하는 것이 곧 추상화입니다.

 

객체를 정의하는 방법은 리터럴 함수, 생성자 함수, 팩토리 함수, Object.create() 이렇게 총 네 가지를 들 수 있습니다.

여기에서 더욱 자세히 설명하였습니다.

 

2. 자바 스크립트에서 상속은 어떻게 표현?

더보기

2. 상속: 객체 간의 관계를 표현하기 위하여 부모에서 자식에게로 속성과 메소드를 물려받아 자식은 부모의 속성을 그대로 사용하면서 자기자신만의 고유한 속성또한 가질 수 있습니다. 자바스크립트에서는 이를 프로토타입 체인 혹은 클래스로 구현할 수 있습니다.

 

사실, 자바스크립트에서 부모 메소드나 속성을 상속받아 사용하기보다 상위 프로토타입의 메소드나 속성에 접근 권한이 생겨 이를 빌려쓴다는 개념이 더욱 확실하기도 해서 Behavior Delegation이라고도 불리기도 합니다.

 

아래는 생성자 함수로 프로토타입 체인을 구현한 사례입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function Person (name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
}
 
Person.prototype.callName = function () {
  console.log("hi, my name is "+this.name);
}
 
function Developer (name, age, gender, major, career) {
  Person.call(this, ...[name, age, gender]);
  this.major = major;
  this.career = career;
}
 
Developer.prototype = Object.create(Person.prototype);
 
function Designer (name, age, gender, major, career) {
  Person.call(this, ...[name, age, gender]);
  this.major = major;
  this.career = career;
}
 
Designer.prototype = Object.create(Person.prototype);
Designer.prototype.constructor = Designer;
 
Designer.prototype.callName = function () {
  console.log("hi, my name is "+this.name+" and I am "+this.career+"-career Designer")
}
 
var juj = new Developer('JUJ''27''FEMALE''sw''2');
 
var jhb = new Designer('JHB''26''FEMALE''Digital media Design''2');

 

ES6에서는 class를 지원하여 class의 extends와 super로 더욱 쉽게 구현할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Person {
  constructor (name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
  }
 
  callName () {
    console.log("hi, my name is "+this.name);
  }
}
 
class Developer extends Person {
  constructor (name, age, gender, major, career) {
    super(name, age, gender);
 
    this.major = major;
    this.career = career;
  }
}
 
class Designer extends Person {
  constructor (name, age, gender, major, career) {
    super (name, age, gender);
 
    this.major = major;
    this.career = career;
  }
 
  callName () {
    console.log("hi, my name is "+this.name+" and I am "+this.career+"-career Designer")
  }
}
 
const juj = new Developer('JUJ''27''FEMALE''SW''2');
const jhb = new Designer('JHB''26''FEMALE''Digital Media Design''2');

 

[출처]

https://velog.io/@cyranocoding/JavaScript%EC%97%90%EC%84%9C%EC%9D%98-OOP-Inheritance%EC%99%80-Prototype-Chain%EA%B3%BC-Class-%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-%EB%B0%8F-%EC%9D%B4%ED%95%B4-spjypizora

https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes

https://shj7242.github.io/2017/10/31/JavaScript6/

 

 

3. 자바스크립트 관점에서 다형성을 다시 설명

더보기

3. 다형성: 다형성은 같은 형태의 코드가 다른 기능을 하는것을 의미합니다.  다형성을 통해 상속으로  기능을 확장, 변경하는 것을 용이하게 해주고, 코드의 길이도 줄일 수 있습니다. 자바에서는 오버 로딩과 오버 라이딩을 통해 다형성을 지원합니다.

 

자바스크립트에서도 위의 코드에서 볼 수 있듯이 메소드 오버라이딩은 해당 객체의 프로토타입에 상위 프로토타입의 메소드와 같은 이름으로 정의하면, 프로토타입 체인에서 가장 가까운 메소드를 호출하기 때문에 상위 프로토타입의 메소드에는 접근이 더이상 불가능해집니다. 이로써 다형성을 지원할 수 있습니다.

 

[출처]

https://brunch.co.kr/@kd4/4

 

4. 자바스크립트로 캡슐화를 구현하려면?

더보기

4. 캡슐화: 필요에 따라 데이터를 외부로 노출시키면 안되는 경우, 변수와 함수를 특정 목적에 따라 묶은 것을 의미합니다. 외부에서 직접 접근이 아닌, 함수를 통해서 접근할 수 있어야 합니다.

 

자바스크립트에서는 JAVA의 private, public 키워드를 제공하고 있지는 않지만 이를 클로저를 사용하여 비슷하게 구현할 수 있습니다.

 

다음은 모듈 패턴으로 구현한 생성자 함수입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
var Developer = (function () {
  // private
  var career;
  var major;
 
  function Developer (name, c) {
    this.name = name;
    career = c ? c : 0;
  }
 
  // public
  Developer.prototype = {
    increaseCareer: function () {
      ++career;
    },
    getCareer: function () {
      return career;
    },
    setMajor: function (m) {
      major = m;
    },
    getMajor: function () {
      return major;
    },
    intro: function () {
      console.log("Hi, this is "+this.name+" and my major is "+major);
    }
  }
 
  return Developer;
})();
 
const juj = new Developer('yujeongJeon'2);
 
juj.setMajor("SW");
 
juj.intro(); // Hi, this is yujeongJeon and my major is SW
 
 

 

왜 즉시실행함수로 생성자 함수를 반환해야 할까요?

바로 생성자 함수를 정의하고 사용하게 되면,  객체의 프로토타입이 Object.prototype으로 잡혀 상속을 구현할 수 없기 때문입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
var Developer = function (name, c) {
  // public
  this.name = name;
 
  // private
  var career;
  var major;
  career = c ? c : 0;
 
  // public
  return {
    increaseCareer: function () {
      ++career;
    },
    getCareer: function () {
      return career;
    },
    setMajor: function (m) {
      major = m;
    },
    getMajor: function () {
      return major;
    },
    intro: function () {
      console.log("Hi, this is "+this.name+" and my major is "+major);
    }.bind(this)
  }
};
 
const juj = new Developer('yujeongJeon'2);
 
juj.setMajor("SW");
 
juj.intro(); // Hi, this is yujeongJeon and my major is SW
 
juj.__proto__ === Object.prototype // true
juj.__proto__ === Developer.prototype // false 

[출처]
https://88240.tistory.com/228
https://debugdaldal.tistory.com/150?category=927008

https://bkdevlog.netlify.com/posts/oop-encapsulation-of-js

5. 리액트 redux를 설명해보기

redux란 상태관리 라이브러리 중 하나로, 컴포넌트에서 상태 관련 로직들을 따로 분리하여 관리할 수 있음.

 Redux: 단일 Store, 불변적인 State, Side effect가 없는 Reducer의 3가지 원칙을 내세운 Flux 프레임워크 

5-1. 여기서 '상태'란?

로컬에서 생성하고 사용하고 있지만 아직 서버에 저장되지 않았거나 저장할 필요가 없는 값을 말함.

캐시 데이터, 서버에서 온 응답, 활성화된 라우트, 로딩 표시 여부 등의 UI 상태 등이 이에 해당한다.

5-2. redux를 사용하면 얻는 이점

1. 상태를 언제, 왜, 어떻게 업데이트해야 하는지 명확해져 상태 변화가 예측가능해짐

 

2. 두번째 원칙에 따라 뷰나 네트워크 콜백에서 결코 상태를 직접 바꾸지 못 한다는 것을 보장할 수 있어 기록을 남기거나, 직렬화하여 테스트와 디버깅을 용이하게 할 수 있고

모든 상태 변화는 중앙에서 관리되며 모든 액션은 엄격한 순서에 의해 하나하나 실행되기 때문에, 신경써서 관리해야할 미묘한 경쟁 상태는 없습니다.

3. Context API가 제공하지 못하는 기능을 리덕스 미들웨어에서 제공하는 경우가 있음 (비동기 작업, 로깅 등)

 

4. 여러 컴포넌트가 상태를 관리하게 될 때, 관련없는 컴포넌트들을 거치지 않고 바로 상태값을 전달할 수 있음.

※ redux는 옵저버 패턴으로 다수의 컴포넌트가 한 저장소를 바라보는 형태로, 상태의 변화를 여러 컴포넌트들에게 전달할 수 있음

 

5. 첫번째 원칙에 따라 하나의 상태 트리만 존재하기 때문에 디버깅이 용이

5-3. 리덕스에서 준수해야 할 원칙 세가지

1. 스토어는 글로벌 상에서 하나만 존재해야 함. == 하나의 스토어에 모든 상태가 관리되어야 함

 

2. 상태는 읽기 전용으로, 무슨 일이 발생했는지를 묘사하는 액션 객체를 전달해야만 변화할 수 있음

 

3. 변화는 순수함수로 작성

※ 리듀서: 이전 상태의 액션을 받아 다음 상태를 반환하는 순수 함수로, 이전 상태값을 변경하는게 아니라 새로운 상태값을 반환

※ 순수함수란? 외부의 개입없이 동일한 인풋값에 따라 항상 동일한 아웃풋을 반환하는 함수

[출처]

https://lunit.gitbook.io/redux-in-korean/ - 공식문서

https://velog.io/@velopert/Redux-1-%EC%86%8C%EA%B0%9C-%EB%B0%8F-%EA%B0%9C%EB%85%90%EC%A0%95%EB%A6%AC-zxjlta8ywt#%EC%95%A1%EC%85%98-%EC%83%9D%EC%84%B1%ED%95%A8%EC%88%98-action-creator

 

Redux (1) 소개 및 개념정리

리덕스 소개 리덕스는, 가장 사용률이 높은 상태관리 라이브러리입니다. 리덕스를 사용하면, 여러분이 만들게 될 컴포넌트들의 상태 관련 로직들을 다른 파일들로 분리시켜서 더

velog.io

6. 이벤트 위임이란?

하위요소에 각각 이벤트 리스너를 등록하지 않고도 상위요소에서 하위 요소들의 이벤트를 제어하는 방식

 

동적으로 요소를 추가하면 일일히 이벤트 리스너를 다시 등록해줘야 하는데, 이런 작업 없이 상위 요소에만 이벤트 리스너를 등록하면 동적으로 추가된 요소에도 같은 이벤트를 발생시킬 수 있음.

 

[출처]

https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/#%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%9C%84%EC%9E%84---event-delegation

 

이벤트 버블링, 이벤트 캡처 그리고 이벤트 위임까지

(기본) 이벤트 버블링, 이벤트 캡처링, 그리고 이벤트 위임까지 이벤트 전달 방식과 관련된 모든 것을 파헤쳐 봅니다.

joshua1988.github.io

7. Map과 Set, 객체와의 차이점

7.1 일반 객체의 불편한 점

1. 프로토타입 체인 때문에 의도하지 않은 연결이 생길 수 있다.
2. 키는 반드시 심볼이나 문자열이여야 하므로 객체를 키로 써서 값과 연결할 수 없었다.
3. 객체는 프로퍼티 순서를 전혀 보장하지 않는다.

4. 일반 객체는 iterable하지 않아 for...of로 순회하거나, spread 연산자로 풀어쓸 수 없다.

7.2 Map과 Set의 차이점

- Map: key-value 형태, key는 하나의 Map 상에서 고유해야 함. key로는 Object, function, String, Symbol을 사용할 수 있음(Number는 불가능)

- Set: value의 집합(컬렉션), 중복된 value는 한번만 들어감

8. 5/4 오답노트

8.1 immer.js는 내부적으로 어떤 API를 사용하고 있을까?

음... copy-on-write 원리로 동작하는 건 알겠는데 어떤 API 쓰는지 뜯어보기

8.2 takeLatest, takeEvery in redux-saga

공식 문서여기를 참조하여 작성함

관련 문제상황: Pagination이 적용된 게시판이 있고, 사용자가 뒤로가기랑 앞으로 가기를 빠르게 클릭하다보면, Pagination bar는 2페이지를 가리키지만, 정작 내용은 다른 페이지를 띄우는 경우가 있다. 어떻게 해결할 수 있을까?

 

redux-saga: redux로 구성한 단방향 데이터 흐름에서 비동기 로직을 더 효율적으로 관리하기 위한 미들웨어입니다. saga는 별도의 쓰레드라고 생각하여, 일반적인 redux 액션으로 실행하고 멈출 수 있습니다. redux-saga는 비동기 흐름을 ES6의 generator를 통해서 관리합니다.

redux-saga는 "Task"라는 개념을 Redux로 가져오기위한 지원 라이브러리입니다. 여기서 말하는 Task란 일의 절차와 같은 독립적인 실행 단위로써, 각각 평행적으로 작동합니다. redux-saga는 이 Task의 실행환경을 제공합니다. 더불어 비동기처리를 Task로써 기술하기 위한 준비물인 "Effect"와 비동기처리를 동기적으로 표현하는 방법을 제공하고 있습니다. Effect란 Task를 기술하기 위한 커맨드(명령, Primitive)와 같은 것으로, 예를들면 select, put, take, call, fork 같은 것들이 있습니다.

 

프로젝트에서 사용하는 주된 이유:

  • 특정 Action을 기다리다 다른 Action을 dispatch한다. (SAVE_FORM 액션이 발생하면 서버에 별도의 요청 후, 그 결과(성공/실패)에 따라 SAVE_FORM_SUCCESS, SAVE_FORM_FAILURE와 같은 액션을 dispatch하고 싶음)
  • 통신처리를 완료를 기다리고, 다른 통신처리를 시작한다.

redux-saga 동작 순서

function* handleRequestUser() {
  while (true) {
    const action = yield take(REQUEST_USER);
    const { payload, error } = yield call(API.user, action.payload);
    if (payload && !error) {
      yield put(successUser(payload));
    } else {
      yield put(failureUser(error));
    }
  }
}

export default function* rootSaga() {
  yield fork(handleRequestUser);
}
더보기
  • redux-saga의 Middleware가 rootSaga Task를 시작시킨다.
  • fork Effect로 인해 handleRequestUser Task가 시작된다.
  • take Effect로 REQUEST_USER Action이 dispatch되길 기다린다.
  • (누군가가 REQUEST_USER Action을 dispatch한다.)
  • call Effect로 API.user 함수를 불러와서 통신처리의 완료를 기다린다.
  • (통신처리가 완료된다.)
  • put Effect를 사용하여 SUCCESS_USER 혹은 FAILURE_USER Action을 dispatch한다.
  • while 루프에 따라 3번으로 돌아간다.
  • 프로젝트에서
function* authorize({ payload: { account, password } }) {
  const options = {
    account: account,
    password: password
  };
  try {
    const { data } = yield call(AuthApi.isLogin, "/api/user/login", options);
    switch (data.code) {
      case "1000":
        yield put({ type: AUTH_SUCCESS, payload: data.data });
        break;
      case "4000":
        {
          yield put({ type: AUTH_LOGOUT_COMPLETE, payload: false });
          yield put({ type: SESSION_EXPIRED });
        }
        break;
      case "9000":
        yield put({ type: AUTH_FAILURE, payload: data.data });
        break;
      case "9200":
        yield put({ type: AUTH_DISABLED, payload: "Inactive User" });
        break;
      default:
        yield put({ type: AUTH_FAILURE, payload: "Unkown Error" });
        break;
    }
  } catch (error) {
    yield put({ type: AUTH_FAILURE, payload: error.message });
  }
}

function* saga() {
  yield takeLatest(AUTH_REQUEST, authorize)
}
더보기

1. 각 AUTH_REQUEST 액션마다 authorize Task를 실행하기 위해 taskLastest 헬퍼함수를  사용합니다.

  • takeLatest: 여러개의 Task들 중 가장 마지막에 발생한 Task를 실행하며, 이전에 실행중이던 Task들은 취소합니다. 따라서 항상 마지막에 발생한 액션에 대한 결과값을 리턴함을 보장합니다.
  • takeEvery: 여러개의 autorize 인스턴스를 동시에 시작합니다. 한개 혹은 여러개의 아직 종료되지 않은 autorize 태스크들이 있더라도 새로운 autorize 태스크를 시작합니다.

2. AHTU_REQUEST 액션이 dispatch되면, call 이펙트로 API 통신 완료를 기다립니다.

3. API 통신의 envelope 코드에 따라 다음 액션을 dispatch합니다.

8.3 React Switch Component

Route컴포넌트를 감싸주면 호출된 URL컴포넌트만 호출하여 불필요한 트래픽을 방지할 수 있다.

마지막 Route컴포넌트로 404페이지를 구현할 수 있다.

참고

8.4 stopPropagation, preventDefault

- stopPropagation은 이벤트가 다른 요소에 전파되는 것을 방지

- preventDefault는 발생한 이벤트 외 별도의 브라우저 행동을 방지 (예시: a tag를 클릭 시 href="#"에 의해 페이지 상단으로 가는 경우 방지 등)


8.5 이벤트 bubbling, capturing 중에 뭐가 먼저 발생하는지?

여러 개의 eventListener가 버블링, 캡처링으로 설정되어 등록되어 있는 요소에서 capturing이 먼저 발생 후, bubbling이벤트가 실행됩니다.

여기를 참고하기

In the example below, if you click on any of the highlighted elements, you can see that the capturing phase of the event propagation flow occurs first, followed by the bubbling phase.

8.6 React Lazy Load

코드 분할을 통해 지연 로딩할 수 있음

번들링은 훌륭하지만 여러분의 앱이 커지면 번들도 커집니다. 특히 큰 규모의 서드 파티 라이브러리를 추가할 때 실수로 앱이 커져서 로드 시간이 길어지는 것을 방지하기 위해 코드를 주의 깊게 살펴야 합니다.

React.lazy는 동적으로 import된 lazy 컴포넌트를 인자로 하며, Suspense 컴포넌트 하위에서 렌더링되어야 합니다. Suspense는 lazy 컴포넌트가 로드되길 기다리는 동안 로딩 화면과 같은 예비 컨텐츠를 보여줄 수 있게 해줍니다.

8.7 Generator에 대해서

*(아스테리스크)를 함수 앞에 붙여 만드는 제너레이터 함수는 이터러블한 이터레이터인 제너레이터를 반환합니다.

제너레이터는 내부에 next 메소드를 가지고 있는데 next 메소드를 호출하면 제너레이터 함수를 실행하면서 yield 구문을 만나면 코드 실행을 일시중지하고 value와 done 속성을 가진 iterator result 객체를 반환합니다.

다시 next 메소드를 호출하면 일시중지했던 부분부터 다음 yield문까지 실행한 이터레이터 결과 객체를 반환합니다.

즉, 제너레이터는 일반함수가 전체 코드 블록을 실행하지 않고, 코드를 일부 실행하고 중지되었다가 다시 그 부분부터 실행할 수 있는 특징이 있습니다.

8.8 strict mode

"use strict" 로 설정 시 무엇이 달라지는지 알아보기

9. URL 인코딩

퍼센트 인코딩이란, url을 알파벳과 특수문자를 제외한 나머지 문자들을 옥텟으로 묶어 16진수로 표현한 것이다.

javascript는 encodeURI()와 decodeURI()를 제공하여 문자열을 퍼센트 인코딩할 수 있음

10. 프리랜더링

 

11. 리액트 reselet

[출처] https://velog.io/@valhadreams/ReactReselect

리액트 reselect 라이브러리는 리덕스 스토어로부터 데이터를 연산하여 뷰에 필요한 최소한의 데이터만을 추출할 수 있는 기능을 제공한다.

 

reselect를 사용하면 selector 내의 인자값이 하나라도 변하지 않으면 재연산되지 않아 효율적이다.

12. 프론트엔드 테스트 전략

[출처] https://meetup.toast.com/posts/174

문제 상황) 1~100까지 반복문을 순회하면서 해당 인덱스를 어떤 순수함수의 인자로 활용하는 로직을 어떻게 테스트하겠는가?