추가 공부가 필요한 항목들
- 실행 컨텍스트
- 프로토타입
- mobX / Redux / contextAPI 차이
- 클로저
- 코딩테스트 문제 해결법
호이스팅
- 호이스팅(Hoisting)의 개념
함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 말한다. - 자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수를 모두 모아
유효 범위의 최상단에 선언함- 엔진 실행 순서 - 함수선언문 해석 → 변수 초기화 → 코드 실행
- 유효 범위 : 함수 블록 내
var선언과함수 선언문내에서만 호이스팅이 발생한다.let/const 변수 선언과함수표현식에서는 호이스팅이 발생하지 않는다
function foo() {
// 함수선언문
console.log("hello");
}
var foo2 = function () {
// 함수표현식
console.log("hello2");
};
- 변수에 할당된 함수표현식은 끌어올려지지 않기 떄문에 이때는 변수의 스코프 규칙을 그대로 따른다.
- 우선순위
변수 선언이 함수 선언보다 위로끌어올려진다
- 코드의 가독성과 유지보수를 위해 호이스팅이 일어나지 않도록 한다.
- 호이스팅을 제대로 모르더라도 함수와 변수를 가급적 코드 상단부에서 선언하면, 호이스팅으로 인한 스코프 꼬임 현상은 방지할 수 있다.
- let/const를 사용한다.
- var를 쓰면 혼란스럽고 쓸모없는 코드가 생길 수 있다. 그럼 왜 var와 호이스팅을 이해해야 할까?
- ES6를 어디에서든 쓸 수 있으려면 아직 시간이 더 필요하므로 ES5로 트랜스컴파일을 해야한다. 따라서 아직은 var가 어떻게 동작하는지 이해하고 있어야 한다.
화살표 함수의 경우 함수 표현식과 같이 호이스팅이 이루어지지 않는다.
클로저
- 클로저는
함수와 그 함수가 선언 됐을 때의 렉시컬 환경과의 조합이다.Lexical Environment는 코드block,function,script를 실행하기 앞서 생성되는 특별한 객체로, 실행할 스코프 범위 안에 있는 변수와 함수를 프로퍼티로 저장하는 객체다.- 즉 우리가 소스 코드를 실행하면서 참조가 필요한 변수의 값을 이 Lexical Environment 라는 객체에서 식별자 이름을 키로 찾는다고 보면 된다.
- 렉시컬 환경 - 실행 컨텍스트와의 관계
실행 컨텍스트는 실행하고 있는 함수를 트래킹하기 위한 특별한 자료 구조다. 현재 실행하고 있는 함수 내의 현재 변수 상태와 this의 값 등을 저장하고 있고, 현재 실행 중인 line을 기억하고 있다. 그래서 nested function이 호출될 때, 이미 실행하고 있는 정보를 저장해뒀기 때문에 nested function의 실행이 끝나면 다시 돌아올 수 있는 것이다.- 실행 컨텍스트는 소스 코드를 실행하기 위해 필요한 것들을 관리하는 내부 메커니즘이며, 실행 컨텍스트가 렉시컬 환경을 관리하고 있다. 위에서 실행 컨텍스트는 실행하고 있는 함수 내의 변수 상태를 저장하고 있다고 했는데, 실행 컨텍스트가 이를 렉시컬 환경이라는 객체에 저장해두고 변경이 있을 때마다 업데이트하고 필요할 때 접근해서 갖다 쓰는 것인 듯하다.
- 클로저는 반환된 내부 함수가 자신이 선언됐을 때의 환경인
스코프를 기억하여, 만일자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 스코프에 접근할 수 있는 함수를 말한다 - 스코프는 함수를 호출할 때가 아니라
어디에 선언하였는지에 따라 결정된다. 이를렉시컬 스코핑이라 한다.자신이 선언된 상위의 스코프를 모두 참조 가능하다
-
자신을 포함하고 있는 외부함수보다 내부함수가 더 오래 유지되는 경우, 외부함수 밖에서 내부함수가 호출되더라도 외부 함수의 지역변수에 접근할 수 있다. 이를 클로저라 부른다.
function outerFunc() { var x = 10; var innerFunc = function () { console.log(x); }; return innerFunc; } /** * 함수 outerFunc를 호출하면 내부 함수 innerFunc가 반환된다. * 그리고 함수 outerFunc의 실행 컨텍스트는 소멸한다. */ var inner = outerFunc(); inner(); // 10 - 클로저의 활용
현재 상태를 기억하고 변경된 최신 상태를 유지하는 특징을 가장 유용하게 사용한다.- 만약 자바스크립트에 클로저가 없다면 상태 유지를 위해 전역변수를 사용할 수밖에 없다.
- 전역 변수는 언제든지 누구나 접근이 가능하고, 변경할 수 있기 때문에 많은 부작용을 유발해 오류의 원인이 되므로 사용 억제가 필요하다
인캡슐레이션개념과 유사하게 사용이 가능하다. 클로저의 외부 함수에 선언된 변수에 직접 접근은 불가하나 해당 변수의 최신 상태를 계속 참조할 수 있기 때문이다.
- 클로저는
함수 안의 내부함수로서 외부함수의 변수를 참조 할 수 있다.- 따라서 클로저를 만들려면, 먼저 외부함수를 만들고 변수를 선언한다.
- 그리고 클로저 함수가 그 변수를 참조하도록 하면, 마치 static 정적변수나 private 변수와 같이 동작하는 변수를 만들수 있게 된다.
- 여기서 클로저 지역 변수는 함수내에서 선언해도 되고, 아규먼트로 지정해도 된다.
var / let / const의 차이점
var는 같은 변수명으로 중복 선언이 가능하며, 호이스팅이 일어난다.var으로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다.
let은 스코프 내에서 같은 변수명을 한 번만 사용 가능하며, 재할당이 가능하다.let으로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행된다.
const는 let과 유사하나, 재할당이 불가능하다.
웹 스토리지의 차이점 (쿠키 vs 로컬스토리지 vs 세션스토리지)
- 웹 스토리지는 쿠키와 비슷하게 해당 도메인과 관련된 특정 데이터를 서버가 아니라 클라이언트에 저장할 수 있도록 하는 기능이다.
쿠키- 쿠키를 사용하는 이유는 HTTP 요청은 상태를 가지고 있지 않기 때문이다.
(Stateless) - 이 말은 브라우저에서는 서버에 요청을 보낼 때 그 요청 자체로는 그 요청이 누구에게서 오는지 알 수 없고, 쿠키에 정보를 담아서 보내면 서버는 쿠키를 통해 파악할 수 있게된다
- 또한 쿠키를 통해 사용자별의 정보를 분석 할 수 있어, 요즘에는 더욱 중요한 개념이 되었다
- 쿠키의 단점
- 장기간 유지되고 브라우저 종료 후에도 유지되는 Persistent Cookie의 경우 사용자의 하드디스크에 저장된다. 그렇기 때문에 공공 PC의 경우는 쿠키를 탈취하여 개인정보를 빼돌릴 수도 있다. 이러한 보안상 취약점이 있고, 네트워크를 통해 암호화되지 않는 쿠키를 전송할 때 쿠키 정보를 탈취하는 스니핑(Sniffing) 공격에 당할 수 도 있다.
- 쿠키 역시 키-벨류 저장소인데, 만료기한도 함께 가진다. HTTP요청시 사용자의 쿠키 정보가 서버로 전달되어 사용자를 구별하곤 한다.
- 쿠키는 사이즈가 매우 작다(4kb)
- 쿠키는 매 HTTP 요청마다 포함되어 서버에 전달된다.
- 쿠키는 사용자 로컬에도 저장되고, 매 HTTP 요청마다 전달된다. 쿠키는 별도의 암호화 없이 전달되기 떄문에 로컬 또는 요청이 도청당하면 사용자 정보가 쉽게 도난당할 수 있다.
- 쿠키를 사용하는 이유는 HTTP 요청은 상태를 가지고 있지 않기 때문이다.
웹스토리지- 웹스토리지는 HTML5에서
쿠키의 단점을 보완해서 만든 기술이다.- 스토리지는 쿠키의 문제점을 보안하기 위해 나왔기 때문에 쿠키의 단점을 대부분 커버한다.
- 표준상 한 사이트당 5mb 용량이 권장된다.
- 또한, 서버에 전달되지 않기 때문에 자원 낭비에 대한 고민도 필요없다.
- 스토리지는 브라우저, 디바이스 등의 환경을 크게 타므로 없어도 되지만 있으면 좋은 기능을 구현하는 것이 좋다.
- 스토리지는 쿠키의 문제점을 보안하기 위해 나왔기 때문에 쿠키의 단점을 대부분 커버한다.
- 쿠키와 달리, 서버에 전송되지 않고 필요한 경우에만 꺼내 쓰는 것으로 자동 전송의 위험성이 적다!
- 또한, 꺼내 쓰고 싶어도
도메인 단위로 접근이 제한되는 특성 때문에 값을 꺼내 쓸 수 없다 - 쿠키와 다르게 유효기간이 존재하지 않고 대략 5MB까지 데이터를 저장 할 수 있다고 한다
- 다만, HTML5를 지원하지 않는 브라우저에서는 사용 할수 없음
로컬 스토리지브라우저를 종료해도 유지되는 데이터로, 명시적으로 지우지 않는 한영구적으로 저장- 서로 다른 브라우저 탭이라도
동일한 도메인이라면 동일한 로컬 스토리지를 사용한다. 지속적으로 필요한 정보를 저장하기에 좋다. (ex. 자동 로그인 등)
세션 스토리지- 세션 쿠키와 달리,
탭/윈도우 단위로 세션 스토리지가 생성됨- 즉 window 객체와 동일한 유효 범위 및 생존 기간을 가지며,
탭/윈도우를 닫을 시 데이터가 삭제된다.
- 즉 window 객체와 동일한 유효 범위 및 생존 기간을 가지며,
- 동일한 탭/윈도우라도 다른 도메인이라면 또 다른 세션 스토리지가 생성
- 잠시 동안 필요한 정보를 저장하기에 좋다. (ex. 입력 폼 저장, 일회성 로그인 등)
- 세션 쿠키와 달리,
- 웹스토리지는 HTML5에서
HTTP Request Method의 차이점
GET은 데이터를 요청할 때 HTTP Request Message의 헤더 부분에 URL이 담겨서 전송된다. 그래서 GET 방식은 보안에 취약점이 있다. 반면, POST는 요청 시 HTTP Request Message의 Body 부분에 데이터가 담겨서 전송된다. 따라서 데이터의 크기가 크고 URL에 데이터가 붙는 GET 방식보다 보안에서 유리하다. 그리고 GET은 조회를 할 때 쓰고 POST는 생성과 같은 작업, PUT은 자원을 업데이트할 때 쓰는 메서드이다.
GET- GET은 서버로부터 정보를 조회하기 위해 설계된 메서드이다.
- GET은 요청을 전송할 때 필요한 데이터를 Body 대신 Header에 담고 URL의 끝에 ?와 함께 이를 값으로 하는 쿼리 파라미터를 전달한다.
POST- POST는 리소스를 생성/변경하기 위해 설계된 메서드이다.
- HTTP 메시지의 Body는 길이의 제한없이 데이터를 전송할 수 있기 때문에 POST 요청은 GET과 달리 대용량 데이터 전송이 가능하다.
PUT- PUT 메서드는 기본적으로 자원의 업데이트(수정)을 담당하는 메서드이다.
- GET, PUT 요청은
멱등하다. 그러나 POST 요청은 멱등하지 않으므로 매 요청마다 다른 응답을 리턴할 수 있다. - GET, POST, PUT 요청은 근본적으로 수행하는 역할이 다르다. 조회, 생성, 수정이라는 메서드의 역할이 구분된다.
- GET은 요청 Body에 데이터가 존재하지 않으며 POST, PUT은 데이터가 존재하기 때문에 GET보다 무겁다.
CORS란?
CORS(Cross-Origin Resource Sharing)는 교차 출처 리소스 공유라는 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다.- 즉, 무분별하게 클라이언트가 다른 리소스에 접근하는 것을 막는 보안 이슈이다.
- 해결법
- 서버측에서 헤더에
Access-Control-Allow-Origin세팅을 통해 해결 - 클라이언트 측에서 Proxy 사용
- 서버측에서 헤더에
화살표 함수
- 화살표 함수는 ES6에서 새로 추가되었다.
- 화살표 함수는 익명 함수로, 이름이 없는 함수, 즉시 실행이 필요할 경우 사용하는 함수이다.
- 한 줄인 경우 return 문을 생략할 수 있는 등 간단하게 함수를 선언할 수 있다
- this 바인딩이 되지 않으므로 메소드 함수로 사용하지 않는다
바인딩- 바인딩이란,
함수 호출과 실제 함수를 연결하는 방법이다. - 함수를 호출하는 부분에서 실제 함수가 위치한 메모리를 연결하는 것도 바인딩이다.
- 바인딩은 정적 바인딩과 동적 바인딩으로 구분할 수 있다.
- 정적 바인딩은 실행 시간 전에 일어나며, 실행 시간에는 변하지 않는 상태로 유지된다.
- 동적 바인딩은 실행 시간에 일어나거나 실행 시간에 변경된다.
- 바인딩이란,
- 자바스크립트에서 모든 함수는 실행될 때마다 함수 내부에 this라는 객체가 추가된다. 일반 함수는 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는 지에 따라 동적으로 바인딩된다.
- 화살표 함수의 this는
언제나 상위 스코프의 this를 가리킨다(Lexical this) - 또한,
call,apply,bind메소드를 사용하여 this를 변경할 수없다.
- 일반 함수와 다르게 화살표 함수는 생성자 함수로 사용할 수 없다
prototype프로퍼티를 가지고 있지 않기 때문
- 일반 함수와 다르게 화살표 함수에서는 암묵적인 arguments 변수 전달이 이루어지지 않는다.
- 호이스팅이 이루이지지 않는다.
Destructuring
- 배열 또는 객체의 값을 변수로 받는 방법
- 배열의 경우
[x, y] = [1, 2]; // 이 형태로 배열형태 변수에 각각의 값을 받을 수 있다.
- 객체의 경우
const obj = { firstName: "Ungmo", lastName: "Lee" };
const { firstName, lastName } = obj;
// const {f,l} = obj; 이렇게 받을 수 없다.**
console.log(firstName, lastName); // Ungmo Lee
스코프(Scope) 와 스코프 체이닝
- 스코프는
Global(전역)과Local(지역)스코프로 나뉜다. - 스코프란
변수에 접근할 수 있는 범위 - 자바스크립트에서 함수를 선언하면 함수를 선언할 때마다 새로운 스코프를 생성한다.
- 그러므로 함수 몸체에 선언한 변수는 해당 함수 몸체 안에서만 접근할 수 있다.
- 이걸 함수 스코프(
function-scoped)라고 하며, 지역 스코프의 예이다.
- 함수 스코프 외에, 중괄호로 둘러쌓인 부분 내의 스코프인
블록 스코프도 존재한다. 스코프 체이닝- 자신을 포함하는 상위 영역으로 올라가서 자신이 원하는 대상을 찾아오는 것을 스코프 체이닝이라고 한다.
함수 영역 안에 선언된 변수가 없는 경우이다.- 이때 프로그램은 변수의 값을 찾으려고 하는데 값을 찾아가는 흐름은
- 함수 블럭 → 매개변수 → 상위 영역
자바스크립트에서 this란?
- this는 일반적으로
메소드를 호출한 객체가 저장되어 있는 속성이다. - 자바스크립트에서 this는 어떻게 호출되는지에 따라 달라진다. 즉, 함수 실행의 주체가 누구인지에 따라 다르다.
- 전역공간에서의 this
- 전역공간에서 this는 브라우저에선 window, node.js에선 global을 가리킨다. 개념상으로 전역 컨텍스트를 호출하는 주체가 전역 객체이기 때문
- 함수 호출시
- 함수 호출시 this는 브라우저에선 window, node.js에선 global을 가리킨다. 이는 자바스크립트의 특성으로, ES6+에서는 this 바인딩을 하지 않는 arrow function이 생겼다. Arrow function에서의 this는 바로 상위 컨텍스트를 가리킨다.
- 메소드 호출시
- 메소드 호출시 this는 메소드의 호출 주체(메소드명 앞)이 된다.
- callback에서의 this는 기본적으로 함수내부에서의 호출과 동일하다.
- 생성자함수 호출시
- new 키워드를 통해 생성자함수 호출시 this는 인스턴스를 가리킨다.
- 즉, 생성자함수 호출시 객체가 만들어지고, 객체가 this가 되는 것.
- 이벤트 리스너 내에서는
- 이벤트를 발생시킨 객체
- 전역공간에서의 this
프로미스 패턴
- 기본적으로 비동기로 동작하는 자바스크립트를 동기 동작시키기 위해 기존에 사용하던 callback을 개선하기 위해 나온 개념이다.
- 프로미스는
fulfilled(처리 완료)- 작업 성공rejected(거부 됨)- 작업 실패pending(보류 됨)- 작업 시작 전settled(해결 됨)- 처리 완료 혹은 거부 됨- 네 가지 상태를 가지며, 다음과 같이 동작한다.

