github.com/baeharam/Must-Know-About-Frontend
baeharam/Must-Know-About-Frontend
:mortar_board: 취준생이라면 반드시 알아야 하는 프론트엔드 관련 지식들. Contribute to baeharam/Must-Know-About-Frontend development by creating an account on GitHub.
github.com
타자치면서 공부
AJAX
Asynchoronous Javascript And XML의 약자로, 비동기적으로 js를 사용해서 데이터를 받아와 동적으로 DOM을 갱신 및 조작하는 웹 개발 기법을 의미한다. 여기서 XML이 있는 이유는 옛날엔 json보다 많이써서 그럼
어떻게 동작하는가?
사용자가 AJAX가 적용된 UI와 상호작용하면, 서버에 AJAX 요청을 보내게 된다. 서버는 DB에서 데이터를 가져와서 JS파일에 정의되어 있는 대로 HTML/CSS와 데이터를 융합하여 만든 DOM 객체를 UI에 업데이트 시킨다. 비동기로 이루어지며, 기존의 페이지를 전부 로딩하는 방식이 아닌 일부만 업데이트 하는 방식이다.
장점
- 페이지를 전환하지 않고 빠르게 화면 일부분을 업데이트 할 수 있다.
- 수신하는 데이터의 양을 줄일 수 있고 클라이언트에게 처리를 맡길 수 있다.
- 서버 처리를 기다리지 않고 비동기 요청이 가능하다.
단점
- 지원하지 않는 브라우저가 있다.
- 페이지 전환없이 서버와 통신을 하기 때문에 보안상 문제가 있을 수 있다.
- 무분별하게 사용하면 역으로 서버의 부하가 늘어날 수 있다.
- 동일 출처 정책 문제가 발생할 수 있다.
이벤트 위임
이벤트 버블링과 캡처링 - 이벤트 위임을 알려면 선수지식으로 알아야함.
이벤트 버블링 : 하위 엘리먼트에 이벤트가 발생할 때 그 엘리먼트부터 시작해서 상위요소까지 이벤트가 전달되는 방식을 말한다.
이벤트 캡처링 : 하위 엘리먼트에 이벤트 핸들러가 있을 때 상위 엘리먼트부터 이벤트가 발생하기 시작해서 하위 엘리먼트까지 이벤트가 전달되는 방식을 말한다.
<div>
<ul>
<li>예시</li>
</ul>
</div>
document.querySelector('li').addEventListener('click', () => console.log('li 클릭'));
document.querySelector('ul').addEventListener('click', () => console.log('ul 클릭'));
document.querySelector('div').addEventListener('click', () => console.log('div 클릭'));
위 코드에서 li를 클릭하면 이벤트 3개 모두가 실행된다.(li 클릭 -> ul -> div) 이게 이벤트 버블링이다.
document.querySelector('ul').addEventListener('click', () => console.log('ul 클릭'), { capture: true });
다음과 같이 capture : ture 옵션을 주고 ul을 클릭하면 ul 클릭 -> li 클릭 순으로 출력 된 후 다시 이벤트 버블링이 동작해 div 클릭이 출력 된다. ul -> li 순으로 상위요소에서 하위로 내려가면서 이벤트가 발생하는걸 이벤트 캡처링이라고 한다.
이벤트 위임 : 하위 엘리먼트들이 여러개 있을 때, 하위 엘리먼트들에 각각 이벤트 핸들러를 달지 않고 상위 엘리먼트에 이벤트 핸들러를 달아 하위 엘리먼트들을 제어하는 방식이다.
장점
- 동적으로 엘리먼트를 추가할 때 마다 핸들러를 고려할 필요가 없다.
- 상위 엘리먼트에 하나의 이벤트 핸들러만 추가하면 되기 때문에 코드가 훨씬 깔끔해진다.
- 메모리에 있게되는 이벤트 핸들러가 적어지기 때문에 퍼포먼스 측면에서 이점이 있다.
예시
<ul onclick="alert(event.type + '!')">
<li>첫번째</li>
<li>두번째</li>
<li>세번째</li>
</ul>
실행 컨텍스트
코드의 실행환경에 대한 여러가지 정보를 담고 있는 개념으로, 간단히 말하면 자바스크립트 엔진에 의해 만들어지고 사용되는 코드 정보를 담은 객체의 집합.
자바스크립트의 코드는 3가지 종류로 이루어지는데, 글로벌 스코프에서 실행하는 글로벌 코드, 함수 스코프에서 실행하는 함수 코드 그리고 여기서 다루진 않지만 eval() 로 실행되는 코드가 있다. 이 각각의 코드는 자신만의 실행 컨텐스트를 생성한다.
엔진이 스크립트 파일을 실행하기 전에 글로벌 실행 컨텐스트(Global Execution Context, GEC)가 생성되고, 함수를 호출할 때마다 함수 실행 컨텍스트(FEC)가 생성된다. 주의할 점은, 글로벌의 경우 실행 이전에 생성되지만 함수의 경우 호출할 때 생성된다는 점이다.
실행 컨텍스트 스택
실행 컨텍스트가 생성되면 흔히 콜 스텍이라고도 불리는 실행 컨텍스트 스택에 쌓이게 된다. GEC는 코드를 실행하기 전에 쌓이고 모든 코드를 실행하면 제거된다. FEC는 호출할 때 쌓이고 호출이 끝나면 제거된다.
miro.medium.com/max/1100/1*dUl6qPEaDJJTXWythQsEtQ.gif 예시 gif
구성요소
Lexical Evironment
변수 및 함수 등의 식별자 및 외부 참조에 관한 정보를 가지고 있는 컴포넌트. 이 컴포넌트는 2개의 구성요소를 가짐.
1) Environment Record : 식별자에 관한 정보를 가지고 있으며 outer 참조는 외부 Lexical Environment를 참조하는 포인터이다.
var x = 10;
function foo() {
var y = 20;
console.log(x);
}
위 와 같은 코드일때
globalEnvironment = {
environmentRecord = { x: 10 },
outer: null
}
fooEnvironment = {
environmentRecord = { y: 20 },
outer: globalEnvironment
}
다음과 같은 Lexical Environment가 형성된다.
따라서 foo() 에서 x를 참조할 때는 현대 Environment Record를 찾아보고 없으면 outer 참조를 사용하여 외부의 Lexical Environment에 속해 있는 레코드를 찾아보는 방식이다.
2) Variable Environment : Lexical이랑 동일한 성격을 갖지만 var로 선언된 변수만 저장한다는 점에서 다르다. 즉 Lexical에서는 var로 선언된 변수를 제외한 나머지를 저장함.
3) this 바인딩 : 실행 컨텍스트가 생성될 때 마다 this 객체 안에 어떻게 바인딩이 되는지를 나타낸 것이다.
- GEC의 경우 : strict mode면 undefined, 아니라면 글로벌 객체로 바인딩(브라우저에선 window, 노드에선 global)
- FEC의 경우 : 해당 함수가 어떻게 호출되었는지에 따라 다르게 바인딩됨.
실행컨텍스트 과정 (생성단계, 실행단계)
생성단계 : Lexical Environment 생성 -> Variable Environment 생성 -> this 바인딩. 이 때 주의할 점은 값이 변수에 매핑되지 않는다는 것이다.
실행단계 : 변수에 값을 매핑시킨다.
miro.medium.com/max/1100/1*SBP65hdVDW5j0LuVryTiXw.gif 참고
스코프
스코프란 자바스크립트 엔진이 참조의 대상이 되는 식별자를 검색할 때 사용하는 규칙의 집합. 즉, 어떤 변수를 사용하거나 함수를 호출하려고 할 때 해당하는 식별자로 사용하는데, 그 식별자를 검색하는 매커니즘이라고 이해하면 된다.
렉시컬 스코프
프로그래머가 코드를 짤 때, 변수 및 함수/블록 스코프를 어디에 작성하였는가에 따라 정해지는 스코프를 렉스컬 스코프라고 한다.
스코프 체인
현재 스코프에서 식별자를 검색할 때 상위 스코프를 연쇄적으로 찾아나가는 방식을 말한다. 실행 컨텍스트를 배웠다면 생성될 때마다 LexicalEnvironment가 만들어지고 그 안에 outer 참조값이 있는데 이 참조 값이 상위 스코프의 Lexical Environment를 가리키기 때문에 이를 통해 체인처럼 연결되는 것이다. outer 참조 값이 null 일 때까지 계속하고 찾지 못한다면 에러를 발생시킨다.
호이스팅
호이스팅이란 끌어올린다 라는 뜻으로 변수 및 함수 선언문이 스코프 내의 최상단으로 끌어올려지는 현상을 말한다. 여기서 주의할 점은 선언문 이라는 것이며 대입문은 끌어올려지지 않음.
클로저
클로저란 함수가 속한 렉시컬 스코프를 기억하여 함수가 렉시컬 스코프 밖에서 실행될 때도 그 스코프에 접근할 수 있게 하는 기능을 말함.
function outer() {
var a = 2;
function inner() {
console.log(a);
}
return inner;
}
var func = outer();
func(); // 2
여기서 글로벌 실행 컨텍스트가 outer()의 참조를 없앨 것 같지만 내부 함수인 inner에서 해당 스코프의 변수 a를 참조하고 있기 때문에 없애지 않는다. 따라서 스코프 외부에서 inner() 가 실행되도 해당 스코프를 기억하기 때문에 2를 출력하게 됨. 즉, 여기서 클로저는 inner()가 되며 func에 담겨 밖에서도 실행되고 렉시컬 스코프를 기억함.
네이티브 객체 : ECMAScript 명세에서 의미론적인 부분을 완전히 정의해놓은 객체들 (Object, Function, Date, Mate ... )
호스트 객체 : 자바스크립트를 실행하는 환경에 종속된 객체로 그 환경에서만 찾아볼 수 있는 객체이다. (브라우저환경이라면 window, document, location 등등)
this의 바인딩
실행 컨텍스트가 생성될 때 마다 this의 바인딩이 일어나며 우선순위 순으로 나열하면 다음과 같다.
1. new를 사용했을 때 해당 객체로 바인딩 된다.
var name = "global";
function Func() {
this.name = "Func";
this.print = function f() { console.log(this.name); };
}
var a = new Func();
a.print(); // Func
2. call, apply, bind 와 같은 명시적 바인딩을 사용했을 때 인자로 전달된 객체에 바인딩이 된다.
function func() {
console.log(this.name);
}
var obj = { name: 'obj name' };
func.call(obj); // obj name
func.apply(obj); // obj name
(func.bind(obj))(); // obj name
3. 객체의 메소드로 호출할 경우 해당 객체에 바인딩 된다.
var obj = {
name: 'obj name',
print: function p() { console.log(this.name); }
};
obj.print(); // obj name
4. 그 외의 경우
- strict mod : undefined로 초기화
- 일반 : 브라우저라면 window 객체에 바인딩 됨.
var vs let vs const
- var는 함수 스코프를 갖고, let과 const는 블록 스코프를 갖는다.
const func = () => {
{
var a = 'a';
let b = 'b';
}
console.log(a);
console.log(b); //b is not defined
}
func()
- 호이스팅 시에 var는 함수 스코프의 최 상단으로 호이스팅되고, let과 const는 블록 스코프의 최상단으로 호이스팅 된다. (선언만 되고 값이 할당되기 전까지는 undefined상태)
- var는 글로벌 스코프에서 선언되었을 경우 글로벌 객체에 바인딩되고, let과 const는 글로벌 객체에 바인딩되지 않는다.
var foo = "Foo"; // globally scoped
let bar = "Bar"; // globally scoped
console.log(window.foo); // Foo
console.log(window.bar); // undefined
- var는 재선언이 가능하지만 let과 const는 불가능하다.
var foo = "foo1";
var foo = "foo2"; // 문제없음
let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared
- const는 재 할당이 불가능하다.
IIFE 즉시실행함수
- 2가지 조건. 즉시 실행해야한다, 함수 표현식이어야 한다(선언식x)
(function() {
console.log('IIFE');
})();
이런 모양임. 즉시 ()로 호출해서 함수를 실행시킨다.
(() => console.log('IIFE'))();
화살표 함수로 즉시실행함수 사용.
- 쓰는 이유 : 보통 전역 스코프를 오염시키지 않기 위해서 사용함. 즉, 변수르 ㄹ전역 스코프에 선언하는 것을 피하기 위함.
모듈 시스템
- 모듈이란? 여러 기능들에 관한 코드가 모여있는 하나의 파일로 다음과 같은 것들을 위해 사용한다.
- 유지보수성 : 기능들이 모듈화가 잘 되어있다면, 의존성을 그만큼 줄일 수 있기 때문에 어떤 기능을 개선한다거나 수정할 때 훨씬 편하게 할 수 있다.
- 네임스페이스화 : 자바스크립트에서 전역변수는 전역공간을 가지기 때문에 코드의 양이 많아질수록 겹치는 네임스페이스가 많아질 수 있다. 그러나 모듈로 분리하면 모듈만의 네임스페이스를 가지기 때문에 그 문제가 해결된다.
- 재사용성 : 똑같은 코드를 반복하지 않고 모듈로 분리시켜서 필요할 때마다 사용할 수 있다.
- CommonJS 방식 - 다른 모듈을 사용할때는 require, 내보낼때는 module.exports사용.
- exports vs module.exports의 차이
- module.exports는 빈 객체를 참조하고, exports는 module.exports를 참조함.
- require는 항상 module.exports를 리턴받는다.
- 왜 나눠졌나? exports는 module.exports를 참조하기 때문에 직접 module.exports를 수정하지 않고 객체의 멤버를 만들거나 수정하는 방식으로 사용한다. 따라서 exports에 어떤 값을 할당하거나 새로운 객체를 할당했다고 하더라도 결국 require는 module.exports를 리턴받기 때문에 잠재적인 버그를 피할 수 있다.
programmingsummaries.tistory.com/340 이 글도 보니 이해가 된다. exports를 쓰는게 정말 미세하게 더 안전한 경우가 있다는 차이는 알겠는데 그렇다고 굳이 두가지 버전으로 만들어야 했나 하는 생각이든다.
- AMD, UMD 방식도 있긴 하다.
- ES6에선 import, export
콜스택과 힙.
- JS 엔진이 JS를 실행할 때 원시 타입 및 참조 타입을 저장하는 메모리 구조로 콜스택과 힙스택을 가진다.
- 콜 스택 : 원시타입 값과 함수 호출의 실행 컨텍스트를 저장하는 곳이다.
- 힙 : 객체, 배열, 함수와 같이 크기가 동적으로 변할 수 있는 참조타입 값을 저장하는 곳.
github.com/baeharam/Must-Know-About-Frontend/blob/master/Notes/javascript/stack-heap.md 예제가 좋다
이벤트 루프
- 자바스크립트는 단일 스레드 기반 언어로, 자바스크립트 엔진이 단일 콜 스택을 갖는다. 이 말은 요청이 동기적으로 처리된 다는 것을 의미하는데 그렇다면 비동기 요청은 어떻게 처리될 수 있을까? 그것은 바로 자바스크립트를 실행하는 환경인 브라우저나 Node.js가 담당한다. 여기서 자바스크립트 엔진과 그 실행 환경을 상호 연동시켜주는 장치가 바로 이벤트 루프이다. 이벤트 루프는 자바스크립트 엔진에 있지 않고 그 환경에 속한다.
- 자바스크립트는 태스크 큐와, 마이크로 태스크 큐를 갖는다. 각각 스크립트 실행, 이벤트 핸들러, 콜백함수 등의 태스크를 담는 공간이다. 태스크가 콜백함수라면 그 종류에 따라 다른 큐에 담기는데 대표적으로 태스크큐 - setTimeout, setInterval, Ui rendering 등이 있고 마이크로 태스크 큐는 Promise, MutationObserver를 가진다.
이벤트 루프는 2개의 큐를 감시하고 있다가 콜 스택이 비게 되면, 콜백함수를 꺼내와서 실행한다. 이 때 마이크로태스크 큐의 콜백함수가 우선순위를 가지기 때문에 마이크로 태스크 큐의 콜백함수를 모두 실행하고 나서 태스크 큐의 콜백함수를 실행한다.
- 요약 : 자바스크립트는 단일 스레드 기반 언어이기 때문에 비동기 처리를 위해서 외부 환경의 도움을 받아야된다. 이벤트 루프는 브라우저나 노드js에 있는, 자바스크립트 엔진 밖의 장치인데 태스크큐와 마이크로 태스크 큐를 감시하면서 자바스크립트 엔진 내의 콜스택이 비게되면 태스크 큐에 있는 콜백함수를 비동기적으로 실행하도록 콜스택에 넣어주는 역할을 한다.
프로토타입
- 정의 : 자바스크립트의 모든 객체는 자신의 원형(프로토타입) 이 되는 객체를 가짐. 보이지 않는 속성인 [[Prototype]]이 자신의 프로토타입 객체를 참조한다. 특정 브라우저에서는 __proto__라는 속성으로 참조할 수도 있지만 비표준임.
- .prototype과 [[Prototype]]
[[Prototype]]은 은닉 속성이지만 함수 객체는 특별히 접근할 수 있는 속성인 .prototype을 갖는다.
prototype 속성에는 constructor 속성을 갖고 이는 생성자가 역할을 한 함수 객체를 가리킨다.
- 프로토타입 체인
어떤 프로퍼티를 참조 할 때, 찾고자 하는 프로퍼티가 객체에 없으면 [[Prototype]] 링크를 타고 끝까지 올라가면서 해당 프로퍼티를 찾는다.
어떤 프로퍼티를 할당할 때는 찾고자 하는 프로퍼티가 객체에 있으면 그 값을 바꾸지만, 프로퍼티가 없고 [[Prototype]]링크를 타고 올라가 해당 프로퍼티를 찾았을 경우 그 프로퍼티가 변경가능한 값이라면 새로운 직속 프로퍼티를 할당해서 상위 프로퍼티가 가려지는 현상이 발생한다. 변경 불가능 한 값이면 비엄격모드에선 무시되고, 엄격모드에는 에러가 발생한다.
function Func() {}
Func.prototype.num = 2;
var a = new Func();
console.log(a.num); // 2
a.num = 1;
console.log(a.num); // 1
console.log(Func.prototype.num) // 2
a.num에 Func.prototype.num이 가려지는 현상. defineProperty() 를 사용해서 변경불가능한 프로퍼티로 만들 수 있다.
관련 함수 및 연산자 확인 github.com/baeharam/Must-Know-About-Frontend/blob/master/Notes/javascript/prototype.md
== vs ===
- 둘다 동일 비교를 하지만 ===의 경우 타입변환이 일어나지 않으며, 타입까지 일치해야한다.
- 객체/배열의 경우 참조타입이기 때문에 둘다 동일하게 작동함.
- 문자열의 경우 원시타입이지만, 객체로도 만들 수 있기 때문에 동등 비교가 다르다.
- === 써라
엄격 모드
기존에 무시되던 에러들로 하여금 에러를 발생시키도록 하는 모드.
new의 동작방식
- 빈 객체를 생성한다
- [[Prototype]] 속성을 생성자 호출할 함수의 prototype 속성으로 지정한다. (만약 함수의 prototype 속성이 원시값이면 Object.prototype으로 지정)
- 객체를 생성하고 이 객체를 this로 지정한다
- 함수를 호출하고 해당 함수의 this 로 위에서 지정한 객체를 사용한다.
- 함수의 리턴값이 원시값이라면 새로 만들어진 객체가 리턴되고 객체라면 해당 객체가 리턴된다.
function Func() {}
const f = new Func();
- 빈 객체 생성 {}
- 해당 객체의 [[Prototype]] 을 Func.prototype 으로 지정
- 이 객체를 this 로 지정
- Func() 을 호출하고 이 함수에서 this 를 위 객체로 지정
- 함수의 리턴값이 undefined 원시값이므로 생성한 객체를 리턴