Ch.Covelope

프론트(FE) 면접 질문 리스트 본문

front_end

프론트(FE) 면접 질문 리스트

Chrysans 2024. 8. 6. 18:49
728x90
반응형

 브라우저에 URL을 입력했을 때 일어나는 일

1. URL 파싱   

  - 브라우저는 입력된 URL을 파싱 하여 프로토콜, 도메인, 경로 등을 분석합니다.

 

    URL : 리소스 위치를 나타내는 표준화된 주소 체계(고유한 식별자)

    프로토콜 (protocol) : 웹 브라우저가 서버와 통신하는 방법

    도메인(domain) : 웹사이트의 고유한 이름

    경로(path) : 웹 서버 내의 특정 리소스 위치

 

2. DNS 조회    

 - 먼저 브라우저 캐시, 운영체제 캐시, 라우터 캐시, ISP 캐시를 확인합니다.    

 - 캐시에 없다면, ISP(인터넷 서비스 제공업체 SK, KT 등)의 DNS 서버에 쿼리를 보냅니다.    

 - 브라우저는 도메인 이름을 IP 주소로 변환하기 위해 DNS 조회를 시작합니다.

 

3. IP 주소 획득    

 - DNS 서버는 해당 도메인의 IP 주소를 반환합니다.

 

4. TCP ( Transmission Control Protocol(전송 제어 프로토콜)) 연결 설정    

  - 브라우저는 획득한 IP 주소로 TCP 연결을 시도합니다.

   (TCP 는 데이터 전송 보장, 연결 지향, 흐름제어(속도 조절), 순서보장)    

 

 - 3-way 핸드셰이크 과정을 통해 연결을 설정합니다.

 (서버와 클라이언트가 모두 데이터를 주고받을 수 있는 준비가 되었다는 걸 보장하기 위해서)

 

5. HTTPS의 경우 TLS 핸드셰이크    

  - HTTPS 프로토콜을 사용하는 경우, TLS 핸드셰이크를 통해 암호화 연결을 설정합니다.

 

6. HTTP 요청 전송    

 - 브라우저는 서버에 HTTP GET 요청을 보냅니다.    

 - 요청 헤더에는 쿠키, 사용자 에이전트 등의 정보가 포함됩니다.

 

7. 서버 응답 처리    

 - 웹 서버는 요청을 처리하고 응답을 생성합니다.    

 - HTTP 응답에는 상태 코드, 헤더, 본문(HTML, CSS, JavaScript 등)이 포함됩니다.

 

8. 콘텐츠 렌더링    

 - 브라우저는 받은 HTML을 파싱하여 DOM 트리를 생성합니다.    

 - CSS를 파싱하여 CSSOM을 생성하고, JavaScript를 실행합니다.    

 - 렌더 트리를 구성하고 레이아웃을 계산한 후 화면에 페이지를 그립니다.

 

 콘텐츠 렌더링 추가 설명  

 

TCP/TLS 연결 및 GET 요청

 

서버로부터 HTML 문서를 받으면 브라우저는 파싱 과정을 시작합니다.

 

토큰화(Tokenization):

  • HTML 문자열을 토큰으로 변환합니다.

토큰 객체화:

  • 각 토큰을 해당 특성을 나타내는 객체로 변환합니다.
  • 이 객체들은 토큰의 유형(시작 태그, 종료 태그, 속성, 텍스트 등)과 관련 정보를 포함합니다.
예:

"<p>" 토큰 → { type: "startTag", tagName: "p" }

"Hello" 토큰 → { type: "text", content: "Hello" }

"</p>" 토큰 → { type: "endTag", tagName: "p" }

 

이렇게 생성된 객체를 DOM 노드로 변환 

예:

{ type: "startTag", tagName: "p" } → new HTMLParagraphElement() 
{ type: "text", content: "Hello" } → new Text("Hello")

 