- 프로미스가 선언된 순간부터
pending상태가 된다. - 프로미스의 목적이 충족(fulfilled)되면,
then()함수가 호출된다. - 프로미스의 동작 중 오류가 발생하거나 문제가 있어 거부(reject)되면,
catch()함수가 호출된다. - 프로미스가
fulfilled되거나reject된 이후의 상태를settled된 상태라고 한다.
-
프로미스 생성은
new Promise(function(resolve, reject) { ... }- 의 형태로 선언한다.
- 프로미스 내부 동작이 성공하면
resolve를 호출하고, 실패하면reject를 호출한다.
- 여러 개의 프로미스 객체를
then()으로 연결하여 사용하는 것을프로미스 체이닝이라고 하며, 여러 동작을 순차적으로 수행하기 위해 사용한다. - 여러 개의 프로미스를 한 번에 묶어서 수행하고,
모든 프로미스가 resolve되었을 때 결과를 보여주는Promise.all()함수도 존재한다.
비동기 함수(async/await)
- Promise를 사용한다고 해도 어쩔 수 없는 한계가 존재한다.
- 콜백 함수에 비해 나아졌다고는 하나, 중첩 사용하거나 return으로 함수를 호출하면서 로직이 복잡해지면 가독성이 떨어진다.
- 하지만 async/await을 사용한다고 해서 프로미스를 완전히 대체할 수 있는 것은 아니다.
- 사용법
asyncasync키워드를 사용하여 정의된 함수는 항상 프로미스를 반환한다.- 따라서 함수 호출 뒤에
then으로 체이닝이 가능하다. - 리턴값이 프로미스라면 그대로 반환된다.
await- await은
async 함수 내부에서만사용된다. - await 키워드를 붙여 프로미스를 사용하면, 해당 프로미스가 처리 완료될 때 까지 기다린다.
- await은
이벤트 캡쳐링 / 이벤트 버블링
이벤트 캡쳐링(Event Capturing)- HTML 문서의 최상위 단계인 <html></html> 부터 제일 안 쪽에 위치한 태그까지 순차적으로 읽어가며 해당 태그에 이벤트가 할당되었는지를 검색한다.
- 이렇게
외부에서부터 내부로이벤트를 검색해나가는 것을 이벤트 캡쳐링이라고 하며, 명시적으로 이벤트 캡쳐링 단계에서 이벤트가 실행되도록 설정하지 않는 한 기본적으로 이 단계에서는 이벤트의 종류가 뭐뭐 있고, 어떤 태그에 할당되어 있는지만 검색한다.
- 이렇게
- HTML 문서의 최상위 단계인 <html></html> 부터 제일 안 쪽에 위치한 태그까지 순차적으로 읽어가며 해당 태그에 이벤트가 할당되었는지를 검색한다.
이벤트 버블링(Event Bubbling)본격적인 이벤트 실행이 발생하는 단계가 이벤트 버블링이다.- 이벤트 버블링 단계에서는 이벤트 캡쳐링과 정 반대의 순서로 정 반대의 일이 진행된다.
- 이벤트 캡쳐링에서 검색한 이벤트들을 좁은 범위에서부터 넓은 범위로 하나하나 넓혀가며 할당된 이벤트를 실행한다.
- 이벤트는 항상
캡쳐링이 먼저, 버블링이 나중에 실행된다.- 모던 브라우저에서 모든 이벤트 핸들러는 버블링 단계에 등록된다.
- 즉, 명시적으로 addEventListener와 같은 이벤트 핸들러에 캡쳐링 단계에서 이벤트 실행이 발생하도록 등록하지 않는다면, 버블링 단계에 이벤트가 실행된다.
- 하지만 모든 이벤트가 버블링 단계에 실행되는 것은 아니다
- 예로, focus와 같은 이벤트는 버블링이 발생하지 않는다.
이벤트 캡쳐링(Event Capturing)은 넓은 범위에서부터 좁은 범위로 이동하며 HTML 태그에 할당된 이벤트를 읽어들이는 역할만 수행하고,이벤트 버블링(Event Bubbling)은 좁은 범위에서 넓은 범위로 이동하며 각 태그에 할당된 이벤트를 실행하는 역할을 수행한다.
이벤트 위임(Event Delegation)
- 이벤트 버블링으로 인해 가장 하위 태그에 선언된 이벤트는 그 부모 태그에서도 감지된다.
- 이를 인지하지 못하고 사용한 경우, 가장 하위 태그에서 동작시키기 위해 선언한 이벤트가 그 부모 태그들에서도 동작된다…
- 하지만, 이를 반대로 생각하면, 가장 하위 태그의 이벤트를 발생시킴으로써 그 부모 태그의 이벤트들도 실행할 수 있다는 이야기가 된다.
- 비슷한 이벤트를 다룰 경우,
공통된 조상 태그에 하나의 이벤트 핸들러를 할당해도 여러 요소의 이벤트를 다룰 수 있다는 것이 이벤트 위임의 핵심이다!! - 즉, 컨테이너에서 가장 최상위 위계를 가진 태그에 모든 이벤트를 등록하고 선택된 이벤트를 실행하는 것이 이벤트 위임
- 이벤트 위임 작동 순서
- 컨테이너에 하나의 핸들러를 할당한다.
- event.target 변수를 통해 이벤트가 발생한 요소를 검색한다.
- 이벤트가 발생하면 그 요소에 할당된 이벤트를 실행한다.
- 이벤트를 위임을 사용하는 방법
stopPropagation()메서드를 사용한다- 이벤트 버블링을 멈춘다!
- 이 메서드가 사용되면, 더이상 해당 메서드를 호출한 컨테이너의 상위 컨테이너에서는 이벤트가 인식되지 않는다.
event.target에 조건을 붙여, 조건에 부합하는 이벤트만 실행- 이벤트 발생을 원하는 조건에서만 이벤트가 수행되도록 명시적으로 선언한다.
- 장점
- 핸들러를 여러 개 사용하지 않아도 원하는 이벤트를 실행시킬 수 있다는 점에서
메모리를 절감할 수 있다. 유지보수측면에서 장점을 가진다(공통 핸들러만 수정하면 되므로)
- 핸들러를 여러 개 사용하지 않아도 원하는 이벤트를 실행시킬 수 있다는 점에서
자바스크립트의 프로토타입
- 자바스크립트는
프로토타입 기반의 언어이다.- 이는 클래스 기반 언어와는 다른 것으로,
‘상속'의 기능을 제공하지 않는다. - 하지만, 프로토타입을 이용해 특정 객체를 원형으로 삼고, 이를 복제하는 방식으로 상속과 같은 기능을 만들어 낸다.
- 이는 클래스 기반 언어와는 다른 것으로,
자바스크립트의 이벤트 루프☠️☠️☠️☠️☠️
- 자바스크립트는 그 자체로 실행되지 않으며, 실행을 위한 특정 엔진이 필요하다
- 하나의 예로, Chrome에 내장된 V8
- V8은 크게 두 가지 요소로 나뉜다
Heap- 메모리 할당이 이루어지는 공간
Call Stack- 실행되어야 하는 작업이 쌓이는 공간
Single-Thread이기 때문에, 한번에 하나의 작업만 수행 가능하다.- 함수 실행 call 이 이루어지는 순간, 해당 함수는 call stack 에 담기며, 함수 내부의 순서에 따른 실행 순서대로 stack 에 계속 작업할 내역이 쌓이게 된다.
- Stack 에 더 이상 담을 수 있는 call 이 없다면, 나중에 들어온 작업부터 실행이 되어 Stack 을 빠져나간다.
- Stack 에 있는 작업이 실행되는 시간이 매우 길다면? 이 현상이 바로
Blocking이다. - 이러한 Blocking 현상 해소를 위해 사용할 수 있는 간단한 해결책이 바로 비동기 함수이다.
- 작업 시간이 오래 걸리는 경우, Call Stack이 아닌 다른 영역에서 작업하도록 한다.
- V8은 크게 두 가지 요소로 나뉜다
- 하나의 예로, Chrome에 내장된 V8
- 비동기 함수를 실행하는 다른 영역?
Event Loop- 이벤트 루프는 런타임 환경에 내장된 여러 장치들과 자바스크립트 엔진을 활용해 비동기 처리를 하는 일종의 동작 시스템.
- 자바스크립트 런타임은 한 번에 한 가지 작업만 수행할 수 있지만, 브라우저에서 제공하는 Web API 덕분에 비동기 함수를 병렬적으로 처리할 수 있게 된다.
- Event Loop의 역할
- Event Loop 의 역할은,
Task Queue와Call Stack을 꾸준히 감시하는 것이다. - 스크립트 실행 중 Stack 에 들어온 동기 함수는 바로 실행되어 Stack 을 빠져나가지만, 비동기 함수는 브라우저의 Web Api 로 이동해 이 공간에서 작업을 진행한다.
- 그리고 비동기 함수의 작업이 완료되는 순간 브라우저의 “
Task Queue“ 라는 공간으로 들어간다.- 이벤트 루프는 Queue 와 Stack 을 계속 지켜보다가, Stack이 비었다는 것을 알아차리는 순간, Task Queue 에 들어온 첫 번째 요소부터 순서대로 다시 Stack 에 올려 함수가 실행되도록 한다.

- 이벤트 루프는 Queue 와 Stack 을 계속 지켜보다가, Stack이 비었다는 것을 알아차리는 순간, Task Queue 에 들어온 첫 번째 요소부터 순서대로 다시 Stack 에 올려 함수가 실행되도록 한다.
- Event Loop 의 역할은,
실행 컨텍스트(Execution Context)☠️☠️☠️☠️☠️
https://prefer2.tistory.com/entry/Javascript-실행컨텍스트-Execution-Context
- 실행 컨텍스트는
실행 가능한 코드에 제공할 환경 정보들을 모아놓은 객체를 말한다. 따라서, 우리가 코드를 작성하고 실행하게 된다면 실행 컨텍스트 내부에서 실행되고 있는 것이다. 여기서 말하는 실행 가능한 코드는전역 코드: 전역 영역에 존재하는 코드함수 코드: 함수 내에 존재하는 코드Eval 코드:eval함수로 실행되는 코드block 코드: while, if , for, function 등에서 만들어지는 {} 코드
- 자바스크립트 엔진은 코드를 실행하기 위해 여러 가지 정보를 알고 있어야 한다.
- 변수: 전역 변수, 지역 변수, 매개 변수, 객체의 프로퍼티
- 함수 선언
- 변수의 유효 범위(Scope)
- this
- 실행 컨텍스트의 동작
- 일단 처음 코드를 실행시키면 모든 것을 포함하는 전역 컨텍스트가 생긴다.
- 컨텍스트 생성 시 컨텍스트 안에 변수 객체, 스코프 체인, this가 생성된다.
- 컨텍스트 생성 후 함수가 실행되는데, 사용되는 변수들은 변수 객체 안에서 값을 찾고, 없다면 스코프 체인을 따라 올라가며 값을 찾는다.
- 함수 실행이 마무리되면 해당 컨텍스트는 사라진다(클로저 제외)
- 페이지가 종료되면 전역 컨텍스트가 사라진다.
Reflow & Repaint(Redraw)
- 화면에 모든 요소가 그려지고 나서 사용자 인터렉션 또는 페이지의 기능에 따라 일부 변경이 생기는 경우에 발생하는 현상이다.
Reflow- 노드의 크기 또는 위치가 변경되어 현재 레이아웃에 영향을 미쳐서
배치를 다시 해야하는 경우에 발생한다. - Repaint 대비 심각한 성능 저하를 유발시킬 수 있다.
- 발생 경우
- 윈도우 리사이징
- 노드 추가/제거/수정
- 요소 위치 변경
- 요소 크기 변경
- 폰트 변경
- 텍스트 내용 변경
- 이미지 크기 변경
- 페이지 초기 렌더링
- 엘리먼트에 대한 위치 값 계산 시
- 노드의 크기 또는 위치가 변경되어 현재 레이아웃에 영향을 미쳐서
Repaint- 배경색 변경 등 단순한 스타일 변경과 같은 작업에 발생한다. 즉, 화면 레이아웃에는 영향을 미치지 않는 경우에 발생한다.
- 발생 경우
- 특정 엘리먼트의 색상 값 변화
- Reflow 최소화 방법
- 클래스 변화에 따른 스타일 변경 시,
최대한 DOM 구조상 끝단에 위치한 노드에 준다. 인라인 스타일을 최대한 배제한다.- 인라인 스타일이 없으면, 외부 스타일 클래스 조합으로
단 한번만 Reflow를 발생시킬 수 있다.
- 인라인 스타일이 없으면, 외부 스타일 클래스 조합으로
- 애니메이션이 들어간 노드는
position: fixed또는position: absolute로 지정한다.- 포지션 속성을 fixed 또는 absolute로 주면 지정된 노드는 전체 노드에서 분리된다. 즉, 전체 노드에 거쳐 reflow비용이 들지 않고, 해당 노드의 repaint 비용만 든다.
- 캐쉬를 사용하여
중복되는 요청을 최소화한다. DOM에 대한 직접적인 접근을 최소화한다.
- 클래스 변화에 따른 스타일 변경 시,
서버사이드 렌더링(SSR) VS. 클라이언트 사이드 렌더링(CSR)
- 서버사이드 랜더링은 전통적인 웹 방식으로, 페이지가 새로고침 될 때마다 서버로부터 리소스를 전달받아 화면에 렌더링하는 방식이다.
- 하지만, React, Vue 등의 라이브러리가 등장하면서 훨씬 더 좋은 성능의 SPA 방식의 개발 환경이 선호되기 시작하였다.
CSR에서 서버는 단지 JSON 파일을 보내주는 역할만 할 뿐이며, html을 그리는 역할은 클라이언트에서 수행한다.- 하지만, CSR은 다음과 같은 단점을 가진다.
- 자바스크립트가 모든 동작을 수행한 후에 화면에 내용이 나타나므로
초기 구동 속도가 SSR에 비해 느리다 SEO를 할 수 없다- 검색 엔진 최적화(SEO)란, 웹 페이지 검색엔진이 자료를 수집하고 순위를 매기는 방식에 맞게 웹 페이지를 구성해서 검색 결과의 상위에 나올 수 있게 하는 작업을 말한다.
- SPA를 개발하는 경우 여러 가지 이점이 있음에도 불구하고 SEO가 잘 되지 않는다는 약점이 있다. 따라서 정보 제공을 목적으로 하는 웹 페이지는 SPA 방식이 불리할 수 있으며, React나 Angular 같은 프레임워크는 서버 렌더링을 통해 SEO에 대응할 수 있는 기술을 지원하므로 선별적으로 사용하면 된다.
- 보안적으로 취약하다
- 자바스크립트가 모든 동작을 수행한 후에 화면에 내용이 나타나므로
- 하지만, CSR은 다음과 같은 단점을 가진다.
Next.js
- SSR을 쉽게 구현하도록 도와주는 프레임워크
- Next.js는 React의 SSR(Server Side Rendering)을 쉽게 구현할 수 있게 도와주는 프레임워크다.
- Next.js 작동원리
- 1 ) 초기에 사용자가 Server에 페이지 접속을 요청하면, SSR방식으로 렌더링 될 HTML을 보냄.
- 2 ) 브라우저에서 JavaScript를 다운로드하고 React를 실행함.
- 3 ) 사용자, 페이지가 서로 상호작용하여 다른 페이지로 이동할 땐, Server가 아닌 CSR방식으로 브라우저에서 처리함.
생명주기 메소드
- 클래스 기반 컴포넌트는 그들이 mount(DOM에 렌더링)되었을때, unmount 되었을 때 등과 같이 그들의 생명주기 중 특정한 시점에 호출되는 메소드를 선언할 수 있다.
componentWillMount: 컴포넌트가 생성된 후 DOM에 렌더링되기 전에 호출된다.componentDidMount: 처음으로 렌더링이 끝나고 컴포넌트의 DOM 엘리먼트가 사용 가능할 때 호출된다.componentWillReceiveProps: props가 업데이트 될 때 호출된다.shouldComponentUpdate: 새로운 props를 받았을 때 호출되며, 성능 최적화를 위해 리랜더링을 막을 수 있다.componentWillUpdate: 새로운 props를 받았고 shouldComponentUpdate가 true를 리턴할 때 호출된다.componentDidUpdate: 컴포넌트가 업데이트된 후에 호출된다.componentWillUnmount: 컴포넌트가 DOM에서 제거되기 전에 호출되어 이벤트리스너 등을 정리할 수 있게 해준다.
요소를 배치하는 방법의 차이
static: 기본값으로 요소들이 겹치지 않고 상→하로 배치된다.relative: 원래 배치되어야 할 위치에서 지정한 값 만큼 떨어진 곳에 요소를 배치한다.fixed: 웹 브라우저 화면 전체를 기준으로 배치한다. 스크롤을 하더라도 위치가 고정된다.absolute: 가장 가까운 상위 요소의 위치를 기준으로 지정한 값 만큼 떨어진 곳에 요소를 배치한다.
크로스 브라우징
- 크로스 브라우징은 웹 표준에 따라 서로 다른 OS 또는 플랫폼에 대응하는 것을 말한다.
- 브라우저별 렌더링 엔진이 다른 상황 등 어떤 상황 속에서도 문제없이 동작하게 하는 것을 목표로 한다.
Class VS. ID
- 아이디와 클래스의 차이는 id는 유일한 요소에 적용할 때, 그리고 클래스는 복수의 요소에 적용할 때 사용한다는 점이다.
- 하나의 ID는 하나의 문서에서 한 번만 사용할 수 있다.
- 하나의 Class는 하나의 문서에서 여러 번 사용할 수 있다.
- 우선순위는 ID가 Class보다 높다.
- CSS 우선순위 -
important → inline → id → class → tag → 상속
- CSS 우선순위 -
Display 속성
block:항상 새로운 라인에 요소가 시작되고화면 크기의 전체 가로폭을 영역으로 차지한다. width 속성 값을 부여해주면 그 너비만큼 영역을 차지한다.inline: 새로운 라인에서 시작되지 않으며다른 요소들과 같은 줄에 배치될 수 있고 content 너비만큼의 영역을 차지한다. 그리고 width, height, margin-top, margin-bottom 속성이 적용되지 않는다.inline-block: block 레벨 요소와 inline 레벨 요소의 특징을 모두 가지고 있다. 한 줄에서 inline 레벨 요소들과 같이 배치될 수 있으며 width와 height 속성으로 영역의 크기를 지정할 수 있다.none: 선택한 요소들을 화면에 나타나지 않게 한다. ‘visibility: hidden’과의 차이점은 영역이 남아있는지 여부가 다르다는 점(display: none은 영역도 없앰).
padding과 margin의 차이
margin은 대상의 외부 여백을 의미한다.padding은 대상의 내부 여백을 의미한다.
prop drilling
prop drilling은 부모 컴포넌트에서 하위 컴포넌트(자식 컴포넌트의 자식 컴포넌트 등으)로 데이터를 전달할 때 발생하는 것으로, props를 전달하는 것 외에는 props를 필요로 하지 않는 다른 컴포넌트를 통해 “drilling”(내리꽂기) 된다.- 컴포넌트를 리팩토링하고, 컴포넌트를 더 작은 컴포넌트들로 쪼개지 않고, state를 가장 가까운 부모 컨포넌트와만 공유함으로써 prop drilling 회피할 수 있다. 위계상 멀리/깊게(deep/far) 떨어진 컴포넌트와 state를 공유할 때, React의 Context API 혹은 Redux와 같은 state 관리 라이브러리를 사용할 수 있다.
React란?
- React는 SPA (Single Page Application) 즉, 단일 페이지 응용 프로그램에서 사용자 인터페이스를 구성하는데 사용되는
오픈 소스 프론트엔드 JS 라이브러리로, 웹 및 모바일 앱의 Layer를 다루는데 사용된다. - React의 주요 특징
- RealDOM을 조작하는데 많은 비용이 들어간다는 점을 고려하여 리액트는 RealDOM 대신
VirtualDOM을 사용한다. 서버 사이드 렌더링을 지원한다.- 단방향 데이터 흐름 또는 데이터 바인딩을 따른다.
- UI 구성 요소를 재사용할 수 있도록 개발할 수 있다.
- RealDOM을 조작하는데 많은 비용이 들어간다는 점을 고려하여 리액트는 RealDOM 대신
React.js의 Virtual Dom
DOM:Document Object Model로 HTML 문서를 프로그래밍적으로 접근가능하게 해주는 인터페이스- HTML 은 브라우저에 의해 해석되어 실제 문서를 나타내는 노드 개체들의 트리구조로 변환된다.(DOM Parser) DOM 의 목적은
javascript 를 사용해서 이 문서에 대한 프로그래밍 인터페이스를 제공하는 것이다. - DOM node 에 접근하여 편집을 하면 DOM 이 업데이트 되는데 비용이 많이 든다.
- 새로운 node 를 추가하면 DOM 에 해당 node 를 추가하여 업데이트 해줘야하며, 만약 이러한 업데이트로 인해 레이아웃에 대한 변화가 생기면 웹페이지 일부 또는 전체를 다시 랜더링 될 수 있다.(reflow, layout)

