프론트앤드 기술면접 TOP65-(7)

이보아·2024년 9월 19일
0
post-thumbnail

38. ⭐ NextJS의 서버 사이드 컴포넌트와 클라이언트 사이드 컴퍼넌트에 대해서 설명해주세요.

서버 사이드 컴포넌트
- 정의: 서버에서 렌더링되는 컴포넌트, 초기 페이지 로드 시 서버에서 데이터를 가져와 HTML을 생성
- 장점: SEO 최적화에 유리하여, 초기 로딩 속도가 빠르다. 데이터 요청을 서버에서 처리하므로 클라이언트의 부담을 줄인다.
- 사용 예 : 사용자 인증 정보, 데이터베이스에서 가져온 데이터를 기반으로 하는 페이지

클라이언트 사이드 컴포넌트
- 정의: 클라이언트(브라우저)에서 렌더링되는 컴포넌트로, 사용자 상호작용에 따라 동적으로 업데이트됨
장점: 사용자 경험을 향상시키며, 페이지 전환, 상태 관리를 유연하게 처리할 수 있다.
- 사용 예: 버튼 클릭 시 데이터를 가져오거나, UI 요소의 동적인 변경이 필요한 경우

39. 코드스플리팅이란 무엇인가요?

애플리케이션의 코드를 여러 개의 청크로 나누어 필요할 때만 로드하는 기법입니다. 이를 통해 초기 로딩 시간을 단축하고, 사용자에게 필요한 코드만 전송하여 성능을 개선할 수 있습니다.

📑 청크(Chunk)란? 애플리케이션의 코드나 리소스를 나누어 놓은 작은 단위입니다. 코드 스플리팅을 통해 큰 파일을 여러 개의 청크로 나누어, 필요한 경우에만 해당 청크를 로드하도록 하는 방식입니다.

코드스플리팅 특징

  • 장점: 초기 다운로드 크기를 줄여 페이지 로딩 속도 향상, 사용자 경험 개선.
  • 방법: 동적 import()를 사용하여 특정 컴포넌트나 모듈을 필요할 때만 로드.
  • 사용 예: 라우팅에 따라 특정 페이지가 필요할 때만 해당 페이지의 코드를 로드.

javascript 예시

// main.js
function loadModule() {
    import('./module.js')
        .then(module => {
            module.default();
        })
        .catch(err => {
            console.error('모듈 로드 실패:', err);
        });
}

// 버튼 클릭 시 모듈 로드
document.getElementById('loadButton').addEventListener('click', loadModule);

React 예시

// main.js
function loadModule() {
    import('./module.js')
        .then(module => {
            module.default();
        })
        .catch(err => {
            console.error('모듈 로드 실패:', err);
        });
}

// 버튼 클릭 시 모듈 로드
document.getElementById('loadButton').addEventListener('click', loadModule);

Next.js 예시

// pages/index.js
import dynamic from 'next/dynamic';

const DynamicComponent = dynamic(() => import('../components/DynamicComponent'), {
    loading: () => <p>로딩 중...</p>,
});

function HomePage() {
    return (
        <div>
            <h1>홈페이지</h1>
            <DynamicComponent />
        </div>
    );
}

export default HomePage;

40. Next.js edge runtime은 무엇이고 어떤 장점이 있을까요?

Next.js의 Edge Runtime은 서버와 클라이언트 사이에서 코드가 실행되는 환경으로, 주로 엣지 서버에서 작동합니다.

Next.js edge runtime 특징과 장점

  • 빠른 응답 속도: 사용자와 가까운 서버에서 실행되어 지연 시간을 줄입니다.
  • 자동 확장: 트래픽이 많아져도 서버가 자동으로 확장되어 안정적으로 동작합니다.
  • 비용 효율성: 필요한 만큼만 자원을 사용하여 운영 비용을 절감할 수 있습니다.
  • 유연한 API 처리: API 요청을 쉽게 처리하고, 데이터 변환이나 인증 작업을 수행할 수 있습니다.
  • 보안 강화: 요청을 필터링하고 인증을 처리하는 미들웨어를 쉽게 만들 수 있습니다.

41. ⭐ JS의 var, const, let 키워드가 비교 설명해주세요.

호이스팅(Hoisting)
var : 변수 선언이 함수나 전역 스코프의 최상단으로 끌어올려집니다. 따라서 선언 전에 접근하면 undefined를 반환합니다.
let과 const : 호이스팅은 되지만, 선언 전에 접근하면 ReferenceError가 발생합니다. 이는 "일시적 사각지대(Temporal Dead Zone)" 때문입니다