해당 노드들을 트리 자료구조인 DOM 생성

 

** 간략

 브라우저가 받은 HTML 텍스트를 파싱 합니다

a) 토큰화: 텍스트를 개별 토큰으로 분리합니다.

b) 객체 변환: 각 토큰을 특성을 나타내는 객체로 변환합니다.

c) 노드 생성: 이 객체들을 DOM 노드로 변환합니다.

d) DOM 트리 구성: 노드들을 트리 구조로 연결하여 DOM 트리를 만듭니다.

CSSOM 트리도 위와 같은 방식으로 생성되지만 dom은 문서의 구조를 반영 CSSOM  은 스타일 규칙의 계층과 우선순위를 반영한 트리 구조를  가지고 있다.

 

DOM 트리 CSSOM 트리를 결합하여 렌더트리를 생성한다 

 

렌더 트리의 노드들이 가지는 스타일과 속성에 따라 브라우저 화면의 위치와 크기를 계산하는 레이아웃 과정을 거쳐서 화면의 픽셀을 렌더링 하는 페인팅 과정이 진행됩니다.

리플로우와 리페인트는 초기 렌더링 이후에도 발생할 수 있고 리플로우는 항상 리페인트를 동반하는데 화면에 레이아웃이 변경되는 돔 요소의 추가 제거 위치 변경 폰트 변경등의 작업에서 리플로우와 리페인트가 진행되고 단순 컬러 변경같이 레이아웃에 영향을 미치지 않은 것들은 리페인트만 진행됩니다.

 

위 과정들 중 스크립트를 만나게 되면 (렌더링 엔진 -> 자바스크립트 엔진으로 제어권 넘김)

 

 

※ 제어권이 넘어가면

 

1. script 태그를 만나면

  • HTML 파싱이 일시 중지됩니다.
  • 스크립트 파일을 다운로드합니다.
  • 다운로드가 완료되면 스크립트를 실행합니다.
  • 실행이 완료된 후 HTML 파싱이 재개됩니다.

2. 인라인 스크립트를 만나면

  • HTML 파싱이 일시 중지됩니다.
  • 스크립트가 즉시 실행됩니다.
  • 실행이 완료된 후 HTML 파싱이 재개됩니다.

 

SPA(Single Page Application) 의 경우- HTML 문서는 초기 한 번만 불러옵니다.

- 간단한 초기 HTML을 불러오는데 빈 컨테이너와 주요 스크립트 파일 참조만 포함합니다. (렌더링 될 태그의 id)

- 간단하기 때문에 파싱이 빠르게 완료되고 대부분의 콘텐츠는 이후 JS에 의해 동적 생성

 

호이스팅

 변수 및 함수 선언문이 스코프 내의 최상단으로 끌어올려지는 듯한 현상을 말합니다.
여기서 주의할 점은 "선언문"이라는 것이며 "대입문"(변수에 값을 할당하는 문장)은 끌어올려지지 않습니다.

선언문은 변수나 함수를 생성하는 문장이고
대입문은 이미 선언된 변수에 값을 할당하는 문장입니다.

"var, let, const 모두 호이스팅 됩니다. 하지만 그 동작에 차이가 있습니다.

var: 호이스팅 되면서 undefined로 초기화됩니다. 따라서 선언 전에 접근하면 undefined를 반환합니다.
let과 const: 호이스팅 되지만 초기화되지 않은 상태로 남아있습니다. 
이 상태를 'Temporal Dead Zone(TDZ)'이라고 합니다. TDZ에서 변수에 접근하려고 하면 ReferenceError가 발생합니다.

 

스코프

스코프란 변수(식별자)에 접근할 수 있는 유효한 범위를 뜻합니다.

 

스코프 체인

스코프 체인이란, 현재 스코프에서 식별자를 검색할 때 상위 스코프를 연쇄적으로 찾아나가는 방식을 의미합니다.
변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 해당 변수를 참조하는 
코드의 스코프부터 상위 스코프 방향으로 이동하며 선언된 변수를 검색합니다.

 