- HTML 은 브라우저에 의해 해석되어 실제 문서를 나타내는 노드 개체들의 트리구조로 변환된다.(DOM Parser) DOM 의 목적은
- 브라우저(Chrome, Firefox, Safari, IE 등)에서 사용자 인터페이스 즉, UI를 구성하는데는 위와 같은 과정을 거친다.

- 그리고 저기서 빨간색 박스처리한
렌더링 엔진의 역할에 대해서 알아봐야한다.- 1)
Parser- 각 파일들을 브라우저가 알아들을 수 있게 변환. - 2)
DOM Tree파일의 경우, 각 태그의 관계도 형성을 위해 DOM 트리 생성. - 3)
Attachment- HTML의 각 태그에 맞는 스타일(CSS) 정보를 객체 형태로 다음 단계로 넘겨줌. - 4)
Render Tree- 외부 CSS 파일이 선언되어있다면 이를 필요료 하는 각 HTML 엘리먼트에 결합 후, 이전 Attachment에서 전달받은 스타일 값 들을 계산, 그리고 레이아웃 정보 형성. - 5)
Layout- 렌더 트리 작업이 끝난 레이아웃에 대해서 좌표 부여. - 6)
Painting렌더링이 끝난 각 레이아웃들에게 실제 사용자에게 보여질 모양과 색 부여.
- 1)
- 이러한 처리과정은 브라우저에 어떠한 작은 변화가 있을 때마다 위의 작업들을 계속적으로 반복하며 다시 레이아웃을 형성하게 된다.
- 특히나 요즘 같이
SPA(Single Page Application)가 대세인 웹앱 같은 경우, 단일 페이지에서 사용자와의 인터랙션이 빈번히 일어나게 되고, 사용자 입장에서는 한번의 클릭이지만 실제 그 클릭 이벤트로 일어나게 되는 수많은 레이아웃들의 위치, 모양, 색상, 데이터 호출 등이 일어나기 때문에 기존의 방식대로 개발을 진행하게 되면 브라우저가 연산하게 되는 양은 어마어마하게 늘어날 수 밖에 없다. 그리고 자연스럽게 이는 사용자에게 부적절한 경험을 제공하게 된다. - 리액트는 메모리에 가상 돔을 올려놓고 이전과 이후에 가상 돔을 비교 후, 변경된 부분만 실제 돔에 반영하는 전략을 채택하고 있다.
- 렌더 함수가 호출되면서. 최초의 렌더 단계가 실행된다.
- 이렇게 만들어진 가상 돔이 실제 돔으로 적용된다.
- 사용자의 행위로 컴포넌트의 상태값이 변경이 된다
- 이로 인해 두 번째 렌더가 일어나고, 가상 돔을 그린다
새로운 가상 돔과 실제 돔의 차이점을 비교하고, 변경된 부분만 실제 돔에 적용한다.
React hooks이란?
Hooks는 클래스 기반 컴포넌트의 장점(예를 들면, 내부 state와 생명주기 메소드)을 함수형 컴포넌트로 가져오려는 리액트의 시도이다..- React에 hooks를 도입해서 얻을 수 있는 장점
- 클래스 기반 컴포넌트, lifecycle hooks, this의 필요성이 사라진다.
- 공통 기능을 커스텀 hook로 만들어서 로직을 재사용하기 쉬워진다.
- 컴포넌트 자체에서 로직을 분리할 수 있어서 읽기 쉽고 테스트하기 쉬운 코드를 작성할 수 있다.
React Hooks - 성능 최적화
- 먼저 컴포넌트의 리렌더링 되는 조건은 아래와 같다.
- 부모에서 전달받은
props가 변경될때 - 부모 컴포넌트가 리렌더링 될 때
- 자신의
state가 변경 될 때
- 부모에서 전달받은
-
useMemo- 이 함수는 React Hook 중 하나로서 React에서 CPU 소모가 심한 함수들을 캐싱하기 위해 사용된다.
- 만약 컴포넌트내의 어떤
함수가 값을 리턴하는데 하나의 변화에도 값을 리턴하는데 많은 시간을 소요한다면 이 컴포넌트가 리렌더링 될 때마다 함수가 호출되면서 많은 시간을 소요하게 될 것이다. - 또 그 함수가 return되는 값이 자식 컴포넌트에도 사용이 된다면, 그 자식 컴포넌트도 함수가 호출 될 때마다 새로운 값을 받아 리렌더링 된다.
- 만약 컴포넌트내의 어떤
useMemo(() => func, [input_dependency]);func은 캐시하고 싶은 함수이고,input_dependency는 useMemo가 캐시할 func에 대한 입력의 배열로서 해당 값들이 변경되면 func이 호출된다.이것을 적용하면input_dependency가 있는 데이터가 변할 때에만 평균을 구하는 연산을 수행하도록 한다.input_dependency에는usersstate를 넣어준다.
const average = useMemo(() => { console.log("calculate average. It takes long time !!"); return users.reduce((acc, cur) => { return acc + cur.score / users.length; }, 0); }, [users]);- useMemo는 종속 변수들이 변하지 않으면 함수를 굳이 다시 호출하지 않고 이전에 반환한 참조값을 재사용 한다.즉, 함수 호출 시간도 세이브할 수 있고 같은 값을 props로 받는 하위 컴포넌트의 리렌더링도 방지할 수 있다.
- 이 함수는 React Hook 중 하나로서 React에서 CPU 소모가 심한 함수들을 캐싱하기 위해 사용된다.
-
useCallback- useMemo가 리턴되는 값을 memoize 시켜주었는데, useMemo와 비슷한 useCallback은
함수 선언을 memoize하는데 사용된다.
- useMemo가 리턴되는 값을 memoize 시켜주었는데, useMemo와 비슷한 useCallback은
state를 직접 변경하지 않고 왜 setState를 이용하는가?
- 만약 컴포넌트의 state를 직접 변경하려고 시도한다면, 리액트는
컴포넌트를 다시 렌더링해야 하는지 알 수 있는 방법이 없다.setState()메소드를 사용하면 리액트는 컴포넌트의 UI를 업데이트할 수 있다.
state와 props의 차이는?
- props는 부모 컴포넌트에서 자식 컴포넌트로 전달되는 데이터이다
props는 수정될 수 없으며 표시되거나 다른 값을 계산하는데만 사용된다. state는 컴포넌트의 생명 주기 동안 수정될 수 있는 내부 데이터로, 다시 렌더링해도 유지된다.
HTTP / HTTPS
HTTPHTTP(Hyper Text Transfer Protocol)- 인터넷을 통해 정보를 주고받는 데 사용하는 규약
- HTTP는 애플리케이션 레벨의 프로토콜로 TCP/IP 위에서 작동한다.
- HTTP는 Stateless 프로토콜이며, Method, Path, Version, Headers, Body 등으로 구성된다.
- HTTP의 문제점
HTTP는 통신 상대를 확인하지 않는다- HTTP 통신에서는 상대방이 누구인지 확인하려는 처리가 없기 때문에 누구든지 요청을 보낼 수 있고 요청 대상이 접근 권한 처리를 안한 경우 응답을 반환한다.
- 즉, 요청을 보내서 응답을 받았을 때 요청을 보낸 이 입장에서 응답을 준 사람이 실제 의도한 사람인지 확인할 수 없고, 요청을 받은 입장에서도 응답을 내려준 사람이 실제 의도한 요청을 보내는 사람인지 확인할 수 없다.
- 디도스 공격에도 취약하다
HTTP는 평문 통신이기 때문에 도청이 가능하다- 통신 경로상에서 패킷을 수집해서 도청이 가능하다
완전성을 보장할 수 없기 때문에 변조가 가능하다- HTTP통신을 통해 수신한 내용이 송신 측에서 보낸 내용과 일치한다는 것을 보장할 수 없다
HTTPSHTTPS(Hyper Text Transfer Protol Secure)SSL/TLS를 통해 암호화하여 컴퓨터 네트워크를 통한 통신을 보안하도록 설계된 웹 통신 프로토콜- HTTP를 SSL을 사용해 데이터를 둘러싸 보안 기능이 향상된다
- SSL 인증서라고도 불리는 방식
SSL-보안 소켓 계층(Secure Sockets Layer, SSL)인증서는 종종 디지털 인증서로 불리며, 브라우저(사용자의 컴퓨터)와 서버(웹사이트) 사이의 암호화된 연결을 수립하는 데 사용된다.TLS(Transport Layer Security)- 인터넷 상의 커뮤니케이션을 위한 개인 정보와 데이터 보안을 용이하게 하기 위해 설계되어 널리 채택된 보안 프로토콜.CA(Cretificate Authority)?- 암호화에 사용되는 키를 저장해 주는 신뢰성이 검증된 민간 기업…
- CA의 공개 키들을 브라우저가 알고 있다.
- 실제 HTTP로 데이터가 전송되기 전에 SSL 인증서를 통해 상호 확인한다.
- 사용자가 Https로 된 웹사이트에 접속한다.
- 사용자의 브라우저는(예를 들어 크롬) 이 사이트를 제공해 주는
웹 서버와 서로 SSL 인증서를 교환한다 - 웹 서버와 브라우저는 서로 키를 교환하게 되며 이때 브라우저는 키를 이용해 이들만의 예비마스터키를 생성.
데이터를 암복호화 한다 - 웹 서버도 이 마스터키를 획득하게 된다면 이 키를 통해 데이터를 암복호화 할 수 있게 되며 안전하게 데이터가 전송될 수 있다.
TCP & UDP