재선언 및 재할당
var: 같은 스코프 내에서 재선언이 가능하고, 재할당도 가능합니다.
let: 같은 스코프 내에서 재선언이 불가능하지만, 재할당은 가능합니다.
const: 재선언과 재할당이 모두 불가능합니다. 상수로서, 선언 후 값이 변경되지 않습니다.

스코프 (Scope)
var: 함수 스코프(function scope)를 가집니다. 즉, 함수 내에서 선언된 var는 함수 전체에서 접근 가능합니다.
let과 const: 블록 스코프(block scope)를 가집니다. 즉, {}로 감싸진 블록 내에서만 접근 가능합니다.

42.⭐ 호이스팅이란?

자바스크립트의 변수와 함수 선언해당 스코프의 최상단으로 끌어올려지는 특성을 말합니다. 이로 인해 변수나 함수를 선언하기 전에 참조할 수 있게 됩니다.

변수 선언

var로 선언된 변수는 선언만 호이스팅되며, 초기화는 호이스팅되지 않는다. 따라서, 선언 전에 접근하면 undefined가 반환됨.

console.log(a); // undefined
var a = 5;

함수 선언

삼수 선언은 전체가 호이스팅되므로, 선언 전에 호출할 수 있다.

greet(); // "Hello!"
function greet() {
    console.log("Hello!");
}

let과 const

let과 const로 선언된 변수도 호이스팅되지만, 선언되기 전에는 접근할 수 없으며, 이를 시도하면 ReferenceError가 발생합니다. 이는 "일시적 사각지대(Temporal Dead Zone)" 때문입니다.

console.log(b); // ReferenceError
let b = 10;

43. JS의 스코프와 클로저에 대해서 아는대로 설명해주세요.

스코프(Scope) : 변수의 유효 범위를 정의하는 개념으로, 변수가 어디에서 접근 가능한지를 결정합니다. 자바스크립트에서는 주로 두 가지 타입의 스코프가 있습니다

클로저(Closure) : 함수가 선언된 환경을 기억하는 함수입니다. 즉, 내부 함수가 외부 함수의 변수에 접근할 수 있는 기능입니다.

스코프 타입

  1. 전역 스코프 (Global Scope)

    코드의 최상단에서 선언된 변수는 전역 스코프에 속합니다. 어디에서나 접근할 수 있습니다.

var globalVar = "나는 전역 변수";

function example() {
    console.log(globalVar); // "나는 전역 변수"
}
  1. 지역 스코프 (Local Scope)

    함수 내에서 선언된 변수는 해당 함수 내에서만 접근 가능하며, 다른 함수에서는 접근할 수 없습니다.

function example() {
    var localVar = "나는 지역 변수";
    console.log(localVar); // "나는 지역 변수"
}

console.log(localVar); // ReferenceError
  1. 블록 스코프 (Block Scope)

    let과 const로 선언된 변수는 블록 {} 내에서만 유효합니다.

if (true) {
    let blockVar = "나는 블록 변수";
    console.log(blockVar); // "나는 블록 변수"
}
console.log(blockVar); // ReferenceError

클로저 장점

  1. 데이터 은닉

    클로저를 통해 외부에서 접근할 수 없는 변수를 만들 수 있습니다.