실행 컨텍스트(Execution Context)

JavaScript 엔진이 코드를 실행할 때 생성하는 환경입니다. 간단히 말해, 코드가 실행되는 범위와 그 안에서 사용할 수 있는 변수, 함수 등의 정보를 담고 있는 객체라고 할 수 있습니다.

 

 

실행 컨텍스트

                                                                   |                                          |

렉시컬 환경                      변수 환경

         |                                           

 환경 레코드                                    

외부 렉시컬 환경 참조                                  

 

 

변수 환경 (Variable Environment)

var 키워드로 선언된 변수들의 바인딩을 저장하는 데 사용됩니다

함수 선언문으로 정의된 함수들도 변수 환경에서 관리됩니다.

 

렉시컬 환경(Lexical Environment)

변수 식별자, 해당 변수에 바인딩된 값을 가지고
스코프 체인을 포함하는 자료 구조입니다. 함수를 호출할 때마다 새로운 렉시컬 환경이 생성되며, 
함수의 실행 컨텍스트에 대한 정보를 담고 있습니다. 그리고 함수 실행이 종료되면 해당 렉시컬 환경은 제거됩니다.

 

환경 레코드 (Environment Record)

환경 레코드는 특정 스코프 내의 식별자들과 그들의 바인딩을 기록하는 역할을 합니다.

 

외부 렉시컬 환경 참조 (Outer Lexical Environment Reference)

해당 렉시컬환경의 부모 렉시컬 환경 참조값을 가지고 있습니다.

 

this바인딩

실행 컨텍스트가 생성될 때 this 바인딩이 결정됩니다.

이는 함수가 호출되는 시점이나 전역 컨텍스트가 생성되는 시점입니다.

함수가 어떻게 호출되었는지에 따라 this가 결정됩니다.

 

 

  • 일반 함수 호출: this는 전역 객체에 바인딩 (strict mode에서는 undefined)
  • 메서드 호출: this는 메서드를 소유한 객체에 바인딩
  • 생성자 함수 호출: this는 새로 생성된 객체(인스턴스)에 바인딩
  • call, apply, bind 메서드 사용: this는 명시적으로 지정된 객체에 바인딩
  • 화살표 함수: this는 상위 스코프의 this를 그대로 사용 (렉시컬 this)

 

ajax

웹 페이지의 일부분만을 비동기적으로 서버와 통신하고 업데이하는 기술 방식으로 비동기 통신을 위한 패러다임
이를 fetch api 나 axios를 사용하여 구현

 

ajax 이전에 웹 개발에서는 사소한 변경에도 항상 전체 페이지(html)를 다시 로드해야 했고 그로 인해 서버 부하 사용자 경험 등이 좋지 못했습니다.

 

 

Sync(동기)와 Async(비동기)의 차이

Sync는 요청을 보내고 해당 요청에 대한 응답을 기다리는 것을 의미하고, Async는 요청에 대한 응답을 기다리지 않고 다음 동작을 수행하는 것을 의미합니다.
예시로 alert와 같은 작업은 블로킹이고 setTimeout, fetch와 같은 작업들은 논블로킹입니다.

 

 

콜백함수

콜백 함수는 다른 함수에 인자로 전달되어, 그 함수의 실행이 끝난 후에 실행되는 함수입니다.

이벤트 핸들링, 배열 메서드,비동기 작업 처리(비동기 완료 이후 작업 처리) 등에서 사용됩니다.

 

고차함수

하나 이상의 함수를 인자로 받거나 함수를 리턴하는 함수이며 함수를 값처럼 다루는 게 특징입니다.

 

map, filter, forEach 등 함수를 인자로 받는 메서드 등

 

콜백지옥

 