Reduct / map / filter
for문
const practice = [
{ name: "개발자", value: 150, active: false },
{ name: "퉁이리", value: 200, active: true },
{ name: "프론트엔드", value: 110, active: true },
{ name: "티스토리", value: 300, active: true },
{ name: "깃허브", value: 250, active: true },
];
for (let i = 0; i < practice.length; i++) {
console.log(practice[i].name);
}
-
while문const practice = [ { name: "개발자", value: 150, active: false }, { name: "퉁이리", value: 200, active: true }, { name: "프론트엔드", value: 110, active: true }, { name: "티스토리", value: 300, active: true }, { name: "깃허브", value: 250, active: true }, ]; let i = 0; while (i < practice.length) { console.log(practice[i].name); i++; }- while문도 마찬가지로 i를 활용하여 카운팅을 하고 practice 길이만큼만 반복하게 하였다.
-
forEachconst practice = [ { name: "개발자", value: 150, active: false }, { name: "퉁이리", value: 200, active: true }, { name: "프론트엔드", value: 110, active: true }, { name: "티스토리", value: 300, active: true }, { name: "깃허브", value: 250, active: true }, ]; practice.forEach((data) => console.log(data.name));- forEach는 아주 단순한 반복문으로 별다른 부가기능은 없다는 특징이 있다.
- 가장 기본적인 반복문이다.
- 그렇지만 for문보다 코드가 더 예뻐 보인다.
- 그 이유는 아래와 같다!
- 임시 변수(i)를 사용하지 않아도 된다.
- 길이를 따로 설정하지 않아도 된다.
-
mapconst practice = [ { name: "개발자", value: 150, active: false }, { name: "퉁이리", value: 200, active: true }, { name: "프론트엔드", value: 110, active: true }, { name: "티스토리", value: 300, active: true }, { name: "깃허브", value: 250, active: true }, ]; const practiceNames = practice.map((data) => data.name); console.log(practiceNames);- map은 어떤 배열을 다른 형태의 배열로 재생산할 때 사용된다.
- 기존 배열을 수정하는 것이 아니라 새 배열을 반환하는 것이다!
- map은 배열의재탄생을 도와준다.
-
filterconst practice = [ { name: "개발자", value: 150, active: false }, { name: "퉁이리", value: 200, active: true }, { name: "프론트엔드", value: 110, active: true }, { name: "티스토리", value: 300, active: true }, { name: "깃허브", value: 250, active: true }, ]; const practice220 = practice.filter((data) => data.value < 220); console.log(practice220);- filter는 배열 안에서 특정 조건을 가진 요소만 뽑아내는 반복문이다.
- filter도 map과 같이필터링을 통과한 값에 대해 새 배열을 반환한다.
- 위 코드는 value의 값이 220 미만인 값에 대해 필터링을 진행 후 필터를 통과한 값으로 이루어진 배열을 반환하였다.
- 검색 기능에서 많이 활용된다.
-
reduceconst practice = [ { name: "개발자", value: 150, active: false }, { name: "퉁이리", value: 200, active: true }, { name: "프론트엔드", value: 110, active: true }, { name: "티스토리", value: 300, active: true }, { name: "깃허브", value: 250, active: true }, ]; const practiceSum = practice.reduce((pre, cur) => pre + cur.value, 0); console.log(practiceSum);- practice에 있는 모든 value 값들의 합을 구하고 싶을 때, reduce를 사용한다.
- 누적 합을 구할 때 reduce를 많이 사용한다.
- pre는 누산 값 cur은 현재 값 0은 초기 값
- reduce 메서드 역시 하나의 결괏값을반환한다.
자바스크립트의 가비지 컬렉션
💡
JavaScript는 더 이상 사용되지 않을 변수와 함수를 Heap(메모리 힙)에서 제거함으로써 메모리를 효율적으로 관리한다. 이러한 역할을 수행해주는 도구를 Garbage Collector라고 한다.
- 거의 모든 프로그래밍 언어의 메모리 라이프 사이클은 다음과 같이 작동한다
할당(allocate): 프로그램이 사용할 수 있도록 운영체제가 메모리를 할당하는 것. JavaScript와 같이 고수준 언어에서는 개발자가 신경쓸 일이 없지만, 저수준 언어에서는 개발자가 명시적으로 처리해야한다.사용(use): 코드 상에서 할당된 변수를 사용함으로써 읽기 및 쓰기 작업이 이루어진다.해제(release): 프로그램에서 필요하지 않은 메모리를 OS에 되돌려주는 단계이다. 할당과 마찬가지로 저수준 언어에서는 이를 명시적으로 처리해야 한다.
- JavaScript는
도달 가능성(reachability)이라는 개념을 사용해 메모리 관리를 수행한다.- ‘도달 가능한(reachable)’ 값은 쉽게 말해 어떻게든 접근하거나 사용할 수 있는 값을 의미하며, 도달 가능한 값은 메모리에서 삭제되지 않는다.
- 예시로 아래 값들은 무조건 적으로 도달 가능한 값들이기에, 명백한 이유 없이는 삭제되지 않는다.
- 현재 함수의 지역변수와 매개변수
- 중첩 함수의 체인에 있는 함수에서 사용되는 변수와 매개변수
- 전역 변수
- 기타 등등…
- Garbage Collection 알고리즘
마크 앤 스위프 (Mark and Sweep Algorithms)알고리즘- 가비지 컬렉션 알고리즘이 의존하고 있는 주요 개념은 참조(reference)다. 만약 그것을 가리키는
참조가 하나도 없는 경우(Reachable 하지 않은 경우) 가비지컬렉션 대상(Garbage collectible)이 된다. - 자바스크립트는 마크 앤 스위프 알고리즘을 사용하며, 이는 다음의 세 단계를 거친다.
- 가비지 컬렉터는 모든 루트로부터
완전한 목록을 만들어낸다.(루트는 전역 객체, 즉 window 객체 혹은 root 객체를 의미한다.) - 그런 다음 모든 루트와 그 자식들을 검사해서
활성화 여부를 표시(Mark)한다. 활성으로 표시되지 않은 모든 메모리를 쓸어담아(Sweep) OS에 반환한다.이 과정의 단점도 있긴 하다.- 어떤 메모리를 해제할지 결정하는 데 비용이 든다. 특히, 개발자가 이미 인지하고 있는 경우에도 가비지 컬렉터가 작동하므로 작업이 오버헤드가 될 수 있다.
- 특히, 표시(Mark) 단계에서 메모리 내용이 변경되지 않아야 하기 때문에 전체 시스템의 실행이 정지된다.이 과정에서 프로그램 퍼포먼스가 저하될 수 있다.
참고!!
레퍼런스 카운팅 알고리즘(Reference Counting Algorithms)- 참조 횟수를 계산 하는 알고리즘으로, 이 알고리즘의 한계는
순환참조의 경우 두 객체가 적어도 한 번은 참조한 것으로 간주해서 가비지컬렉션이 될 수 없다. 이 한계를 보완한 알고리즘이 마크 앤 스위프 알고리즘 이다.
- 참조 횟수를 계산 하는 알고리즘으로, 이 알고리즘의 한계는
- 가비지 컬렉터는 모든 루트로부터
- 가비지 컬렉션 알고리즘이 의존하고 있는 주요 개념은 참조(reference)다. 만약 그것을 가리키는
메모리 누수- 메모리 힙이 제대로 관리되지 않을 경우,
현재는 필요가 없음에도 불구하고 메모리 공간에서 제거되지 않은 상태로 유지되는 경우를 의미한다.- 사실, 그동안은 웹개발자에게 메모리 누수는 그렇게 걱정할 부분이 아니었다고 한다. 페이지 안의 링크를 클릭하게 되면, 결국 메모리상에 새 페이지를 불러오기 때문이다.
- 하지만 오늘날 Single Page Application이 보편화되면서 오랜 시간 동일한 페이지에서 사용이 이루어지게 되었고, 메모리 누수 방지의 필요성이 증가했다.
- JavaScript에서 메모리 누수를 발생시키는 대표적인 4가지 사례
전역 변수(Global variables)를 많이 선언한 경우- 선언되지 않은 변수를 참조하면 이는 자동적으로 전역 변수로 생성된다.
엄격모드(Strict mode)를 사용하면 전역변수의 사용을 미리 예방 할 수 있다. 명시적으로 사용된 전역변수는 회수되지 않는다. 전역변수를 사용해야 한다면, 사용된 후에는 반드시null처리해주는 것이 좋다.
- 선언되지 않은 변수를 참조하면 이는 자동적으로 전역 변수로 생성된다.
- 타이머 혹은 이벤트리스너를
클린업(Clean up)하지 않은 경우setInterval의 경우 클린업해주지 않으면 계속 사용 중인 것으로 간주되어 가비지 컬렉터에 의해서 제거되지 못하고 메모리 공간을 계속 차지하게 된다.- 이벤트 리스너의 경우도
removeEventListener를 해주지 않으면 DOM요소의 수명보다 오래 남게 되어 메모리 누수가 발생한다.
클로저외부 함수의 실행이 끝난뒤에도 사라지지 않고 상위 렉시컬 환경을 기억하는 것을 클로저라고 하는데, 이 기억을 위해 메모리가 필요하고 이 메모리는 참조를 제거하지 않는 한 GC에 의해 회수되지 않는다.
DOM을 벗어난 참조- DOM에서는 지워졌지만 자바스크립트에 의해 여전히 메모리를 차지하고 있는 경우를 말한다.
- DOM요소가 코드 내에서 변수나 객체에 의해 참조되고 있으면 DOM 내에서 삭제되어도 GC에 의해 회수되지 않는다.
- 메모리 힙이 제대로 관리되지 않을 경우,
고차 컴포넌트(High Order Component)
-
고차 컴포넌트는
컴포넌트를 매개 변수로 받아 새로운 컴포넌트를 반환하는 함수를 의미한다.import { useState } from "react"; export default function withHover(InnerComponent) { return (props) => { const [isHovered, setIsHovered] = useState(false); function handleMouseEnter() { setIsHovered(true); } function handleMouseLeave() { setIsHovered(false); } return ( <InnerComponent {...{ ...props, handleMouseEnter, handleMouseLeave, isHovered, }} /> ); }; } - 고차 함수를 떠올리면 고차 컴포넌트 또한 이해하기가 편하다.
- 고차 함수는 함수를 인자로 받거나 결과로 반환하는 함수를 의미한다.
- 고차 컴포넌트는
함수 대신 컴포넌트를 인자로 받아 특정 로직을 포함하는 새로운 컴포넌트를 반환한다.
- 보통 고차 컴포넌트는
with로 시작하는 이름을 가지도록 구현한다- hooks가 use로 시작하듯…
- HOC의 단점
암묵적인 props 전달- HOC 패턴을 활용할 경우 개발자 입장에서는 props로 전달되는 속성들이 다소 명확하지 않기 때문에 사용하려는 HOC를 정확하게 파악하고 어떤 props들이 암묵적으로 전달되는지 숙지하고 있어야 한다.
- 또한, 이로 인해 HOC에서 전달해주는 props와 inner Component의 props간에 네이밍이 겹칠 수 있다.
컴포넌트 구조의 복잡성 유발- 고차 컴포넌트를 사용하면 Depth가 불필요하게 커질 수 있다.
- 일부 적용시에는 문제가 없겠지만, 본격적인 적용 시 디버깅에 어려움이 생길 수 있다.
- 이러한 단점은…
- custom hooks를 활용하여 어느 정도 해소할 수 있다.
Is Async/Await pattern is faster then promises?
- 결론적으로 그렇지 않다.
- async/await 패턴 자체가 프로미스를 필요로 하므로, 단순히 신택스 차이만 있을 뿐 동작은 동일하다.
- 하지만,
구형 브라우저의 경우async/await을 promise 패턴으로 변환해서 실행해야 하므로, 이러한 케이스에서는 async/await이 promise 패턴보다 느릴 수 있다.
💡
It is actually literally the same because await requires a promise to work.
So worst case scenario it’s slightly slower because it maintains a second state engine on top of promises (in the case of await code converted to work on older browsers).
Best case scenario it is exactly the same as promises.
And if you thought you could just use await instead of a callback on any arbitrary function, you can’t. It’s become semi-standard now for asynchronous functions to return a promise if they don’t receive a callback, but that’s not widespread yet, and hasn’t made it into any runtime provided functions.