function createCounter() {
    let count = 0; // 은닉된 변수

    return function() {
        count++;
        return count;
    };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
  1. 상태 유지

    클로저를 사용하면 함수 호출 간에 상태를 유지할 수 있습니다.

function makeMultiplier(factor) {
    return function(x) {
        return x * factor;
    };
}

const double = makeMultiplier(2);
console.log(double(5)); // 10

44. 리액트에서 지역상태만 사용해서 개발하는 경우, 발생할 수 있는 문제가 무엇이 있을까요?

복잡해지고 규모가 커질수록, 전역 상태 관리 라이브러리(예: Redux, MobX, Context API 등)를 사용하는 것이 더 효율적이고 유지보수하기 쉬운 방법이 될 수 있습니다. 지역 상태만으로는 이러한 문제들을 효과적으로 해결하기 어려운 경우가 많습니다.

1. 상태 관리의 복잡성 증가

  • 컴포넌트가 많아질수록, 상태를 각 컴포넌트에서 관리해야 하므로 코드가 복잡해질 수 있습니다. 여러 컴포넌트 간의 상태 공유가 어려워집니다.

2. 재사용성 감소

  • 상태가 특정 컴포넌트에만 국한되면, 다른 컴포넌트에서 동일한 상태를 재사용하기 어렵습니다. 이로 인해 코드 중복이 발생할 수 있습니다.

3. 상태 동기화 문제

  • 여러 컴포넌트에서 동일한 데이터를 필요로 할 때, 각 컴포넌트의 상태를 동기화하는 것이 어려워집니다. 이로 인해 UI가 일관되지 않을 수 있습니다.

4. 성능 저하

  • 불필요한 렌더링이 발생할 수 있습니다. 상태가 변경될 때마다 해당 컴포넌트와 그 하위 컴포넌트가 모두 다시 렌더링되기 때문에 성능이 저하될 수 있습니다.

5. 상태 흐름 추적 어려움

  • 상태가 여러 컴포넌트에 분산되어 있을 경우, 상태의 흐름을 추적하고 관리하기 어려워질 수 있습니다. 이는 디버깅을 어렵게 만듭니다.

6. 상태 초기화 문제

  • 컴포넌트가 마운트될 때마다 상태를 초기화해야 할 경우, 코드가 복잡해질 수 있습니다.

45. null과 undefined의 차이점

null과 undefined는 자바스크립트에서 모두 "값이 없음"을 나타내지만, 그 의미와 용도가 다릅니다.

  • undefined : 변수는 선언되었지만 값이 할당되지 않은 상태를 나타냅니다. 초기화 하지 않으면 자동으로 undefined가 된다.
  • null: 변수에 "의도적으로 값이 없음"을 할당할 때 사용합니다. 이는 개발자가 특정한 상태를 나타내기 위해 사용합니다.

46.⭐ 깊은 복사와 얕은 복사

깊은 복사: 복사본이 원본과 완전히 독립적임. 모든 중첩 객체가 새로 복사됨
얕은 복사: 복사본은 원본과 일부 속성을 공유 중첩 객체는 같은 참조를 가지므로, 한쪽에서 변경하면 다른 쪽에도 영향을 줌.

항목얕은 복사깊은 복사
정의객체의 1차원 속성만 복사모든 속성을 재귀적으로 복사
참조참조 데이터 타입은 원본 객체와 공유완전히 독립적인 새로운 인스턴스 생성
예시const shallowCopy = { ...original };const deepCopy = JSON.parse(JSON.stringify(original));
결과원본 객체의 참조 속성이 변경되면 영향을 받음원본 객체와 복사된 객체가 서로 영향을 주지 않음
사용 예단순한 객체나 배열의 복사, 성능이 중요한 경우복잡한 객체나 배열을 완전히 독립적으로 복사해야 할 때
방법Object.assign(), Spread operator (...) 사용JSON 변환, Lodash의 _.cloneDeep 사용
// 얇은 복사 
const o = { x: { y: 1 } };
const c1 = { ...o }; // 얕은 복사
console.log(c1.x === o.x); // true: 같은 중첩 객체를 가리킴

// 깊은 복사 
const _ = require('lodash');
const c2 = _.cloneDeep(o); // 깊은 복사
console.log(c2.x === o.x); // false: 서로 다른 중첩 객체

// 원시 값 복사 
const v = 1;
const c1 = v; // 깊은 복사처럼 값 복사
console.log(c1 === v); // true

주의사항

  • 깊은 복사를 구현할 때는 성능과 메모리 사용에 주의해야 합니다. 복사할 객체가 매우 크거나 복잡한 구조일 경우, 성능 저하가 발생할 수 있습니다.
  • JSON.parse(JSON.stringify(...)) 방식은 객체가 함수, undefined, Symbol, 또는 순환 참조를 포함할 경우 사용할 수 없습니다. 이러한 경우에는 Lodash의 _.cloneDeep와 같은 라이브러리를 사용하는 것이 좋습니다.

47. Strict mode에 대해서 설명해주세요.

Strict mode(엄격 모드)는 자바스크립트의 기능으로, 코드의 실행 환경을 더 안전하고 예측 가능하게 만들기 위해 특정 규칙을 적용. 엄격 모드를 사용하면 잠재적인 오류를 사전에 방지하고, 코드를 더 명확하게 작성할 수 있음

주요 특징

  1. 전역 변수 사용 금지

    선언되지 않은 변수를 사용 X, 이를 통해 변수의 오타로 인한 버그를 방지할 수 있음

"use strict";
x = 10; // ReferenceError: x is not defined
  1. 읽기 전용 속성 수정 금지

    읽기 전용 속성(예: NaN, undefined, Infinity)을 수정하려고 하면 오류가 발생

  2. 삭제(Deletion) 제한

    delete 연산자를 사용하여 변수를 삭제할 수 없음

"use strict";
var obj = {};
delete obj; // SyntaxError: Delete of an unqualified identifier in strict mode.
  1. 함수의 매개변수 중복 금지

    함수의 매개변수 이름이 중복될 수 없음

"use strict";
function myFunction(a, a) { // SyntaxError: Duplicate parameter name not allowed in this context
    // ...
}
  1. this의 의미 변경

    전역 컨텍스트에서 this는 undefined가 됩니다. 이는 전역 객체에 대한 불필요한 접근을 방지

  2. 모듈과 클래스에서 기본적으로 활성화

    ES6의 모듈과 클래스는 기본적으로 엄격 모드가 적용됩니다.

48. 콜백 지옥 (Callback Hell)이 무엇이고 어떻게 해결할 수 있는지 설명해주세요.

자바스크립트에서 비동기 작업을 처리할 때, 많은 콜백 함수가 중첩되면서 코드의 가독성과 유지보수성이 떨어지는 상태를 말합니다. 일반적으로 비동기 작업을 수행하기 위해 여러 단계의 콜백을 중첩할 때 발생합니다. 이로 인해 코드가 복잡해지고, 이해하기 어려워집니다.

getData(function(result1) {
    processResult1(result1, function(result2) {
        processResult2(result2, function(result3) {
            processResult3(result3, function(finalResult) {
                console.log(finalResult);
            });
        });
    });
});

해결 방법

  1. Named Functions (이름 있는 함수 사용)

    콜백 함수를 별도로 정의하여 중첩을 줄인다.

function handleResult1(result1) {
    processResult1(result1, handleResult2);
}

function handleResult2(result2) {
    processResult2(result2, handleResult3);
}

function handleResult3(result3) {
    processResult3(result3, function(finalResult) {
        console.log(finalResult);
    });
}

getData(handleResult1);
  1. Promise 사용

    비동기 작업을 처리할 때 Promise를 사용하면, .then() 메서드를 체인하여 가독성을 높임

getData()
    .then(processResult1)
    .then(processResult2)
    .then(processResult3)
    .then(finalResult => {
        console.log(finalResult);
    })
    .catch(error => {
        console.error(error);
    });
  1. Async/Await 사용

    async/await 문법을 사용하면, 비동기 코드를 동기 코드처럼 작성할 수 있어 가독성이 높임

async function main() {
    try {
        const result1 = await getData();
        const result2 = await processResult1(result1);
        const result3 = await processResult2(result2);
        const finalResult = await processResult3(result3);
        console.log(finalResult);
    } catch (error) {
        console.error(error);
    }
}

main();

49. React와 Angular의 주요 차이점을 설명해 주세요.

  • React: 유연하고 컴포넌트 기반의 라이브러리.
  • Angular: 강력한 기능을 갖춘 전체 프레임워크.
항목ReactAngular
개발 방식UI 라이브러리, 컴포넌트 기반전체 프레임워크, MVC 아키텍처
언어JSX (JavaScript XML) 사용TypeScript 사용
데이터 바인딩단방향 데이터 바인딩양방향 데이터 바인딩
상태 관리훅(hooks) 또는 외부 라이브러리 사용서비스와 RxJS로 관리
생태계큰 커뮤니티, 다양한 라이브러리 존재Google 유지보수, 안정적인 업데이트
성능가상 DOM으로 UI 업데이트 최적화Zone.js로 변경 감지, 성능 개선 필요

50. 이벤트 버블링(Event Bubbling)과 이벤트 캡처링(Event Capturing)을 설명해 주세요.

이벤트 버블링(Event Bubbling)과 이벤트 캡처링(Event Capturing)은 자바스크립트에서 이벤트가 DOM 트리에서 전파되는 두 가지 방식이다. 이 두 개념은 이벤트가 발생한 요소에서 상위 요소로 또는 하위 요소로 전파되는 과정을 설명

이벤트 버블링 (Event Bubbling)

이벤트가 발생한 요소에서 시작하여, 그 요소의 상위 요소(부모 요소)로 전파되는 방식입니다. 즉, 가장 자식 요소에서 시작해 부모 요소로 올라가는 방식

// HTML 
<div id="parent">
    <button id="child">Click me</button>
</div>

// Javascript 
document.getElementById('parent').addEventListener('click', function() {
    console.log('Parent clicked');
});

document.getElementById('child').addEventListener('click', function() {
    console.log('Child clicked');
});
  • 버튼을 클릭 → 콘솔 "Child clicked" 출력 → "Parent clicked" 출력

이벤트 캡처링 (Event Capturing)

이벤트가 상위 요소에서 시작하여, 하위 요소(자식 요소)로 전파되는 방식입니다. 즉, 부모 요소에서 시작해 자식 요소로 내려가는 방식

document.getElementById('parent').addEventListener('click', function() {
    console.log('Parent clicked');
}, true); // true를 추가하여 캡처링 모드로 설정

document.getElementById('child').addEventListener('click', function() {
    console.log('Child clicked');
});
  • 버튼을 클릭 → 콘솔 "Parent clicked" 출력 → "Child clicked" 출력

요약

  • 기본적으로는 이벤트는 버블링 방식으로 전파
  • 이벤트 캡처링을 사용하려면 addEventListener의 세 번째 인자로 true를 전달
  • 이벤트 버블링: 자식 → 부모 (하위 요소에서 상위 요소로)
  • 이벤트 캡처링: 부모 → 자식 (상위 요소에서 하위 요소로)

51. 상태 관리 라이브러리(Redux, MobX 등)의 역할을 설명해 주세요.

상태 관리 라이브러리(Redux, MobX 등)는 애플리케이션의 상태를 효율적으로 관리하고 공유하기 위해 사용됨

  1. 중앙 집중화된 상태 관리
  • 애플리케이션의 모든 상태를 중앙에서 관리하여, 여러 컴포넌트 간의 데이터 공유를 용이함
  1. 예측 가능한 상태 변화
  • 상태 변화가 명확한 규칙(예: 액션과 리듀서)을 통해 이루어져, 디버깅과 테스트가 쉬움
  1. 상태 변경 기록
  • 상태 변화의 이력을 관리하여, 시간여행 디버깅과 같은 기능을 지원
  1. 비동기 처리 지원
  • 비동기 작업(예: API 호출)을 쉽게 관리할 수 있는 구조를 제공
  1. 성능 최적화
  • 상태 변화에 따라 필요한 컴포넌트만 리렌더링하여 성능을 최적화
    이러한 역할 덕분에 복잡한 애플리케이션에서도 상태를 일관되게 유지할 수 있음

52. Semantic Tag, Flex, Grid, Padding, Margin에 대해 각각 설명해주세요.

Semantic Tag: HTML에서 콘텐츠의 의미를 명확히 전달하는 태그, 웹 페이지의 구조를 이해하기 쉽게 하며, SEO 및 접근성을 향상시킴

Flex: CSS Flexbox는 1차원 레이아웃을 만들기 위한 모듈이며, 요소들을 쉽게 정렬하고 배치할 수 있게 하며, 공간을 효율적으로 활용

Grid: CSS Grid Layout은 2차원 레이아웃을 구성하기 위한 모듈, 행과 열로 구성된 복잡한 레이아웃을 쉽게 만들 수 있음

Padding: 요소의 콘텐츠와 경계(테두리) 사이의 내부 공간의 여백을 줄때 사용
Margin: 요소의 경계(테두리)와 다른 요소 사이의 외부 공간에 여백을 줄때 사용

53. 클래스형 컴포넌트 / 함수형 컴포넌트에 대해 설명해주세요.

항목클래스형 컴포넌트함수형 컴포넌트
정의 방식ES6 클래스로 정의함수로 정의
상태 관리this.state 사용Hooks(useState) 사용
생명주기 메서드사용 가능useEffect로 대체
코드 길이상대적으로 길고 복잡할 수 있음간결하고 직관적
성능약간 느릴 수 있음더 가벼운 성능

클래스형 컴포넌트 (Class Components)

ES6 클래스를 사용하여 정의된 컴포넌트 이며, this.state를 사용하여 내부 상태를 관리, 생명주기 메서드 componentDidMount, componentDidUpdate, componentWillUnmount등의 생명주기 메서드를 사용할 수 있음

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };
    }

    render() {
        return <div>{this.state.count}</div>;
    }
}

함수형 컴포넌트 (Functional Components)

단순한 JavaScript 함수로 정의된 컴포넌트, React Hooks(useState, useEffect 등)를 사용하여 상태와 생명주기를 관리할 수 있습니다.

import React, { useState } from 'react';

function MyComponent() {
    const [count, setCount] = useState(0);
    
    return <div>{count}</div>;
}
  • 함수형 컴포넌트는 최근 React에서 더 널리 사용되며, 간결하고 효율적인 코드 작성을 가능하게 함
profile
매일매일 틀깨기

0개의 댓글