콜백 지옥이란 비동기 처리를 위해 연속적으로 콜백 함수를 사용할 때, 들여 쓰기 수준이 매우 깊어지는 문제입니다.
콜백지옥은 콜백함수의 중첩이 깊어질수록 코드를 이해하기 어렵게 만들고, 디버깅이나 유지보수를 어렵게 만들어서 생산성을 저하시키는 문제가 있습니다.
콜백 지옥을 해결하는 방법에는 Promise 나 async/await을 사용하는 방법이 있습니다.

 

Promise

Promise는 자바스크립트 비동기 처리 패턴 중 하나로, 비동기적으로 처리되는 작업의 결과를 나타내는 객체입니다. 기존의 사용하던 콜백 방식의 약점을 보완하여 나온 패턴으로 가독성을 높이고 콜백지옥을 피할 수 있으며 비동기 처리 시점을 명확히 표현할 수 있습니다.
Promise는 세 가지 상태(state)를 가질 수 있습니다. 비동기 작업이 아직 수행되지 않은 상태인 pending, 비동기 작업이 성공적으로 완료된 fulfilled 상태, 비동기 작업이 실패한 rejected 상태가 있습니다.
Promise를 생성할 때는 Promise 생성자 함수를 호출하면 됩니다. Promise 생성자 함수는 비동기 작업을 수행하고, 작업이 완료되면 Promise 객체를 반환합니다.

 

async/await

 비동기 작업을 동기적인 코드처럼 보이게 하여 가독성과 유지보수성을 향상하는 방법입니다.
async 함수는 함수 앞에 async 키워드를 붙여 선언합니다. 이 함수는 Promise를 반환하며, 함수 내부에서 await 키워드를 사용하여 Promise가 처리될 때까지 기다리게 됩니다. 이때, async 함수는 Promise를 기다리는 동안 다른 작업을 수행할 수 있습니다.
async/await는 Promise를 보다 직관적이고 간결하게 사용할 수 있도록 해주며, then()과 catch() 메서드를 사용하지 않아도 되므로 가독성이 향상됩니다. 또한, try-catch 블록을 사용하여 에러 처리를 보다 간편하게 할 수 있습니다. 

 

 

자바스크립트가 싱글스레드를 갖고 있음에도 어떻게 비동기 처리를 하나요?

브라우저로 예를 들어 브라우저의 여러 스레드 중 하나(메인 또는 렌더러 스레드)가 자바스크립트 엔진을 실행합니다.

자바스크립트 엔진은 내부적으로 싱글 스레드로 동작하게 설계되어 있습니다.

그럼에도 자바스크립트는 동기와 비동기를 병렬적으로 실행할 수 있습니다.

 

 이유는 자바스크립트 런타임 환경(브라우저 또는 노드 JS)에서  자바스크립트 엔진이 아닌, 호스트 환경에 의해 이벤트 루프가 실행 관리 되는데 동기 코드는 콜 스택에서 즉시 실행되고 비동기 작업은 Web APIs로 보내져 백그라운드에서 처리됩니다. 이때 작업이 완료되면 콜백 함수가 콜백 큐로 넘어가게 되고 이벤트 루프는 콜 스택을 감지해 비어있다면 콜백 큐의 함수를 콜 스택으로 이동시킵니다.

 

이러한 메커니즘을 통해 자바스크립트는 싱글 스레드로 동작하면서도 비동기를 처리할 수 있습니다.

 

동기 비동기 실행 과정

- 동기 -> 콜스택  -> 실행

 

- 비동기 식별(엔진)  -> 백그라운드 처리(Web APIs 또는 Node.js) -> 콜백 큐에 콜백 넘김(호스트) ->  콜 스택 이동(이벤트 루프) -> 실행

 

이벤트 루프의 주요 역할

 

- 콜 스택과 콜백 큐 모니터링 

- 콜백 실행 조정 (콜 스택이 비어있고 콜백 큐에 대기 중이 작업이 있으면 콜백을 콜 스택으로 이동)

