💡 현재 글은 미완성 단계입니다.
브라우저
브라우저에 URL을 입력하면 생기는 일
- URL해석
- 브라우저에 입력된 URL을 해석하여 해당하는 웹페이지의 호스트명, 프로토콜 정보를 추출
- DNS 조회 (분산형 DB)
- 호스트명을 IP주소로 변환하기 위해 DNS 서버에 쿼리를 보내고 DNS서버는 IP주소를 응답
- 이때 PC의 host 파일 - DNS cache - 공유기(라우터)의 DNS - ISP의 DNS를 먼저 확인하고 없다면 DNS 서버에 질의
- 접속자의 IP에 따라서 가장 가까운 CDN(GSBL)을 전달받을 수도 있음
- 서버연결
- 브라우저는 DNS 서버로 부터 얻은 IP 주소를 이용하여 해당 서버에 TCP 연결을 시도 (TCP 연결이 성공하면 HTTP requests가 보내짐)
- 이때 URL해석에서 얻은 프로토콜이 HTTPS 일 경우 TLS 핸드셰이크 과정을 거침.
- 서버에 요청 전송 및 응답
- TCP연결에 성공했다면 브라우저는 서버에 HTTP 요청을 보내고 서버는 해당하는 웹페이지의 내용에 포함된 HTTP응답 메세지를 전송 (HTML, CSS, JS 등의 파일을 받아옴)
- 서버로받은 HTML파일을 렌더링
브라우저 렌더링 과정
참고 : https://www.youtube.com/watch?v=z1Jj7Xg-TkU
- HTML 파싱 → DOM트리 생성
- 서버로부터 전달받은 HTML은 바이트스트림(8비트)으로 되어있는데 이를 문자열로 변경
- 토큰화과정을 진행. 브라우저가 가지고 있는 토큰과 비교하여 해당 문자가 HTML 파일인지 비교합니다. 이때 토큰은 시작 혹은 종료태그 속성, 속성값 등을 의미
- 토큰화과정에서 노드가 생성되고 노드가 모여 거대한 DOM트리가 생성
- DOM트리를 생성하는 과정에서
img
나link
같은 태그를 만나게 되면 태그안에 있는 리소스를 다운 - DOM트리를 생성하는 과정에서
script
태그를 만나게 되면 브라우저는 DOM생성을 중단하고script
태그안에있는 자바스크립트를 해석
- CSS 파싱 → CSSOM 트리 생성
- DOM 트리를 생성하는 과정과 유사
- 렌더트리 생성
- DOM 트리 + CSSOM 트리를 합쳐서 렌더트리를 생성한다
- 레이아웃 (리플로우)
- 위치, 크기, 계산 속성
- 요소의 크기나 좌표와 같은 좌표를 갖은 레이아웃 트리를 생성
- 이때 display:none 속성은 렌더트리에 포함되지 않음
position, left, top, right, weidth, hegith, margin, padding, border, display, float
등
- 페인트 (리페인트)
- 꾸미기 속성
- 렌더트리를 따라서 페인트 기록이 생성. 요소를 렌더링하는 순서나 여러개의 레이어로 나눈다음 텍스트, 색, 이미지 보더, 그림자 등 시각적인 부분을 그리는 과정을 지남
background, box-shadow, border-radius, border-style, color, outline
등
- Composite
- 페인트 단계에서 만든 여러가지 레이어를 하나로 합성하고 스크린에 픽셀로 나타내게 됨
- 수정이 일어난다면
- 렌더트리를 다시 생성하게 된다. (연산이 많이 일어나는 작업)
- 이때 수정된 부분이 어떤것인지에 따라서 리플로우 과정을 건너뛸 수 있다.
- 단
transform
,opacity
는 GPU가 관여하는 속성으로 DOM트리를 변경하지 않도록 설계되어 있기 때문에 리플로우 리페인트를 건너띌 수 있다.
HTTPS (Hyper Text Transfer Protocol Secure) 과정
참고 : https://www.youtube.com/watch?v=H6lpFRpyl14
- 핸드셰이크 과정을 거침. 클라이언트는 랜덤데이터를 서버에 보내고 서버는 응답으로 랜덤데이터와 인증서를 함께 보냄
- 클라이언트는 전달받은 인증서가 진짜인지 브라우저에 내장된 CA들의 정보를 통해 확인함
- 인증서는 CA의 개인키로 암호화되어 있고 브라우저에 저장된 CA의 공개키로 복호화를 합니다. 이때 복호화에 성공하면 서버로부터 받은 인증서는 검증된 것임. 복호화할 수 없다면 안전하지 않은 페이지로 Warning이 표시됨
- 복호화된 인증서에는 서버의 공개키가 포함되어 있음.
- 핸드셰이크때 이용한 랜덤데이터를 서버의 공개키로 암호화해서 서버로 보내지게되고 양쪽에서 일련의 과정을 통해 동일한 대칭키를 갖게 됨
- 서버와 클라이언트는 대칭키를 이용해서 데이터를 암호화하여 주고 받게됩니다. (계속 비대칭키를 이용하면 연산이 많아지기 때문 즉, 비대칭키로 만든 대칭키를 사용하게됩니다.)
URL vs URI
- URI (Uniform Resource Identifier)
- 정의: 웹 상의 자원을 식별하는 유일한 주소입니다. URI는 리소스를 찾기 위한 일반적인 용어로, URL과 URN을 포함하는 상위 개념입니다.
- 예시: https://example.com/path/to/resource 이것은 리소스를 찾기 위한 전체적인 주소를 나타냅니다.
- URL (Uniform Resource Locator)
- 정의: 리소스가 실제로 위치한 곳을 가리키는 주소입니다. URL은 리소스에 접근하기 위한 구체적인 위치 정보를 제공합니다.
- 구성 요소: 프로토콜(예: http, https), 호스트 이름(도메인 이름 또는 IP 주소), 포트 번호(선택적), 경로(리소스가 있는 위치), 쿼리 문자열(선택적), 프래그먼트(선택적) 등을 포함합니다.
- 예시: https://www.example.com/articles/uri-vs-url-vs-urn 이것은 웹 상의 특정 자원을 찾기 위한 구체적인 위치를 나타냅니다.
- URN (Uniform Resource Name)
- 정의: 리소스의 위치와 무관하게 리소스를 유일하게 식별하는 이름입니다. URN은 리소스가 실제로 어디에 있는지, 혹은 어떻게 접근해야 하는지와는 관계없이 리소스를 식별하기 위한 영구적인 이름을 제공합니다.
- 용도: 주로 도서관, 문서 아카이브 등에서 문서나 출판물 등의 리소스에 대한 영구적인 식별자로 사용됩니다.
- 예시: urn:isbn:0451450523 이것은 특정한 책을 식별하기 위한 ISBN 코드를 나타냅니다.
Javascript
Prototype
참고 - https://www.youtube.com/watch?v=wUgmzvExL_E
|
|
-
prototype은 무엇인가요?
- JS는 프로토타입 기반 언어로 객체의 상속이 프로토타입으로 이루어집니다. 프로토타입은 특정 객체 유형의 모든 인스턴스가 공유하는 객체입니다. 이 속성은 메서드와 속성을 상속하기 위해 사용됩니다.
-
prototype chain은 무엇인가요?
- 객체가 속성이나 메서드에 접근하려고 시도할 때, 해당 속성이나 메서드를 찾기 위해 JS엔진이 따르는 경로입니다. 객체에서 직접 속성이나 메서드를 찾을 수 없는 경우, JS는 객체의 프로토타입 (즉 그 객체의 생성자 함수의 prototype)으로 이동하여 거기에서 속성이나 메서드를 찾는데 이 과정은 프로토타입 체인의 최상단에 도달할때 까지, 즉 null이 프로토타입으로 설정될 때 까지 반복됩니다.
- 즉 프로토타입을 계속 상속하는데 필요한 속성이나 메서드에 접근할때 찾을 때 까지 상위 객체로 올라가게 되는데 이것을 프로토타입 체인이라고 합니다.
-
function.bind가 되는 이유는 무엇인가요?
- 자바스크립트의 모든 함수가 Function 객체의 인스턴스인데 function 객체의 프로토타입에 정의되어 있기에 모든 함수에서 bind를 사용할 수 있습니다.
- function.bind는 새로운 함수를 생성하며, 이 새로운 함수의 this가 bind 메서드에 전돨된 값으로 설정됩니다. 이는 함수가 호출될 때 주어진 this 값과 인자들을 사용하여 실행되도록 합니다. bind는 함수의 실행 컨텍스트를 명시적으로 설정할 때 유용하며 특히 콜백 함수나 이벤트 핸들러에서 this의 값이 예상대로 설정되지 않을때 문제를 해결하는데 사용됩니다.
-
상속은 어떻게 구현하나요?
-
생성자 함수인 경우에는 프로토타입 체인을 사용하여 상속을 구현할 수 있습니다. 하위 클래스(생성자함수)의 프로토타입을 상위 클래스의 인스턴스로 설정함으로써 이루어집니다. 생성자 함수에서는
.prototype
객체에 직접 하려면.__proto__
명령어로 상속을 진행할 수 있습니다.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
const Bmw = function (color) { this.color = color; }; Bmw.prototype.wheels = 4; Bmw.prototype.drive = function () { console.log("Drive"); }; Bmw.prototype.navigation = 1; Bmw.prototype.stop = function () { console.log("Stop"); }; const ix3 = new Bmw("red"); // ix3 instanceof Bmw --> true const x5 = new Bmw("blue"); // x5.constructor === Bmw --> true // 프로토타입을 아래처럼 한번에 선언하게되면 consturctor가 사라지게됨 // x5.constructor === Bmw --> false // 그래서 한줄씩 풀어서 쓰는거나 Bmw.prototype = { constructor: Bmw, // constructor를 직접 명시해야함 wheels: 4, drive() { console.log("Drive"); } navigation: 1, stop() { console.log("Stop"); }, }
-
Class인 경우에는 extends를 사용하여 클래스간에 상속을 정의할 수 있으며 이때 상위 클래스의 내용이 Prototype으로 상속됩니다. 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
class Car { constructor(color) { this.color = color; this.wheels = 4; } dirve() { console.log("Drive.."); } stop() { console.log("Stop!"); } } class Bmw extends Car { constructor(color) { // 부모클래스의 constructor를 오버라이딩 해야하기 때문에 동일한 color 인자를 받아야함 super(color); // constructor에서 this를 빈 객체 {} 로 받아와 리턴하는데 상속받는 경우에 이 과정을 건너뛰기 때문에 super를 사용하여 부모 클래스의 constructor를 super를 이용하여 선언해야함 this.navigation = 1; } // constructor 생성자를 따로 호출하지 않으면 아래처럼 실행됨 // constructor(..args){ // super(...args); //} park() { console.log("Park"); } stop() { console.log("Why"); // 이때 프로토타입 체인을 통해서 부모클래스 까지 가지 않고 메서드 오버라이딩이 되어버림 super.stop(); // 부모 클래스의 stop을 사용하려면 이렇게 } }
-
this
참고 : https://www.youtube.com/watch?v=tDZROpAdJ9w
-
this는 무엇인가요?
- this는 현재 실행 컨텍스트의 객체를 참조하는 식별자입니다. 즉, 현재 코드가 실행되고 있는 “주변 환경"을 가리킵니다. 함수 내에서 this의 값은 그 함수가 호출되는 방식에 따라 달라집니다.
-
this는 언제 결정되나요?
- this의 값은 함수가 호출될 때 결정됩니다. 주요 규칙은 다음과 같습니다
- 전역 컨텍스트에서 this는 전역 객체를 가리킵니다.
- 브라우저에서는 window, Node.js에서는 global 객체가 됩니다.
- 객체의 메서드로서 호출될 때, this는 그 메서드를 호출한 객체를 가리킵니다.
- 생성자 함수에서, this는 새로 생성되는 객체 인스턴스를 가리킵니다.
- 이벤트 핸들러에서, this는 이벤트를 받는 DOM 요소를 가리킵니다.
-
Arrow Function에서의 this는 무엇인가요?
- 화살표 함수(arrow function)에서의 this는 다릅니다. 화살표 함수는 자신의 this를 가지지 않고, 대신에 함수가 생성될 때의 this값을 “렉시컬하게” 바인딩합니다. 즉, 화살표 함수 내부에서의 this는 화살표 함수를 둘러싼 외부 스코프의 this와 같습니다.
-
this를 변경하는 방법은 무엇인가요?
- 참조 : https://www.youtube.com/watch?v=KfuyXQLFNW4
- JavaScript에서는 call, apply, 그리고 bind 함수를 이용해 함수 호출 시 this의 값을 명시적으로 설정할 수 있습니다.
- call과 apply는 함수를 즉시 호출하면서 첫 번째 인자로 this를 설정합니다. call은 개별 인자를, apply는 인자 배열을 받습니다.
- bind는 함수의 this값을 영구히 바꿀 수 있는 새 함수를 반환합니다. 이는 Function.prototype에 정의되어 있으며, bind를 호출하는 함수의 복사본을 생성하고, 이 복사본에서 this의 값을 첫 번째 인자로 전달된 값으로 고정합니다.
Scope
-
스코프란 무엇인가요?
- 변수이름, 함수이름, 클래스이름 과같은 식별자가 본인이 선언된 위치에 따라 다른 코드에서 자신이 참조될 수 있을지 없을지 결정되는 것
-
스코프 체인이란 무엇인가요 ?
- 스코프는 함수의 위치에 따라서 계층적인 구조를 가질 수 있음 이렇게 계층적인 구조로 연결된 것을 스코프체인이라고 함
- 예를들어 Inner scope > Outer Scope > 전역 스코프 처럼 계층적인 구조임
- 변수를 참조할때 JS 엔진은 스코프 체인을 통해 변수를 참조함
- 아래에서 위로 반방향성으로만 존재하여 하위스코프는 상위스코프를 참조할 수 있지만 반대는 되지 않음
-
스코프 레벨이란 무엇인가 ?
- 블록 레벨 스코프 (if, for) = ES6의 let, const
- 함수 레벨 스코프 = 함수
-
동적스코프 - 함수가 호출되는 시점에 결정
-
정적스코프(렉시컬스코프) - 함수가 정의되는 시점에 결정 자바스크립트에서 함수는 상위 스코프를 참조하기 때문에 본인의 내부 슬롯에 상위 스코프에 대한 참조를 저장합니다.
-
함수가 호출되면 실행되는 과정은 ?
- 함수호출 -> 실행 컨텍스트 생성 -> 실행 컨텍스트 스택 푸쉬 -> 렉시컬 환경 생성 (식별자, 식별자에 바인딩 된 값, 상위 렉시켤 환경에 대한 참조) -> 실행 컨덱스트 스택 POP
Closure
참고 : https://www.youtube.com/watch?v=tpl2oXQkGZs
|
|
- 클로져는 무엇인가요?
- 상위 스코프의 식별자를 참조하고 있음.
- 클로져를 활용한 구현경험
- 커링이 무엇인지
- 고차함수는 무엇인지
- 스코프-클로져
Functional Programming
- 배열의 고차함수 어떤것을 사용하는지
- reduce를 어떻게 구현하는지
- 합성은 상속과 어떤 장점이 있는지
- Immutable 장단점은 어떤것이 있는지
OOP
- ES lasses 상속은 어떻게 하고 캡슐화는 어떻게하는지
- 객체를 나누는 단위는?
- 의존성을 낮추는 방법은? (사례중심)
비동기
-
Promise, async/await 차이는?
1 2 3 4 5 6 7 8 9 10 11
new Promise 는 state와 result를 property로 갖음 state: pending result: undefined resolve(value) resolve가 실행되면 state: fulfilled (이행됨) result: value reject(error) 실패하면 state: rejected(거부됨) result: error
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
const pr = new Promise((resolve, reject) => { // resolve -> 성공한 경우 실행되는 Callback 함수 // reject -> 실패한 경우 실행되는 Callback 함수 }); pr.then( function (result) {}, // 이행되었을 때 실행 function (err) {} // 거절되었을 때 실행 ); // catch를 이용하여 명확하게 구분할 수 있음 pr.then(function (result) {}) .catch(function (err) {}) .finally(function () { // 이행이 되었든 거절이되었든 처리가 완료되면 항상 실행됨 ex) 로딩화면 없애기 console.log("끝"); });
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
const order1 = () => { return new Promise((res, rej) => { setTimeout(() => { res("1번주문완료"); }, 1000); }); }; const order2 = (message) => { console.log(message); return new Promise((res, rej) => { setTimeout(() => { rej("2번주문실패"); }, 3000); }); }; const order3 = (message) => { console.log(message); return new Promise((res, rej) => { setTimeout(() => { res("3번주문완료"); }, 2000); }); }; // promise chain // 하나의 작업이 완료되면 다시 넘어감 총 1 + 3 + 2 = 6초가 걸림 order1() .then((res) => order2(res)) // "1번주문완료" 출력 후 reject .then((res) => order3(res)) // 실행되지 않음 .then((res) => consol.log(res)); // 실행되지 않음 .catch(console.log) // "2번주문실패" 출력 .finally(()=> {console.log("끝")}) // "끝" 출력 // async await 사용하면 이렇게 바꿀 수 있음 // promise then을 사용하는 것보다 가독성이 좋고 명확하게 보여짐 async function order() { try{ const result1 = await order1(); const result2 = await order2(result1); const result3 = await order2(result2); console.log(result3); } catch (e) { console.log(e) } console.log("끝"); } order(); // Promise.all // 비동기로 실행 모든 작업이 완료될때 까지 기다리는데 3초정도 걸림 // 만약 하나라도 reject가 되면 에러 발생함 따라서 모든 값들이 필요할때 사용하면 됨 // 전부 성공하면 ["1번주문완료", "2번주문완료", "3번주문완료"] Promise.all([order1(), order2(), order3()]).then(res)=>{ console.log(res); } // async await 사용하면 이렇게 바꿀 수 있음 // promise then을 사용하는 것보다 가독성이 좋고 명확하게 보여짐 async function order() { try{ const result = await Promise.all([order1(), order2(), order3()]); } catch (e) { console.log(e) } } order(); // Promise.race // 하나라도 끝나는 작업이 있으면 리턴함 // "1번주문완료" 가 1초만에 출력되고 종료됨 // 이행되든 거부되든 가장 빠른걸 먼저 출력 Promise.race([order1(), order2(), order3()]).then(res)=>{ console.log(res); } // Promise.any // 프로미스중에 가장 먼저 이행된 객체 반환 Promise.any([order1(), order2(), order3()]).then(res)=>{ console.log(res); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14
async function getName() { // 함수앞에 async를 붙히면 Promise를 반환하게됨 return "cha2hyun"; } console.log(getName()); // Promise {<fulfilled>:"cha2hyun"} getName().then((name) => console.log(name)); // cha2hyun function getName() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(name); }, 1000); }); }
1 2 3 4 5 6 7
async function showName() { const result = await getName("cha2hyun"); // Promise가 끝날때 까지 기다림 즉 1초후에 이름이 찍힘 console.log(result); } console.log("시작"); // "시작" 찍히고 showName(); // 1초후에 "cha2hyun" 찍힘
-
promise 패턴 설명
-
setTimeout에 Promise를 적용하면?
-
동시에 여러개의 관계없는 요청을 한다면?
-
Task queue vs Micro task queue?
Generator
-
generator란 ?
-
함수의 실행을 멈추었다가 다시 실행할 수 있음
-
Symbol.iterator 메서드가 있음. iterator를 반환함 예시) 배열, 문자열
-
iterator는 next 메서드를 가지고 value와 done 속성을 가진 객체를 반환한다
-
작업이 끝나면 done은 true를 갖는다
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
// 함수 앞에 *을 붙힘 function* fn() { try { console.log("1"); yield 1; console.log("2"); yield 2; console.log("3"); yield 3; return "finish"; } catch (e) { console.log(e); } } const a = fn(); // next() // a -> fn{<suspended>} // a.next -> "1" {value: 1, done: false} // a.next -> "2" {value: 2, done: false} // a.next -> "3" {value: 3, done: false} // a.next -> {value: "finish", done: true} // a.next -> {value: undefined, done: true} // return() // a -> fn{<suspended>} // a.next -> "1" {value: 1, done: false} // a.return("end") -> {value: end, done: true} // a.next -> {value: undefined, done: true} // throw() // a -> fn{<suspended>} // a.next -> "1" {value: 1, done: false} // a.throw(new Error('err')) -> "Error: err" {value: undefined, done: true}
-
객체
- 객체 표현 방식중 자주 사용하는지?
- class, prototype, literal 차이
- 자주 사용하는 메서드는?
- JSON 데이터 파싱시 가장 신경쓰이는 것은?
- 대문자 객체와 소문자 객체는 무엇이 차이있는지 (Object vs object)
- 얕은복사와 깊은복사
이벤트 실행방법
- 이벤트 버블링, 이벤트 캡쳐링
타입스크립트
-
Pick, Omit
-
접근제한자
- public - 자식클래스, 클래스인스턴스 모두 접근 가능
- protected - 자식 클래스에서 접근 가능 인스턴스에서는 접근 불가
- private - 해당 클래스 내부에서만 접근 가능 (변수명 앞에 #을 찍는걸로 할 수 있음)
- readonly - 수정할 수 없게 (constructor에서만 수정할 수 있음)
- static - this로 선언 못하고 class 명으로 선언해야함
-
추상클래스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// 추상클래스 abstract class Car { // class 앞에 abstract가 있으면 추상클래스로 선언됨 color: string; constructor(color: string) { this.color = color; } start() { console.log('start'); } abstract doSomething():void; } const car = new Car("red") // abstract class는 new로 선언할 수 없음 class Bmw extends Car { constructor(color: string) { super(color); } doSomething() {} // doSomething이 abstract이기 때문에 오버라이드해서 구현을 꼭 해야함 } const car = new Bmw("red") // 호출할 수 있게됨
-
Generic
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// 유니온 타입 이용시 function getSize(arr: number[] | string[] : boolean[]: object[] ): number { return arr.length; } const arr1 = [1, 2, 3]; const arr2 = ["a", "b", "c"]; const arr3 = [true, false, true]; const arr4 = [{}, {}, { name: "cha2hyun" }]; // Generic 타입 이용시 function getSize<T>(arr: T[]): number { return arr.length; } const arr1 = [1, 2, 3]; const arr2 = ["a", "b", "c"]; const arr3 = [true, false, true]; const arr4 = [{}, {}, { name: "cha2hyun" }]; getSize<number>(arr1);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// any type interface Mobile { name: string; price: number; options: any; } // Generic type interface Mobile<T> { name: string; price: number; options: T; } const m1: Mobile<string> = { name: "cha2hyun", price: 900, options: "good", }; const m2: Mobile<{ color: string }> = { name: "cha2hyun", price: 900, options: { color: "red" }, };
-
keyof : property 키값을 union type으로
1 2 3 4 5 6
interface User { id: number; name: string; } type UserKey = keyof User; // 'id' | 'name' const uk:UserKey = "id"
-
Partial : property를 모두 optional로 변경
1 2 3 4 5 6 7 8 9 10 11 12
interface User { id: number; name: string; } // 이렇게하면 name이 없어서 에러 let admin: User = { id: 1, }; // Partial을 쓰면 User 프로퍼티가 모두 Optional로 변경되서 사용 가능 let admin: Partial<User> = { id: 1, };
-
Required : property를 모두 필수로 바까줌
1 2 3 4 5 6 7 8 9 10 11 12
interface User { id: number; name?: string; } // 이렇게하면 name은 옵셔널이기 때문에 에러가 발생하지 않음 let admin: User = { id: 1, }; // 에러발생 옵셔널을 모두 필수로 바꾸어서 name도 필수값이 됨 let admin: Required<User> = { id: 1, };
-
Record<K, T>
1 2 3 4 5 6 7 8
type Grade = "1" | "2" | "3" | "4"; type Score = "A" | "B" | "C" | "D"; const score: Record<Grade, Score> = { 1: "A", 2: "B", 3: "C", 4: "D", };
기타
- generateor가 무엇인가요?
- ES Next 관심있는 문법은?
- 정규표현식은 무엇이고 언제사용하는지?
Debugging
- 버그 문제를 어떻게 해결하는지?
- 본인만의 디버깅 방식은?
- calling stack?
- network 오류 상황에 어떻게 확인하는지? (break 포인트?)
null vs undefined
-
null과 undefined는 JavaScript에서 “없음"을 나타내는 두 가지 다른 값입니다. 둘 사이에는 몇 가지 주요 차이점이 있습니다
-
의미적 차이
- undefined는 변수가 선언되었지만 값이 할당되지 않은 상태를 나타냅니다. 즉, 변수의 값이 아직 정의되지 않았음을 의미합니다.
- null은 변수에 값이 없음을 의도적으로 나타내는 데 사용됩니다. 즉, 변수가 “비어있음” 또는 “아무것도 가리키지 않음"을 의도적으로 표현할 때 사용합니다.
-
타입:
- typeof undefined는 “undefined"를 반환합니다.
- typeof null은 오래된 JavaScript의 버그로 인해 “object"를 반환합니다. 이는 null이 실제로는 기본 타입임에도 불구하고 발생하는 일종의 이상한 결과입니다.
-
기본값:
- 함수에서 명시적인 반환값이 없을 경우 undefined를 반환합니다.
- 변수를 선언만 하고 초기화하지 않았을 때, 그 변수의 기본값은 undefined입니다.
-
사용 상황:
- undefined는 주로 JavaScript 엔진에 의해 할당되며, 개발자가 직접 사용하는 경우는 드뭅니다.
- null은 개발자가 변수에 ‘값이 없음’을 명시적으로 나타내고 싶을 때 사용합니다.
- 이러한 차이점에도 불구하고, null과 undefined는 둘 다 “없음"을 나타내기 때문에, 느슨한 동등 연산자(==)를 사용하여 비교할 경우 서로 같다고 평가됩니다(null == undefined는 true를 반환). 그러나, 엄격한 동등 연산자(===)를 사용할 경우, 이 두 값은 서로 다르다고 평가됩니다(null === undefined는 false를 반환).