- 실행 순서 관리 

  • 마이크로태스크 큐[promise 콜백]의 작업을 태스크 큐[setTimeout] 보다 우선적으로 처리합니다.
  • 모든 마이크로태스크 큐를 처리한 후에 태스크를 처리합니다.

 

 

모듈(module)이란?

 

"모듈" 이란 코드와 데이터의 묶음 이며 Node 환경에서는 분리된 파일 1개를 의미합니다.

기능별로 분리되고 재사용성이 좋아 개발 효율성과 유지보수성을 높인다.

 

자바스크립트에서의 모듈

 

  • RequireJS: AMD(Asynchronous Module Definition) 형식을 사용하는 모듈 로더입니다.
  • Browserify: Node.js 스타일의 require() 함수를 브라우저에서 사용할 수 있게 해줍니다.
  • Webpack: 모듈 번들러로, 다양한 형식의 모듈을 지원하며 자산 관리 기능도 제공합니다.
  • Rollup: ES6 모듈에 최적화된 번들러로, 트리 쉐이킹을 통해 효율적인 번들을 생성합니다.
  • Parcel: 설정이 거의 필요 없는 제로 컨피그 번들러입니다.
  • SystemJS: 다양한 모듈 형식을 지원하는 동적 모듈 로더입니다.
  • ES6 Modules: 최신 브라우저와 Node.js에서 기본적으로 지원하는 표준 모듈 시스템입니다.
  • CommonJS: Node.js에서 기본적으로 사용되는 모듈 시스템입니다.
  • UMD (Universal Module Definition): AMD, CommonJS, 전역 변수 등 다양한 환경에서 동작하는 모듈을 정의하는 패턴입니다.

 

모듈 시스템이 존재하기 전에는 script 태그로 각각 분리된 모듈을 불러오는 경우에도 모두 하나의 파일에서 동작하는 것처럼 스코프를 공유했습니다. (모두 같은 스코프에서 같은 전역객체를 보기 때문에 전역 상태의 오버라이딩등 예상치 못한 문제들이 존재)

 

이를 해결하고자 즉시실행함수(IIFE)를 통해 불필요한 전역 변수를 선언하지 않도록 하거나, namaspace를 통해 관리하는 등의 방법이 있었지만 전역 객체의 모듈을 관리하는건 힘든 문제였습니다,

 

<script src="script1.js"></script> 
<script src="script2.js"></script>

 

script1.js에서 var x = 5;를 선언하면, script2.js에서도 x에 접근할 수 있습니다.

 

(function() {
  var privateVar = "I'm private";
  // 이 변수는 이 함수 스코프 밖에서 접근할 수 없습니다.
})();

 

즉시 실행 함수(IIFE)를 사용한 해결 방법: IIFE는 함수를 선언하자마자 즉시 실행하는 패턴입니다. 이를 통해 private 스코프를 만들어 변수들을 캡슐화할 수 있습니다.

 

var MyApp = MyApp || {};
MyApp.utils = {
  someFunction: function() { /* ... */ },
  anotherFunction: function() { /* ... */ }
};

 

Namespace를 통한 관리: Namespace는 관련된 기능들을 하나의 객체 아래에 그룹화하는 방법입니다. 이를 통해 이름 충돌을 방지하고 코드를 구조화할 수 있습니다.

 

 

ES6 모듈 시스템

// math.js
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

export const PI = 3.14159;

// main.js
import { add, subtract, PI } from './math.js';

console.log(add(5, 3));        // 출력: 8
console.log(subtract(10, 4));  // 출력: 6
console.log(PI);               // 출력: 3.14159

// math 모듈의 모든 내용을 가져오기
import * as Math from './math.js';

console.log(Math.add(2, 2));   // 출력: 4
console.log(Math.PI);          // 출력: 3.14159

 

 

  • 전역 스코프 오염 방지: 모든 것이 모듈 스코프 내에 있습니다.
  • 명시적 의존성: 어떤 모듈이 어떤 기능을 사용하는지 명확합니다.
  • 코드 구조화: 관련 기능을 논리적으로 그룹화할 수 있습니다.
  • 재사용성: 모듈을 쉽게 다른 프로젝트에서 재사용할 수 있습니다.

 

 

Call by Value, Call by Reference

 

 

// Call by Value 예시
function modifyPrimitive(x) {
    x = x + 5;
    console.log("Inside function:", x); 15
};

let num = 10;
console.log("Before function call:", num); 10
modifyPrimitive(num);
console.log("After function call:", num); 10

 

 

  • Call by Value (값에 의한 호출):
    • 기본형 데이터 타입(Number, String, Boolean, null, undefined, Symbol)에 적용됩니다.
    • 함수에 인자로 전달될 때 값의 복사본이 전달됩니다.
    • 함수 내에서 매개변수의 값을 변경해도 원본 변수에는 영향을 주지 않습니다.
    • 예시의 modifyPrimitive 함수에서 num의 값은 변경되지 않습니다.

 


 

// Call by Reference 예시
function modifyObject(obj) {
    obj.value += 5;
    console.log("Inside function:", obj.value); 15
}

let myObj = { value: 10 };
console.log("Before function call:", myObj.value); 10
modifyObject(myObj);
console.log("After function call:", myObj.value); 15


// 배열 예시
function modifyArray(arr) {
    arr.push(4);
    console.log("Inside function:", arr);  [1, 2, 3, 4]
}

let myArray = [1, 2, 3];
console.log("Before function call:", myArray);  [1, 2, 3]
modifyArray(myArray);
console.log("After function call:", myArray);  [1, 2, 3, 4]

 

  • Call by Reference (참조에 의한 호출):
    • 객체(Object, Array, Function)에 적용됩니다.
    • 함수에 인자로 전달될 때 객체의 참조(메모리 주소)가 전달됩니다.
    • 함수 내에서 객체의 속성을 변경하면 원본 객체에도 영향을 줍니다.
    • 예시의 modifyObject와 modifyArray 함수에서 객체와 배열의 내용이 변경됩니다.

 

 

자바스크립트는 엄밀히 말하면 항상 "call by value"입니다. 객체의 경우, 값으로 전달되는 것이 참조 값이기 때문에 "call by sharing"이라고 부르기도 합니다.

 

// 참조 자체를 변경하는 경우
function replaceObject(obj) {
    obj = { value: 100 };
    console.log("Inside function:", obj.value); 100
}

let anotherObj = { value: 10 };
console.log("Before function call:", anotherObj.value); 10
replaceObject(anotherObj);
console.log("After function call:", anotherObj.value); 10

 

객체의 참조 자체를 변경하는 것은 원본 변수에 영향을 주지 않습니다. replaceObject 함수 예시에서 볼 수 있듯이, 함수 내에서 객체 자체를 새로운 객체로 대체해도 원본 변수는 변경되지 않습니다.

 

불변성(Immutability)을 유지하기 위해서는 객체를 다룰 때 주의가 필요합니다. 함수형 프로그래밍에서는 원본 객체를 변경하지 않고 새로운 객체를 반환하는 방식을 선호합니다.

 

 

 

  • Call by Value: 복사본을 주고받습니다. 변경해도 원본에 영향 없음.
  • Call by Reference: 같은 공간을 공유합니다. 변경하면 모두에게 영향 있음.

 

 

 

 

** 계속 추가중입니다. (틀리거나 잘못된 내용 알려주시면 수정 하도록 하겠습니다 )

 

728x90
반응형

'front_end' 카테고리의 다른 글

멋쟁이 사자처럼 <Front_end> 과정 OT 후기  (0) 2021.10.29
프론트 엔드(Front-end)란?  (0) 2021.10.05
Comments