발행일

[ZBF] JS 멘토링 준비

[ZBF] JS 멘토링 준비

이 글은 네이버 블로그에 2024년 6월 9일에 올렸던 것을 그대로 옮겨온 것입니다.

sync와 async의 차이점을 설명해 주세요.

Sync(동기)에서는 요청을 보내고 해당 요청에 대한 응답을 기다립니다. 이 방식에서는 하나의 작업이 끝나기 전까지 다음 작업을 시작할 수 없습니다.

function syncFunction() {
  console.log("작업 시작");
  for (let i = 0; i < 1000000000; i++) {} // 긴 작업
  console.log("작업 완료");
}

syncFunction();
console.log("다음 작업");

반면, async(비동기)는 요청에 대한 응답을 기다리지 않고 다음 동작을 수행하는 것을 의미합니다. 비동기 방식에서는 하나의 작업이 진행되는 동안 다른 작업을 동시에 수행할 수 있습니다.

function asyncFunction() {
  console.log("작업 시작");
  setTimeout(() => {
    console.log("작업 완료");
  }, 1000);
}

asyncFunction();
console.log("다음 작업");

Blocking과 Non-Blocking의 차이를 설명해 주세요.

Blocking은 한 작업이 완료될 때까지 제어권이 해당 작업에 묶여 있는 것을 의미합니다. 즉, 현재 작업이 끝나기 전까지 다른 작업을 수행할 수 없습니다.

Non-Blocking은 한 작업이 완료되지 않아도 제어권을 반환하여 다음 작업을 수행할 수 있는 것을 의미합니다. 즉, 여러 작업을 동시에 진행할 수 있습니다.

// Blocking example
function blockingFunction() {
  console.log("Blocking 시작");
  for (let i = 0; i < 1000000000; i++) {} // 긴 작업
  console.log("Blocking 완료");
}

blockingFunction();
console.log("다음 작업");

// Non-Blocking example
function nonBlockingFunction() {
  console.log("Non-Blocking 시작");
  setTimeout(() => {
    console.log("Non-Blocking 완료");
  }, 1000);
}

nonBlockingFunction();
console.log("다음 작업");

콜백 함수에 대해 설명해 주세요.

콜백 함수는 다른 함수에 인자로 전달되어 특정 작업이 완료된 후 호출되는 함수입니다.

콜백 함수는 자바스크립트의 중요한 개념 중 하나로, 비동기 프로그래밍에서 특히 많이 사용됩니다. 콜백 함수는 이벤트 핸들러, 비동기 작업, 타이머 함수 등에서 사용되며, 이를 통해 비동기 작업의 완료 시점에 특정 동작을 수행할 수 있습니다. 콜백 함수를 사용하면 코드의 흐름을 제어하고, 비동기 작업을 순차적으로 처리하거나 병렬로 처리할 수 있습니다.

콜백 함수는 다음과 같은 상황에서 자주 사용됩니다:

  1. 이벤트 처리: 사용자 인터페이스에서 발생하는 이벤트(예: 버튼 클릭, 키보드 입력 등)를 처리하기 위해 콜백 함수를 사용합니다.

  2. 비동기 작업: AJAX 요청, 타이머 함수(setTimeout, setInterval) 등에서 비동기 작업의 완료 시점을 처리하기 위해 콜백 함수를 사용합니다.

  3. 배열 메서드: forEach, map, filter, reduce 등과 같은 배열 메서드에서 콜백 함수를 사용하여 각 요소에 대한 작업을 수행합니다.

콜백 함수는 코드의 재사용성과 유연성을 높여주며, 비동기 작업을 효율적으로 관리할 수 있게 해줍니다.

콜백 지옥의 의미와 콜백 지옥을 해결하는 방법을 설명해 주세요.

콜백 지옥은 익명 함수에 콜백 함수를 전달하는 과정에서 콜백 내에서 함수 호출이 반복되어 코드의 들여쓰기 수준이 지나치게 깊어지는 현상을 말합니다. 이는 주로 이벤트 처리나 서버 통신과 같은 비동기 작업을 제어하는 데 사용되지만, 이러한 방식은 코드의 가독성을 저하시키고 유지보수를 어렵게 만듭니다.

콜백 지옥은 코드가 마치 "피라미드"처럼 오른쪽으로 점점 깊어지는 형태를 띄기 때문에, 코드의 흐름을 이해하기 어려워지고 디버깅이 복잡해집니다.

// 콜백 지옥 예시
asyncOperation1((result1) => {
  asyncOperation2(result1, (result2) => {
    asyncOperation3(result2, (result3) => {
      console.log(result3);
    });
  });
});

// 콜백 지옥 해결 - Promise 사용
asyncOperation1()
  .then(result1 => asyncOperation2(result1))
  .then(result2 => asyncOperation3(result2))
  .then(result3 => console.log(result3))
  .catch(error => console.error(error));

// 콜백 지옥 해결 - Async/Await 사용
async function handleOperations() {
  try {
    const result1 = await asyncOperation1();
    const result2 = await asyncOperation2(result1);
    const result3 = await asyncOperation3(result2);
    console.log(result3);
  } catch (error) {
    console.error(error);
  }
}

handleOperations();

해결 방법

  1. 코딩 패턴으로 콜백 익명 함수를 각각의 함수로 분리 익명 함수를 별도의 명명된 함수로 분리하면 코드의 가독성이 향상됩니다. 각 함수가 명확한 역할을 가지게 되어, 코드의 구조를 더 쉽게 이해할 수 있습니다.

2. Promise 사용 Promise 객체를 사용하면 비동기 작업을 보다 체계적으로 처리할 수 있습니다. Promise는 비동기 작업의 완료 또는 실패를 처리하는 방식을 제공합니다. then 메서드를 사용하여 순차적으로 작업을 이어나갈 수 있어, 콜백 지옥을 피할 수 있습니다.

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("데이터 수신 완료"), 1000);
  });
}

fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error));

3. Async/Await 사용

async와 await 키워드를 사용하면 비동기 코드를 동기 코드처럼 작성할 수 있습니다. async/await는 Promise를 기반으로 작동하며, 코드의 가독성과 유지보수성을 크게 향상시킵니다. 복잡한 비동기 로직을 간단하고 직관적으로 표현할 수 있습니다.

async function fetchData() {
  try {
    const data = await new Promise((resolve) => {
      setTimeout(() => resolve("데이터 수신 완료"), 1000);
    });
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

fetchData();
// 콜백 지옥 예시
asyncOperation1((result1) => {
  asyncOperation2(result1, (result2) => {
    asyncOperation3(result2, (result3) => {
      console.log(result3);
    });
  });
});

// 콜백 지옥 해결 - Promise 사용
asyncOperation1()
  .then(result1 => asyncOperation2(result1))
  .then(result2 => asyncOperation3(result2))
  .then(result3 => console.log(result3))
  .catch(error => console.error(error));

// 콜백 지옥 해결 - Async/Await 사용
async function handleOperations() {
  try {
    const result1 = await asyncOperation1();
    const result2 = await asyncOperation2(result1);
    const result3 = await asyncOperation3(result2);
    console.log(result3);
  } catch (error) {
    console.error(error);
  }
}

handleOperations();

Event loop에 대해 설명해 주세요.

이벤트 루프는 자바스크립트의 비동기 처리를 관리하는 핵심 메커니즘입니다. 자바스크립트는 단일 스레드로 작동하며, 이벤트 루프를 통해 비동기 작업을 효율적으로 처리합니다.

  1. 콜 스택(Call Stack): 함수 호출이 쌓이는 구조입니다. 현재 실행 중인 함수가 끝나면 스택에서 제거되고, 다음 함수가 실행됩니다.

  2. 태스크 큐(Task Queue): 비동기 작업의 콜백 함수들이 대기하는 큐입니다. 예를 들어, setTimeout, Promise의 콜백 등이 여기에 들어갑니다.

  3. 이벤트 루프(Event Loop): 이벤트 루프는 콜 스택과 태스크 큐를 지속적으로 확인합니다. 콜 스택이 비어 있는 경우, 태스크 큐에서 대기 중인 첫 번째 콜백을 콜 스택으로 이동시켜 실행합니다.

작동 방식:

  1. 자바스크립트 엔진은 먼저 콜 스택에서 모든 동기 코드를 실행합니다.

  2. 비동기 작업(예: setTimeout, fetch)은 콜백 함수를 태스크 큐에 넣습니다.

  3. 콜 스택이 비어 있는 경우, 이벤트 루프는 태스크 큐에서 첫 번째 콜백을 가져와 콜 스택에 넣고 실행합니다.

  4. 이 과정이 반복되며 비동기 작업들이 순차적으로 처리됩니다.

이러한 작동 방식 덕분에 자바스크립트는 단일 스레드 환경에서도 효율적으로 비동기 작업을 처리할 수 있습니다.

Promise와 Async/Await의 차이를 설명해 주세요.

Promise는 ES6에서 도입된 비동기 작업을 처리하는 객체입니다. Promise는 비동기 작업의 완료 여부를 나타내며, 세 가지 상태를 가질 수 있습니다:

pending(대기), fulfilled(이행), rejected(거부).

Promise를 사용하면 비동기 작업이 완료되었을 때 실행할 코드를 체계적으로 관리할 수 있습니다.

Async와 Await는 ES8에서 도입된 비동기 작업을 더욱 쉽게 처리할 수 있는 문법입니다. Async/Await는 Promise를 기반으로 작동하며, 비동기 작업을 마치 동기 작업처럼 작성할 수 있게 해줍니다.

Promise와 Async/Await의 차이점:

  1. 가독성: Promise는 then과 catch 메서드를 사용하여 체인 형식으로 비동기 작업을 처리합니다. 반면, Async/Await는 동기 코드처럼 await 키워드를 사용하여 비동기 작업의 결과를 변수에 할당할 수 있어 가독성이 더 좋습니다.
  2. 에러 처리: Promise는 catch 메서드를 사용하여 에러를 처리합니다. Async/Await는 try...catch 블록을 사용하여 에러를 처리하므로, 동기 코드와 일관된 방식으로 에러를 관리할 수 있습니다.
  3. 코드 구조: Promise는 중첩된 비동기 작업을 처리할 때 콜백 지옥을 피할 수 있지만, 여전히 체인 형식으로 인해 코드가 길어질 수 있습니다. Async/Await는 비동기 작업을 순차적으로 작성할 수 있어 코드 구조가 간결해집니다.
function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("데이터 수신 완료"), 1000);
  });
}

fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error));
async function fetchData() {
  try {
    const data = await new Promise((resolve) => {
      setTimeout(() => resolve("데이터 수신 완료"), 1000);
    });
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

fetchData();

map과 forEach의 차이를 설명해 주세요.

1. 반환 값의 차이:

map: 새로운 배열을 반환합니다. 원본 배열을 변경하지 않으며, 각 요소를 변환한 후 새로운 배열에 담아 반환합니다.

forEach: 반환 값이 없습니다(undefined). 원본 배열을 직접 수정하거나 외부 상태를 변경하는 데 사용됩니다.

2. 사용 목적의 차이:

map: 배열의 각 요소를 변환하여 새로운 배열을 생성할 때 사용합니다.

forEach: 배열의 각 요소에 대해 어떤 작업을 수행할 때 사용합니다. (예: 콘솔에 출력, DOM 조작 등)

3. 원본 배열의 상태:

map: 원본 배열은 변경되지 않습니다.

forEach: 원본 배열을 변경할 수 있습니다.

// map: 새로운 배열을 반환
const numbers = [1, 2, 3, 4];
const squared = numbers.map(n => n * 2);
console.log(squared); // [2, 4, 6, 8]

// forEach: 반환 값 없음
const numbers = [1, 2, 3, 4];
numbers.forEach((n, index) => {
  numbers[index] = n * 2;
});
console.log(numbers); // [2, 4, 6, 8]

var, let, const의 차이를 설명해 주세요.

자바스크립트에서 변수를 선언할 때 var, let, const 키워드를 사용할 수 있습니다. 각 키워드는 서로 다른 특성과 사용 방식을 가지고 있습니다.

var:

  • 중복 선언이 가능합니다.

  • 함수 레벨 스코프를 가집니다. 즉, 함수 내에서 선언된 var 변수는 함수 전체에서 접근할 수 있습니다.

  • 선언하기 전에 사용할 수 있습니다. (호이스팅)

  • 호이스팅 시 초기화되지 않은 상태로 선언만 위로 끌어올려집니다.

let:

  • 중복 선언이 불가능합니다.

  • 블록 레벨 스코프를 가집니다. 즉, 블록({}) 내에서 선언된 let 변수는 해당 블록 내에서만 접근할 수 있습니다.

  • 재할당이 가능합니다.

  • 호이스팅은 되지만, 선언하기 전에 사용할 수 없습니다. (Temporal Dead Zone(TDZ)에 걸리기 때문에, 선언 이전에 접근하면 ReferenceError가 발생합니다.)

const:

  • 중복 선언이 불가능합니다.

  • 블록 레벨 스코프를 가집니다.

  • 재할당이 불가능합니다. 선언과 동시에 초기화되어야 합니다.

  • 객체나 배열의 경우, 참조를 변경하지 않는 한 내부 값을 변경할 수 있습니다.

  • 호이스팅은 되지만, 선언하기 전에 사용할 수 없습니다. (Temporal Dead Zone(TDZ)에 걸리기 때문에, 선언 이전에 접근하면 ReferenceError가 발생합니다.)

// var: 함수 스코프, 호이스팅 시 초기화됨
console.log(a); // undefined
var a = 10;

// let: 블록 스코프, 호이스팅 시 초기화되지 않음
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;

// const: 블록 스코프, 재할당 불가, 호이스팅 시 초기화되지 않음
console.log(c); // ReferenceError: Cannot access 'c' before initialization
const c = 30;

var를 사용하지 않고 let과 const를 사용하는 것이 권장되는 이유는 다음과 같습니다:

  1. 스코프 범위: var는 함수 스코프를 가지지만, let과 const는 블록 스코프를 가집니다. 이는 변수가 선언된 블록 내부에서만 유효하게 하여 오류를 줄이고 코드의 예측 가능성을 높입니다.
  2. 호이스팅(Hoisting): var는 변수 선언이 호이스팅되지만, let과 const는 호이스팅되더라도 초기화가 되지 않습니다. 이는 코드의 실행 순서를 더 직관적으로 이해할 수 있게 합니다.
  3. 재할당 및 상수 선언: const는 상수 선언에 사용되어 재할당을 방지합니다. 이는 코드의 안정성을 높이고 의도하지 않은 변수 변경을 방지하는 데 도움이 됩니다.
  4. 변수 선언의 명확성: let과 const는 코드 작성 시 의도를 명확히 나타냅니다. const는 변경되지 않는 값을, let은 변경 가능한 값을 나타내어 코드를 읽는 사람이 쉽게 이해할 수 있게 합니다.

const로 선언된 객체나 배열의 특성에 대해 설명해 주세요. 그리고 객체나 배열의 내용을 변경하지 않도록 하려면 어떻게 해야 하나요?

const로 선언된 객체나 배열은 참조 자체는 불변이지만, 내부 값은 변경할 수 있습니다. 예를 들어, const로 선언된 배열의 요소나 객체의 프로퍼티는 변경할 수 있습니다. 이는 const가 변수의 참조를 고정시키지만, 그 참조가 가리키는 객체나 배열의 내용까지 고정시키지는 않기 때문입니다.

객체나 배열의 내용을 변경하지 않도록 하려면 다음과 같은 방법을 사용할 수 있습니다:

  • 객체: Object.freeze()를 사용하여 객체를 동결시킵니다. 이렇게 하면 객체의 프로퍼티를 추가, 삭제, 변경할 수 없게 됩니다.

  • 배열: 배열도 Object.freeze()를 사용하여 동결시킬 수 있습니다. 배열의 요소를 추가, 삭제, 변경할 수 없게 됩니다.

TDZ가 생기는 이유와 그 목적은 무엇인가요?

TDZ(Temporal Dead Zone)가 생기는 이유는 변수 선언과 초기화의 일관성을 유지하고, 코드를 더 안전하게 만들기 위해서입니다. 자바스크립트에서 let과 const로 선언된 변수는 스코프의 시작 지점부터 선언문까지 TDZ에 머물게 되며, 이 구간에서는 변수를 참조할 수 없습니다.

TDZ의 주요 목적

  1. 코드의 안전성 향상: TDZ는 변수가 선언되기 전에 접근하는 것을 방지하여, 잠재적인 참조 오류를 줄입니다. 이는 변수가 초기화되지 않은 상태에서 사용되는 것을 막아, 예기치 않은 버그를 예방하는 데 도움이 됩니다.
  2. 코드의 명확성: TDZ를 통해 변수는 선언과 동시에 초기화되어야 함을 명확히 합니다. 이는 코드의 흐름을 더 예측 가능하게 만들고, 개발자가 코드의 실행 순서를 쉽게 이해할 수 있게 합니다.
  3. 일관된 스코핑 규칙: TDZ는 블록 레벨 스코프를 사용하는 let과 const의 일관된 동작을 보장합니다. 이를 통해 함수 레벨 스코프를 가지는 var와의 차별성을 명확히 하고, 변수를 선언할 때 더 의도적으로 사용할 수 있게 합니다.

호이스팅과 TDZ의 관계를 설명해 주세요.

호이스팅과 TDZ는 자바스크립트 변수 선언과 관련된 중요한 개념입니다. 호이스팅은 자바스크립트 엔진이 변수 선언을 스코프의 최상단으로 끌어올리는 동작을 의미합니다. 하지만, let과 const의 경우에는 호이스팅되더라도 TDZ에 의해 초기화 전까지는 접근할 수 없습니다.

  1. 호이스팅: 모든 변수 선언(var, let, const)은 스코프의 최상단으로 호이스팅됩니다. var는 호이스팅과 동시에 undefined로 초기화되기 때문에, 선언 전에 접근해도 오류가 발생하지 않습니다. 반면, let과 const는 선언은 호이스팅되지만 초기화는 선언문에서 이루어집니다.
  2. TDZ: let과 const는 호이스팅된 후, 초기화되기 전까지 TDZ에 머물게 됩니다. 이 기간 동안 해당 변수에 접근하려고 하면 참조 오류(ReferenceError)가 발생합니다. 이는 변수가 초기화되기 전에 사용되는 것을 방지하여 코드의 안정성을 높입니다.

TDZ(Temporal Dead Zone)에 대해서 설명해 주세요.

TDZ(Temporal Dead Zone)는 자바스크립트에서 let과 const 키워드로 선언된 변수들이 초기화되기 전에 접근할 수 없는 구간을 의미합니다. TDZ는 스코프의 시작 지점부터 변수 선언문까지의 구간을 포함합니다. 이 구간에서는 변수를 참조하면 참조 오류(ReferenceError)가 발생합니다.

호이스팅이 되지 않는다고 표현하지만, 실제로 호이스팅되고 있는 이유는 무엇인가요?

let과 const로 선언된 변수들도 사실 호이스팅이 됩니다. 다만, var와는 달리 초기화 단계가 함께 진행되지 않습니다. var로 선언된 변수는 호이스팅 시 undefined로 초기화되지만, let과 const로 선언된 변수는 초기화되지 않은 상태로 TDZ에 머무릅니다. 이는 초기화 전까지 변수를 사용할 수 없게 만드는 효과를 줍니다. 따라서, let과 const도 호이스팅되지만 TDZ에 의해 초기화되기 전에는 접근할 수 없는 것입니다.

메서드 체이닝에 대해 설명해 주세요.

메서드 체이닝은 객체의 메서드가 자기 자신을 반환하여, 여러 메서드를 연속해서 호출할 수 있게 하는 프로그래밍 기법입니다. 이를 통해 코드가 간결해지고, 직관적인 흐름을 유지할 수 있습니다.

장점:

  • 코드가 간략해집니다.
  • 직관적인 코드를 작성할 수 있습니다.
  • 여러 메서드를 한 줄로 연결할 수 있어 코드의 가독성이 높아집니다.

단점:

  • 에러 발생 시, 어느 부분에서 에러가 발생했는지 파악하기 어렵습니다.
  • 디버깅이 복잡할 수 있습니다.

메서드 체이닝은 코드의 가독성과 유지보수성을 높이는 데 유용하지만, 에러 처리와 디버깅에 주의가 필요합니다.

class Calculator {
  constructor() {
    this.value = 0;
  }

  add(num) {
    this.value += num;
    return this;
  }

  subtract(num) {
    this.value -= num;
    return this;
  }

  multiply(num) {
    this.value *= num;
    return this;
  }

  divide(num) {
    this.value /= num;
    return this;
  }
}

const calc = new Calculator();
calc.add(5).subtract(2).multiply(3).divide(1);
console.log(calc.value); // 9

일반 함수와 화살표 함수의 차이

일반 함수:

  • this 바인딩: 함수 호출 방식에 따라 this에 바인딩할 객체가 동적으로 결정됩니다.

  • 생성자 함수: new 키워드를 통해 생성자 함수로 사용할 수 있습니다.

  • arguments 객체: 함수 실행 시 암묵적으로 arguments 변수가 전달되어 사용할 수 있습니다.

화살표 함수:

  • 함수 정의: ES6에서 도입된 함수로, function 키워드 대신 화살표(=>)를 사용하여 간략하게 함수를 정의할 수 있습니다.

  • 생성자 함수로 사용 불가: prototype 속성이 없기 때문에 new 키워드를 사용하여 생성자 함수로 사용할 수 없습니다.

  • arguments 객체: arguments 객체를 생성하지 않습니다.

  • this 바인딩: 화살표 함수의 this는 언제나 상위 스코프의 this(Lexical this)를 가리키며, this에 바인딩할 객체가 정적으로 결정됩니다.

  • 클로저로 사용 가능: 화살표 함수는 클로저로 사용될 수 있습니다.

생성자 함수는 객체를 생성하고 초기화하는 데 사용되는 특별한 함수입니다. 자바스크립트에서는 생성자 함수를 통해 새로운 객체를 만들고, 그 객체의 초기 속성값을 설정할 수 있습니다. 생성자 함수는 일반 함수와 비슷하지만, 보통 대문자로 시작하는 이름을 가지며, new 키워드와 함께 사용됩니다. new 키워드를 사용하여 생성자 함수를 호출하면, 새로운 객체가 생성되고 this 키워드는 그 새로 생성된 객체를 가리키게 됩니다. 생성자 함수 내에서는 객체의 속성들을 정의하고 초기값을 설정할 수 있습니다.

arguments 객체는 함수 내부에서 사용할 수 있는 지역 변수로, 함수에 전달된 모든 인수들을 담고 있습니다. 이 객체는 배열과 유사하지만, 실제 배열은 아니며, 배열처럼 인덱스를 통해 접근할 수 있고 length 속성을 가집니다.

arguments 객체는 주로 함수가 몇 개의 인수를 받을지 미리 알 수 없을 때 사용됩니다. 이를 통해 함수에 전달된 인수들을 순회하거나 특정 인수에 접근할 수 있습니다.

this의 의미를 설명해 주세요.

this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수입니다. 함수의 호출 방식에 따라 특정 객체를 바인딩하게 됩니다.

  1. 생성자 함수 내부:
  • 생성자 함수 내부에서 this는 생성자 함수가 생성할 인스턴스에 바인딩됩니다.
  1. Call, Apply, Bind 메서드 사용:
  • call, apply, bind 메서드를 사용할 때, this는 함수에 첫 번째 인자로 전달된 객체에 바인딩됩니다.
  1. 객체 내부의 메서드:
  • 객체 내부의 메서드에서 호출될 때, this는 해당 객체에 바인딩됩니다.
  1. 일반 함수 호출:
  • 위의 세 가지 경우를 제외한 일반 함수 호출에서는 this는 전역 객체에 바인딩됩니다. (엄격 모드에서는 undefined에 바인딩됩니다.)
  1. 화살표 함수 내부:
  • 화살표 함수 내부에서 this를 사용할 경우, this는 해당 화살표 함수가 선언된 상위 스코프의 this에 바인딩됩니다.

자바스크립트에서 bind 메소드의 역할은 무엇인가요?

bind 메소드:

  • bind 메소드는 함수의 this 값을 영구적으로 설정하여 새로운 함수를 반환합니다.
  • 이를 통해 특정 객체를 this로 사용하는 함수를 만들 수 있습니다.
  • 추가적인 인자를 함께 전달할 수도 있습니다.
const obj = { x: 42 };
function printX() {
    console.log(this.x);
}

const boundPrintX = printX.bind(obj);
boundPrintX(); // 42 출력

자바스크립트의 apply와 call 메소드의 차이점은 무엇인가요?

call 메소드:

  • 함수의 this 값을 설정하고, 개별 인자로 전달합니다.
  • 예: func.call(thisArg, arg1, arg2, ...)

apply 메소드:

  • 함수의 this 값을 설정하고, 인자들을 배열로 전달합니다.
  • 예: func.apply(thisArg, [arg1, arg2, ...])
function greet(greeting, name) {
    console.log(greeting + ', ' + name);
}

greet.call(null, 'Hello', 'Alice'); // Hello, Alice
greet.apply(null, ['Hi', 'Bob']);  // Hi, Bob

함수 선언형과 함수 표현식의 차이를 설명해 주세요.

함수 선언형(Function Declaration):

  • function 키워드를 사용하여 함수를 정의합니다.

  • 함수 선언형은 호이스팅되기 때문에 코드가 실행되기 전에 로드됩니다. 따라서, 함수가 선언되기 전에도 호출이 가능합니다.

함수 표현식(Function Expression):

  • 변수에 함수를 할당하는 방식으로 함수를 정의합니다.

  • 함수 표현식은 함수가 선언된 이후에만 호출이 가능합니다. 즉, 함수가 할당된 변수가 접근 가능한 스코프 내에서만 호출할 수 있습니다.

호이스팅에 대해 설명해 주세요.

  • 자바스크립트에서 변수와 함수 선언이 코드의 최상단으로 끌어올려지는 현상을 말합니다.
  • 변수 선언과 함수 선언은 스코프의 최상단으로 끌어올려지지만, 변수의 초기화는 호이스팅되지 않습니다.

호이스팅(Hoisting)은 변수 및 함수의 선언이 스코프 내의 최상단으로 끌어올려지는 것 같은 현상을 말합니다. 이는 자바스크립트 엔진이 코드 실행 전에 변수와 함수의 메모리 공간을 미리 할당해주기 때문입니다.

자바스크립트에서는 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당합니다. 이로 인해 변수 및 함수 선언이 스코프의 최상단으로 끌어올려진 것 같은 현상이 발생하며, 이를 호이스팅이라고 합니다.

주의할 점:

  • 함수 선언형은 호이스팅되어, 함수 선언 이전에도 호출이 가능합니다.

  • 함수 표현식은 호이스팅되지 않습니다. 함수 표현식은 변수에 함수를 할당하는 형태로, 변수 선언 부분만 호이스팅됩니다. 따라서, 함수가 할당된 이후에만 호출이 가능합니다.

이벤트 버블링과 이벤트 캡처링에 대해 설명해 주세요.

이벤트 버블링(Event Bubbling)은 이벤트가 발생한 요소에서 시작하여 그 요소의 상위 요소로 차례차례 전파되는 과정을 말합니다. 예를 들어, 클릭 이벤트가 가장 안쪽에 있는 요소에서 발생하면, 이 이벤트는 그 요소의 부모 요소, 조부모 요소 등 상위 요소들을 따라 최상위 요소까지 전파됩니다.

이벤트 캡처링(Event Capturing)은 이벤트가 가장 상위 요소에서 시작하여, 이벤트가 발생한 요소에 도달할 때까지 하위 요소로 차례차례 전파되는 과정을 말합니다. 즉, 이벤트가 상위 요소에서 하위 요소로 전파되며, 최종적으로 이벤트가 발생한 요소에 도달하게 됩니다.

이벤트 버블링과 캡처링 모두 DOM 트리에서 이벤트가 전파되는 방식이며, 이 두 과정은 순서대로 일어날 수 있습니다. 이벤트 캡처링이 먼저 일어나고, 그 다음 이벤트 버블링이 발생하는 구조를 가지며, 이를 통해 이벤트 핸들러를 원하는 시점에 실행할 수 있습니다.

<!DOCTYPE html>
<html>
<head>
  <title>이벤트 버블링과 캡처링</title>
</head>
<body>
  <div id="parent">
    <button id="child">Click me</button>
  </div>

  <script>
    // 이벤트 캡처링
    document.getElementById('parent').addEventListener('click', (e) => {
      console.log('Parent Capturing');
    }, true);

    // 이벤트 버블링
    document.getElementById('child').addEventListener('click', (e) => {
      console.log('Child Bubbling');
    });

    // 이벤트 버블링
    document.getElementById('parent').addEventListener('click', (e) => {
      console.log('Parent Bubbling');
    });
  </script>
</body>
</html>

이벤트 위임(Event Delegation)이 무엇인지 설명해주세요.

  • 이벤트 리스너를 자식 요소마다 붙이는 대신, 공통된 상위 요소에 하나의 이벤트 리스너를 설정합니다.
  • 이벤트가 발생하면, 이벤트는 버블링(전파)을 통해 상위 요소까지 전달됩니다.
  • 상위 요소의 이벤트 리스너가 이벤트를 처리하며, 이벤트의 target 속성을 통해 실제 이벤트가 발생한 자식 요소를 식별합니다.

이벤트 위임은 자바스크립트에서 이벤트 처리를 효율적으로 관리하기 위한 기법입니다. 이 방법은 공통된 상위 요소에 하나의 이벤트 리스너를 설정하여 자식 요소들의 이벤트를 처리하는 방식입니다. 이를 통해 성능을 최적화하고 코드의 복잡성을 줄일 수 있습니다.

이벤트 위임의 작동 원리:

  1. 버블링: 자바스크립트의 이벤트 모델에서 이벤트가 발생하면, 그 이벤트는 DOM 트리 상에서 상위 요소로 전파(버블링)됩니다. 예를 들어, 특정 요소에서 클릭 이벤트가 발생하면, 그 클릭 이벤트는 해당 요소에서 시작하여 최상위 요소인 document까지 전파됩니다.

  2. 상위 요소에 이벤트 리스너 설정: 상위 요소에 이벤트 리스너를 설정하면, 자식 요소에서 발생하는 모든 이벤트는 상위 요소로 버블링 되므로 상위 요소에서 이를 처리할 수 있습니다. 이렇게 하면 자식 요소 각각에 이벤트 리스너를 설정할 필요 없이, 상위 요소 하나에만 이벤트 리스너를 설정해도 모든 자식 요소의 이벤트를 처리할 수 있습니다.

이벤트 위임의 장점:

  • 효율성: 다수의 자식 요소 각각에 이벤트 리스너를 설정하는 대신, 상위 요소 하나에만 설정하여 메모리 사용량을 줄이고 성능을 개선할 수 있습니다.

  • 동적 요소 처리: 동적으로 생성되는 자식 요소들도 별도의 처리 없이 이벤트 리스너가 적용됩니다.

<!DOCTYPE html>
<html>
<head>
  <title>Event Delegation</title>
</head>
<body>
  <ul id="parent">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
  </ul>

  <script>
    document.getElementById('parent').addEventListener('click', (e) => {
      if (e.target && e.target.nodeName === 'LI') {
        console.log(`List item clicked: ${e.target.textContent}`);
      }
    });
  </script>
</body>
</html>

이벤트 전파란 무엇인가요?

자바스크립트의 이벤트 전파는 이벤트가 발생할 때 DOM 트리를 통해 이동하는 방식을 의미하며, 두 가지 단계로 나눌 수 있습니다:

1. 캡처링 단계 (Capturing Phase):

이벤트가 최상위 요소에서 시작하여 이벤트가 발생한 요소까지 내려가는 단계입니다.

2. 버블링 단계 (Bubbling Phase):

이벤트가 발생한 요소에서 시작하여 최상위 요소까지 올라가는 단계입니다.

예를 들어, 버튼 클릭 시 이벤트 전파는 document에서 시작해 버튼 요소로 내려간 후, 다시 document로 올라갑니다. 기본적으로 이벤트는 버블링 단계에서 처리됩니다.

클로저에 대해 설명해 주세요.

클로저(Closure)는 자바스크립트에서 함수가 정의된 렉시컬 스코프(Lexical Scope)를 기억하여, 함수가 그 스코프 밖에서 실행될 때도 해당 스코프에 접근할 수 있는 특성을 말합니다. 즉, 클로저는 함수와 그 함수가 선언된 어휘적 환경의 조합입니다.

클로저는 함수가 생성될 때, 함수 내부에서 선언된 변수뿐만 아니라 함수가 정의된 환경에 있는 변수들까지도 함께 저장합니다. 이로 인해, 함수가 다른 스코프에서 호출되더라도 원래의 스코프에 접근할 수 있게 됩니다.

장점:

  1. 캡슐화: 데이터를 보호하고 외부에서 직접 접근할 수 없도록 합니다.

  2. 정보 은닉: 내부 변수와 메서드를 숨겨 코드의 보안성과 유지보수성을 높입니다.

  3. 상태 유지: 함수 호출 간의 상태를 기억할 수 있습니다.

단점:

  1. 메모리 소비: 참조를 유지하므로 메모리 사용이 증가할 수 있습니다.

  2. 디버깅 어려움: 내부 상태를 유지하기 때문에 디버깅이 어려울 수 있습니다.

  3. 성능 저하: 외부 변수를 계속 참조하여 성능이 저하될 수 있습니다.

function makeCounter() {
  let count = 0;

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

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

렉시컬 스코프에 대해 설명해 주세요.

렉시컬 스코프(Lexical Scope)란 함수가 선언되는 위치에 따라서 상위 스코프가 결정되는 개념을 의미합니다. 이를 다른 말로 정적 스코프(Static Scope)라고도 부릅니다.

렉시컬 스코프는 함수가 호출되는 위치와는 무저관하게, 함수가 정의된 위치에 따라 변수의 유효 범위가 결정됩니다. 즉, 함수 내부에서 사용되는 변수는 함수가 정의된 시점의 스코프 체인을 기준으로 참조됩니다.

렉시컬 환경에 대해 설명해 주세요.

렉시컬 환경(Lexical Environment)은 변수 식별자, 해당 변수에 바인딩된 값, 그리고 스코프 체인을 포함하는 자료 구조입니다. 이는 자바스크립트 엔진이 변수와 함수의 실행 컨텍스트를 관리하는 방식입니다.

렉시컬 환경은 함수가 호출될 때마다 새롭게 생성되며, 함수의 실행 컨텍스트를 담고 있습니다. 여기에는 다음과 같은 정보들이 포함됩니다:

  1. 환경 레코드: 변수 식별자와 해당 변수에 바인딩된 값을 저장하는 객체입니다.

  2. 외부 렉시컬 환경에 대한 참조: 상위 스코프에 대한 참조를 통해 스코프 체인을 형성합니다.

함수가 실행되는 동안, 해당 함수의 렉시컬 환경은 현재 실행 컨텍스트의 일부로 존재하며, 함수 실행이 종료되면 해당 렉시컬 환경은 제거됩니다.

렉시컬 환경 덕분에 자바스크립트는 함수가 선언된 위치를 기준으로 변수와 상위 스코프를 정확하게 참조할 수 있게 됩니다. 이는 렉시컬 스코프(Lexical Scope)와 밀접한 관련이 있으며, 클로저(Closure)와 같은 고급 개념의 기초가 됩니다.

실행 컨텍스트에 대해 설명해 주세요.

실행 컨텍스트(Execution Context)는 코드가 실행될 때 생성되는 환경을 나타내는 추상적인 개념입니다. 실행 컨텍스트에는 여러 중요한 정보들이 포함되어 있으며, 이 정보들은 코드의 실행을 관리하는 데 필수적입니다.

실행 컨텍스트에는 다음과 같은 정보들이 포함됩니다:

  1. 변수 객체: 함수 내부의 변수, 함수 선언문 등을 저장합니다.

  2. 렉시컬 환경: 변수 식별자와 바인딩된 값을 포함하고, 스코프 체인을 형성합니다.

  3. this 바인딩: this 키워드가 참조하는 객체를 정의합니다.

실행 컨텍스트는 스택 구조로 관리됩니다. 자바스크립트 엔진은 코드를 실행할 때마다 새로운 실행 컨텍스트를 생성하고, 이를 실행 컨텍스트 스택에 추가합니다. 코드 실행이 완료되면, 해당 실행 컨텍스트는 스택에서 제거됩니다.

클로저에서의 실행 컨텍스트

클로저는 함수가 정의된 렉시컬 환경을 기억하여, 함수가 스코프 밖에서 실행될 때도 그 환경에 접근할 수 있게 하는 개념입니다. 이 과정에서 실행 컨텍스트는 중요한 역할을 합니다.

  1. 렉시컬 환경: 함수가 생성될 때, 실행 컨텍스트는 해당 함수의 렉시컬 환경을 생성합니다. 이 렉시컬 환경은 함수 내부에서 선언된 변수들과 함수가 정의된 스코프 체인을 포함합니다.

  2. 환경 참조 유지: 클로저는 함수가 선언된 시점의 실행 컨텍스트를 기억합니다. 이로 인해 함수가 나중에 호출되더라도, 원래의 실행 컨텍스트를 통해 상위 스코프의 변수들에 접근할 수 있습니다. 이는 클로저가 상위 함수의 변수들을 "캡처"하여 유지할 수 있게 합니다.

호이스팅에서의 실행 컨텍스트

호이스팅은 변수와 함수 선언이 스코프 내에서 최상단으로 끌어올려지는 것처럼 동작하는 현상을 말합니다. 이 과정에서 실행 컨텍스트가 중요한 역할을 합니다.

  1. 변수와 함수 선언: 코드 실행 전에 자바스크립트 엔진은 실행 컨텍스트를 생성합니다. 이 컨텍스트는 변수 객체를 포함하여, 코드 내 모든 변수와 함수 선언을 수집합니다.

  2. 선언과 초기화: 실행 컨텍스트는 변수와 함수 선언을 최상단으로 끌어올립니다.

  • var로 선언된 변수는 undefined로 초기화됩니다.

  • 함수 선언은 전체 함수 정의가 호이스팅됩니다.

  1. 실행 단계: 실행 컨텍스트가 생성되고 호이스팅이 완료되면, 코드가 순차적으로 실행됩니다. 이때 변수와 함수는 호이스팅된 상태에서 실행됩니다.

스코프와 스코프 체인에 대해 설명해 주세요.

스코프

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

  1. 전역 스코프 (Global scope):
  • 코드 어디에서든지 접근할 수 있는 범위입니다.

  • 전역 변수는 전체 코드에서 참조할 수 있습니다.

  1. 함수 스코프 (Function scope):
  • 함수 내에서만 유효한 범위를 갖는 스코프입니다.

  • 함수 내부에서 선언된 변수는 해당 함수 내부에서만 접근할 수 있습니다.

  • 함수 스코프는 지역 스코프(Local scope)라고도 불립니다.

  1. 블록 스코프 (Block scope):
  • 블록 단위(\{\}) 내에서만 유효한 범위를 갖는 스코프입니다.

  • letconst 키워드로 선언된 변수는 블록 스코프를 가집니다.

  • 블록 스코프는 조건문, 반복문 등의 코드 블록 내에서 유효합니다.

스코프 체인

스코프 체인이란, 현재 스코프에서 식별자를 검색할 때 상위 스코프를 연쇄적으로 찾아나가는 방식을 의미합니다.

  • 변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 해당 변수를 참조하는 코드의 스코프부터 상위 스코프 방향으로 이동하며 선언된 변수를 검색합니다.

  • 스코프 체인은 함수나 블록 내에서 변수를 찾지 못하면 상위 스코프로 이동하여 검색을 계속합니다.

  • 최종적으로 전역 스코프까지 검색하여 변수를 찾습니다.

이 과정을 통해 자바스크립트는 변수의 유효 범위를 결정하고, 코드에서 변수에 접근할 수 있도록 합니다.

프로토타입과 프로토타입 체인에 대해 설명해 주세요.

프로토타입 (Prototype)

자바스크립트는 프로토타입 기반의 언어이며, 프로토타입이란 객체의 원형을 뜻합니다. 모든 객체는 프로토타입(prototype)이라는 객체를 가지고 있으며, 각각의 객체는 이 프로토타입으로부터 속성(property)과 메서드(method)를 상속받습니다.

  • 프로토타입 상속: 객체는 자신의 프로토타입 객체에 정의된 속성과 메서드를 사용할 수 있습니다.

프로토타입 체인 (Prototype Chain)

프로토타입 체인은 자바스크립트가 특정 객체의 속성(property)이나 메서드(method)에 접근하려고 할 때, 해당 속성이나 메서드가 객체 자체에 없으면 [[Prototype]]이 가리키는 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체를 차례대로 검색하는 과정을 말합니다.

  • 속성 검색 과정: 객체에 속성이 없으면, 자바스크립트 엔진은 프로토타입 체인을 따라 상위 프로토타입 객체에서 속성을 검색합니다.

  • 상속 구조: 프로토타입 체인을 통해 객체는 상위 객체의 속성과 메서드를 상속받습니다.

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}`);
};

const alice = new Person('Alice');
alice.greet(); // Hello, my name is Alice

console.log(alice.__proto__ === Person.prototype); // true

프로토타입(Prototype)과 클래스(Class)의 차이점은 무엇인가요?

프로토타입(Prototype):

  • 자바스크립트의 모든 객체는 프로토타입이라는 숨겨진 링크를 가집니다.
  • 프로토타입은 객체 간 상속을 구현하는 방식입니다.
  • 함수로 객체를 생성할 때, 생성된 객체는 그 함수의 prototype 속성을 참조합니다.

클래스(Class):

  • ES6에서 도입된 문법으로, 객체 지향 프로그래밍을 쉽게 할 수 있게 해줍니다.
  • 클래스는 객체의 청사진으로, 생성자(constructor)와 메소드(method)를 정의합니다.
  • 클래스 기반 상속을 사용합니다.

깊은 복사와 얕은 복사에 대해 설명해 주세요.

깊은 복사 (Deep Copy)

깊은 복사는 새로운 메모리 공간을 확보하여 원본 데이터의 모든 값을 완전히 복사하는 것을 의미합니다. 이 과정에서 원본 데이터와 복사된 데이터는 서로 독립적인 메모리 공간을 가지게 됩니다. 따라서, 복사된 데이터를 수정해도 원본 데이터에는 영향을 주지 않습니다.

얕은 복사 (Shallow Copy)

얕은 복사는 참조 타입 데이터의 메모리 주소값을 복사하는 것을 의미합니다. 즉, 원본 객체와 복사된 객체가 동일한 메모리 주소를 참조하게 됩니다. 이로 인해, 복사된 객체를 수정하면 원본 객체에도 영향을 미치게 됩니다. 얕은 복사를 사용할 때는 이러한 특성을 주의해야 합니다.

// 얕은 복사
const obj1 = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj1 };
shallowCopy.b.c = 3;
console.log(obj1.b.c); // 3

// 깊은 복사
const obj2 = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj2));
deepCopy.b.c = 3;
console.log(obj2.b.c); // 2

구조 분해 할당에 대해 설명해 주세요.

구조 분해 할당(destructuring)은 객체나 배열의 값을 추출하여 변수에 바로 할당할 수 있는 편리한 문법입니다. 이 문법은 ES6에서 도입되었습니다.

객체의 구조 분해 할당:

  • 객체의 속성을 분해하여 변수에 할당할 수 있습니다.

  • 객체의 각 속성을 쉽게 추출하여 사용할 수 있게 합니다.

배열의 구조 분해 할당:

  • 배열의 요소를 분해하여 변수에 할당할 수 있습니다.

  • 배열의 각 요소를 손쉽게 추출하여 사용할 수 있게 합니다.

구조 분해 할당은 코드를 더 간결하고 읽기 쉽게 만들며, 함수의 매개변수로 객체나 배열을 전달받아 필요한 값을 쉽게 추출할 때 유용합니다.

Spread 문법과 Rest 문법의 차이에 대해 설명해 주세요.

Spread 문법:

  • 객체나 배열의 데이터를 개별 요소로 풀어놓는 역할을 합니다.

  • 배열이나 객체를 복사하거나, 여러 배열이나 객체를 결합할 때 유용합니다.

  • 함수 호출 시, 배열 요소를 개별 인수로 전달할 때 사용됩니다.

Rest 문법:

  • 전달받은 여러 인수를 하나의 배열이나 객체로 모아주는 역할을 합니다.

  • 함수의 매개변수에서 사용되어, 가변 인수를 하나의 배열로 받을 수 있습니다.

  • 객체의 나머지 속성을 하나의 객체로 모으거나, 배열의 나머지 요소를 하나의 배열로 모을 때 유용합니다.

// 스프레드 연산자
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2); // [1, 2, 3, 4, 5]

// Rest 파라미터
function sum(...numbers) {
  return numbers.reduce((acc, curr) => acc + curr, 0);
}

console.log(sum(1, 2, 3)); // 6

ES6에서 생긴 큰 변화들에 대해 설명해 주세요.

  1. let & const 키워드:
  • var 키워드와 달리 블록 스코프를 가집니다.

  • 재선언이 불가합니다.

  • const는 재할당이 불가합니다.

  1. 화살표 함수 (Arrow function):
  • 간결한 문법으로 함수를 정의할 수 있습니다.

  • this 바인딩이 정적으로 결정되어, 객체 메서드로 사용하기에는 부적합합니다.

  • 호이스팅되지 않습니다.

  1. for...of 반복문:
  • 배열, 문자열, Map, Set 등 반복 가능한 객체의 값을 순회합니다.

  • Object에 사용하면 TypeError가 발생합니다.

  • 각 반복에서 값을 반환합니다.

  1. for...in 반복문:
  • 객체의 속성을 순회합니다.

  • 각 반복에서 속성 키를 반환합니다. (배열의 경우 인덱스)

  1. 클래스 (class):
  • class 키워드를 사용하여 클래스를 정의할 수 있습니다.

  • constructor를 통해 생성자를 정의합니다.

  • this를 사용해 인스턴스 객체에 접근할 수 있습니다.

  • new 키워드로 인스턴스 객체를 생성할 수 있습니다.

  • 호이스팅되지 않습니다.

  1. 프로미스 (Promise):
  • 비동기 처리를 위한 패턴입니다. 성공 또는 실패 결과를 처리할 수 있습니다.
  1. 템플릿 리터럴 (Template literals):
  • 백틱(`)을 사용하여 문자열 내에 표현식을 삽입할 수 있습니다.

  • 여러 줄 문자열을 쉽게 작성할 수 있습니다.

  1. 기본 매개 변수 (Default parameters):
  • 함수의 매개변수에 기본값을 설정할 수 있습니다.
  1. 나머지 매개 변수 (Rest parameter):
  • 개수가 정해지지 않은 매개변수들을 배열로 받을 수 있습니다.
  1. 전개 연산자 (Spread operator):
  • 배열이나 객체를 개별 요소로 펼칠 수 있습니다.
  1. 구조 분해 할당 (Destructuring assignment):
  • 배열이나 객체의 속성을 해체하여 그 값을 별도의 변수에 할당할 수 있습니다.
  1. 제너레이터 (Generator):
  • 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재개할 수 있는 특수한 함수입니다.
  1. import & export (가져오기 및 내보내기):
  • 모듈 시스템을 통해 코드를 모듈 단위로 분리하고 재사용할 수 있습니다.

Ajax에 대해 설명해 주세요.

Ajax란 Asynchronous JavaScript And XML의 약자로, 브라우저가 가지고 있는 XMLHttpRequest 객체를 이용하여 서버와 브라우저 간에 비동기 방식으로 데이터를 교환할 수 있는 통신 기능을 의미합니다.

Ajax를 사용하면 페이지를 새로 고치지 않고도 서버와 데이터를 주고받을 수 있습니다. 이를 통해 웹 애플리케이션의 사용자 경험을 향상시키고, 동적인 콘텐츠 업데이트가 가능합니다. Ajax는 JSON, HTML, XML 등 다양한 형식의 데이터를 주고받을 수 있으며, 현대 웹 개발에서 중요한 역할을 합니다.

import와 require의 차이점에 대해 설명해 주세요.

import와 require는 둘 다 외부 파일이나 라이브러리의 코드를 불러오는 역할을 하지만, 서로 다른 문법적 구조를 가지고 있습니다. 또한 하나의 프로그램에서 두 키워드를 동시에 사용할 수 없습니다.

require:

  • Node.js에서 사용되는 CommonJS의 키워드입니다.

  • 프로그램의 어느 지점에서나 호출이 가능합니다.

  • 복수 객체 내보내기:

  • exports.객체명 = 객체명;

  • 단일 객체 내보내기:

  • module.exports = 객체명;

import:

  • ES6에서 새롭게 도입된 키워드입니다.

  • 필요한 모듈 부분만 선택하여 로드할 수 있어 require보다 성능이 우수하며 메모리 절약이 가능합니다.

  • 복수 객체 내보내기:

  • export \{ 객체명 \};

  • 단일 객체 내보내기:

  • export default 객체명;

npm과 yarn의 차이 및 장단점

npm (Node Package Manager):

  • Node.js와 함께 기본적으로 설치되는 패키지 매니저입니다.

  • JavaScript 패키지를 설치, 관리 및 배포할 수 있습니다.

  • 커맨드라인 인터페이스를 통해 다양한 명령어를 제공합니다.

장점:

  • 넓은 사용자 기반: npm은 Node.js와 함께 기본적으로 설치되므로 널리 사용됩니다.

  • 풍부한 패키지: npm 레지스트리에 많은 패키지가 등록되어 있어 다양한 기능을 쉽게 사용할 수 있습니다.

  • 오랜 역사와 안정성: npm은 오랜 시간 동안 사용되어 왔기 때문에 안정성과 신뢰성을 보장합니다.

단점:

  • 속도 문제: 이전 버전의 npm은 패키지 설치 속도가 느리다는 평이 있었습니다.

  • 일관성 부족: npm은 종종 패키지 설치 시 일관성이 부족하여, 동일한 종속성을 가진 프로젝트에서도 서로 다른 버전의 패키지가 설치될 수 있습니다.

Yarn:

  • Facebook에서 개발한 패키지 매니저로, npm의 단점을 보완하고자 만들어졌습니다.

  • npm 레지스트리와 호환되며, 빠르고 일관성 있는 패키지 설치를 목표로 합니다.

장점:

  • 빠른 속도: Yarn은 병렬 패키지 설치를 통해 npm보다 빠른 설치 속도를 자랑합니다.

  • 일관성: Yarn은 yarn.lock 파일을 통해 종속성 버전의 일관성을 유지합니다. 이는 동일한 프로젝트에서 항상 동일한 버전의 패키지가 설치되도록 보장합니다.

  • 보안: Yarn은 패키지를 설치할 때 체크섬을 통해 패키지의 무결성을 확인합니다.

단점:

  • 추가 설치 필요: Node.js와 함께 기본적으로 설치되지 않으므로 별도로 설치해야 합니다.

  • npm과의 중복: npm이 이미 널리 사용되고 있어, Yarn을 사용하면 두 패키지 매니저의 중복 관리가 필요할 수 있습니다.

package.json과 package-lock.json의 역할에 대해 설명해 주세요.

package.json:

  • 현재 프로젝트에 관한 정보와 패키지 매니저(npm, yarn)를 통해 설치한 모듈들의 의존성을 관리하는 파일입니다.

  • 프로젝트의 이름, 버전, 설명, 주요 스크립트, 의존성 목록 등을 포함합니다.

  • 의존성 목록에는 프로젝트가 필요로 하는 패키지들과 그 버전 범위가 정의되어 있습니다.

package-lock.json:

  • package.json에 선언된 패키지가 설치될 때 정확한 버전과 종속성이 설치되도록 보장하는 파일입니다.

  • 패키지의 설치 이력을 기록하여, 동일한 버전의 패키지가 일관되게 설치되도록 합니다.

  • 이를 통해 다른 개발자나 배포 환경에서 패키지 설치 시 동일한 버전의 패키지가 설치되도록 보장합니다.

TypeScript를 쓰는 이유에 대해 설명해 주세요.

TypeScript는 마이크로소프트(Microsoft)에서 개발하고 관리하는 오픈소스 프로그래밍 언어로, 자바스크립트의 단점을 해결하기 위해 만들어졌습니다.

  1. 타입 에러 방지:
  • 컴파일 단계에서 타입 오류를 포착하여, 런타임 전에 문제를 발견할 수 있습니다.
  1. 코드 가독성 및 디버깅 향상:
  • 명시적인 정적 타입 지정을 통해 코드의 가독성을 높이고, 디버깅을 쉽게 할 수 있습니다.
  1. 코드 자동 완성 및 가이드:
  • 강력한 코드 자동 완성 기능과 개발 가이드를 제공하여 개발 생산성을 향상시킵니다.
  1. 객체지향 프로그래밍 지원:
  • 클래스와 인터페이스의 특징을 지원하여 객체지향 프로그래밍 환경을 제공합니다.

null, undefined, undeclared, NaN에 대해 설명해 주세요.

null:

  • null은 사용자가 의도적으로 변수에 "빈 값"을 할당한 경우를 의미합니다. 이는 변수가 객체가 아니라는 것을 명시적으로 표현할 때 사용됩니다.

undefined:

  • undefined는 변수가 선언되었지만, 아직 값이 할당되지 않은 상태를 의미합니다. 즉, 변수가 초기화되지 않았을 때의 기본 값입니다.

undeclared:

  • undeclared는 변수가 선언되지 않은 경우를 의미합니다. 변수를 선언하지 않고 접근하려고 할 때 발생하는 상태입니다.

NaN:

  • NaN은 "Not a Number"의 약어로, 숫자로 나타낼 수 없는 값을 나타냅니다. 주로 숫자 연산이 실패했을 때 결과로 반환됩니다.

자바스크립트 데이터 타입에 대해 설명해 주세요.

자바스크립트의 데이터 타입은 크게 원시 타입(Primitive Data Type)과 객체/참조 타입(Object/Reference Type)으로 나뉩니다.

원시 타입 (Primitive Data Type):

  • boolean: 논리적 참(true) 또는 거짓(false)을 나타냅니다.

  • null: 의도적으로 값이 비어 있음을 나타내는 타입입니다.

  • undefined: 변수가 선언되었지만, 아직 값이 할당되지 않은 상태를 나타냅니다.

  • number: 숫자 값을 나타냅니다. 정수와 부동소수점을 포함합니다.

  • string: 문자열 값을 나타냅니다.

  • symbol: ES6에서 추가된 타입으로, 고유하고 변경 불가능한 값을 나타냅니다. 주로 객체의 고유한 프로퍼티 키를 만들 때 사용됩니다.

객체/참조 타입 (Object/Reference Type):

  • object: 객체, 배열, 함수 등을 포함하는 타입입니다. 객체는 여러 속성의 집합으로, 키-값 쌍으로 구성됩니다.

비교:

  • 원시 타입은 값이 직접 변수에 저장됩니다. 값이 변경되면 새로운 메모리 공간이 할당됩니다.

  • 객체/참조 타입은 값이 참조에 의해 저장됩니다. 변수는 객체의 메모리 주소를 참조합니다. 객체의 값이 변경되면, 해당 객체를 참조하는 모든 변수에 영향을 미칩니다.

mutable과 immutable에 대해 설명해 주세요.

mutable:

  • 변경 가능한 변수의 유형을 말합니다.

  • 주로 참조 타입 데이터(객체, 배열 등)에 해당합니다.

  • 데이터의 값을 변경하면 동일한 메모리 주소에서 값이 변경됩니다.

mutable methods:

  • pop, push, unshift, shift, splice, fill, reverse, sort 등

immutable:

  • 변경이 불가한 변수의 유형을 말합니다.

  • 주로 원시 타입 데이터(boolean, null, undefined, number, string, symbol)에 해당합니다.

  • 데이터의 값을 변경하면 기존 메모리 주소를 변경하지 않고, 새로운 메모리 주소에 새로운 값이 할당됩니다.

immutable methods:

  • concat, filter, find, forEach, includes, indexOf, map, join 등

  • 문자열 메서드(slice, replace, split 등)는 모두 immutable methods입니다.

throttle과 debounce에 대해 설명해 주세요.

throttle과 debounce는 DOM 이벤트를 기반으로 실행하는 JavaScript의 성능을 최적화하기 위해 이벤트를 제어하고 제한하는 방법입니다.

throttle:

  • 이벤트를 일정 주기마다 처리하여 이벤트를 제어하는 방식입니다.

  • throttle은 설정한 주기마다 이벤트를 실행하므로, 지속적으로 발생하는 이벤트를 효율적으로 관리할 수 있습니다.

debounce:

  • 연속적으로 발생하는 이벤트들을 그룹화하여 일정 시간 동안 이벤트가 발생하지 않으면 하나의 이벤트만 실행되도록 처리하는 방식입니다.

  • debounce는 일정 시간 동안 이벤트가 발생하지 않을 때까지 대기한 후, 마지막 이벤트를 실행합니다.

iterable, iterator, generator에 대해 설명해 주세요.

이터러블(iterable):

  • 순회 가능한 객체를 의미합니다.

  • 배열, 문자열, Map, Set 등과 같이 Symbol.iterator 메서드를 가진 객체가 이터러블입니다.

이터레이터(iterator):

  • 반복을 위해 설계된 특정 인터페이스가 있는 객체입니다.

  • next() 메서드를 가지며, \{ value, done \} 객체를 반환합니다.

  • value: 현재 위치의 값

  • done: 반복이 끝났는지를 나타내는 불리언 값

제너레이터(generator):

  • iterator 객체를 반환하며, 이터러블을 생성하는 함수입니다.

  • 제너레이터 함수를 통해 이터레이터를 만들 수 있으며, 함수 내부에서 값을 순회할 수 있습니다.

  • 제너레이터 함수는 함수 선언문에 *(Asterisk)를 붙여 선언합니다.

  • 제너레이터 함수 내에서는 yield 키워드를 사용하여 값을 반환하고, 함수의 실행을 일시 중지할 수 있습니다.

자바스크립트 동작 원리에 대해 설명해 주세요.

자바스크립트는 싱글 스레드 기반의 언어이며, V8 엔진을 사용합니다. V8 엔진은 크게 메모리 힙(Memory Heap)과 콜 스택(Call Stack) 두 요소로 구성되어 있습니다.

Memory Heap:

  • 메모리 할당이 이루어지는 공간입니다.

Call Stack:

  • 코드가 실행될 때 호출 스택이 쌓이는 공간입니다. 함수 호출이 시작되면 스택에 쌓이고, 실행이 완료되면 스택에서 제거됩니다.

Web APIs:

  • 콜 스택에서 실행된 비동기 함수는 Web API를 호출하고, Web API는 콜백 함수를 콜백 큐에 밀어 넣습니다.

  • Web API에는 DOM, Ajax, setTimeout 등이 있습니다.

Callback Queue:

  • 콜백 함수를 저장하는 자료구조로, 선입선출(FIFO) 방식으로 함수를 처리합니다. Task Queue라고도 불립니다.

Event Loop:

  • 이벤트 루프는 콜 스택이 비워지면 콜백 큐에 존재하는 함수들을 하나씩 콜 스택으로 옮기는 역할을 합니다. 이 과정을 통해 비동기 작업이 처리됩니다.

자바스크립트는 웹 브라우저나 Node.js 환경에서 동작하며, 이벤트 기반, 비동기 프로그래밍을 지원하는 싱글 스레드 언어입니다. 자바스크립트의 동작 원리는 크게 다음과 같은 요소로 구성됩니다:

엔진 (Engine):

자바스크립트 코드를 해석하고 실행하는 역할을 합니다. 대표적인 자바스크립트 엔진으로는 V8 (Google Chrome과 Node.js에서 사용)이 있습니다.

콜 스택 (Call Stack):

자바스크립트는 싱글 스레드로 동작하기 때문에 한 번에 하나의 작업만 처리할 수 있습니다. 콜 스택은 함수 호출이 발생할 때마다 해당 함수를 스택에 쌓고, 함수 실행이 완료되면 스택에서 제거하는 방식으로 작동합니다.

힙 (Heap):

동적으로 할당되는 메모리를 저장하는 곳입니다. 객체와 같은 데이터는 힙에 저장됩니다.

이벤트 루프 (Event Loop):

자바스크립트의 비동기 동작을 관리합니다. 콜백 함수나 이벤트 핸들러가 실행되기를 기다리는 동안, 이벤트 루프는 콜 스택이 비어 있는지 확인하고, 비어 있다면 작업 큐(Task Queue)에서 대기 중인 작업을 콜 스택으로 이동시켜 실행합니다.

태스크 큐 (Task Queue):

비동기 작업의 콜백 함수들이 대기하는 곳입니다. 타이머, 이벤트, 프로미스의 콜백 등이 여기에서 대기하다가 콜 스택이 비면 실행됩니다.

자바스크립트의 실행 과정:

  1. 코드 실행: 자바스크립트 엔진이 코드를 해석하고 실행합니다.
  2. 함수 호출: 함수가 호출되면 콜 스택에 쌓입니다.
  3. 비동기 작업: 비동기 작업(예: 타이머, 네트워크 요청)이 발생하면 콜백 함수가 태스크 큐에 추가됩니다.
  4. 이벤트 루프: 이벤트 루프가 콜 스택을 감시하다가 비어 있으면 태스크 큐에서 작업을 가져와 실행합니다.

V8 엔진에 대해서 설명해 주세요.

V8 엔진은 구글 크롬과 Node.js에서 사용되는 자바스크립트 엔진입니다. V8 엔진은 자바스크립트 코드를 빠르게 실행하기 위해 설계되었으며, 자바스크립트를 기계어로 변환하여 실행하는 JIT(Just-In-Time) 컴파일러를 포함하고 있습니다. 메모리 관리와 성능 최적화를 통해 자바스크립트의 실행 속도를 크게 향상시킵니다.

왜 자바스크립트는 싱글 스레드 기반의 언어인가요?

자바스크립트는 웹 브라우저에서 사용자 인터페이스를 쉽게 다루기 위해 설계된 언어로, 단일 스레드 모델을 채택하여 복잡한 동시성 문제를 피하고, 코드의 직관적 이해를 돕기 위해 싱글 스레드 기반으로 동작합니다. 이 모델을 통해 개발자는 비교적 단순한 구조로 코드를 작성할 수 있으며, UI 업데이트와 이벤트 처리를 효율적으로 관리할 수 있습니다.


자바스크립트의 reduce() 메서드가 무엇인가요 ?

reduce() 메서드는 배열의 각 요소를 순회하면서 누적값을 계산하는 데 사용됩니다. 이 메서드는 배열을 단일 값으로 축약하는 기능을 합니다.

reduce() 메서드는 두 개의 인수를 받습니다:

  1. 콜백 함수: 배열의 각 요소에 대해 실행되는 함수. 이 함수는 누적값(accumulator)과 현재 요소(currentValue)를 인수로 받습니다.

  2. 초기값 (optional): 누적값의 초기값. 생략하면 배열의 첫 번째 요소가 초기값이 됩니다.

사용 예시

  • 배열의 합 계산: 배열의 모든 요소를 더해 하나의 값으로 반환할 수 있습니다.

  • 배열의 최대값 계산: 배열의 각 요소를 비교하여 최대값을 찾을 수 있습니다.

  • 배열의 객체 속성 합산: 배열의 객체 속성 값을 모두 합산할 수 있습니다.

자바스크립트에서 스프레드 연산자(Spread Operator)가 무엇인가요?

스프레드 연산자(Spread Operator)는 자바스크립트에서 배열이나 객체의 요소를 개별 요소로 확장하는 데 사용되는 문법입니다. 세 개의 점(...)으로 표현됩니다. 이 연산자는 배열이나 객체를 복사하거나 병합할 때, 그리고 함수에 인수를 전달할 때 유용하게 사용됩니다.

주요 기능

  1. 배열 확장:
  • 기존 배열의 요소를 새로운 배열에 쉽게 복사하거나 합칠 수 있습니다.
  1. 객체 확장:
  • 기존 객체의 속성을 새로운 객체에 복사하거나 합칠 수 있습니다.
  1. 함수 호출 시 인수 확장:
  • 배열의 요소를 개별 인수로 쉽게 전달할 수 있습니다.

장점

  • 간결성: 배열이나 객체를 쉽게 복사하고 합칠 수 있어 코드가 간결해집니다.

  • 가독성: 코드의 의도가 명확해져 가독성이 높아집니다.

  • 유연성: 함수 호출 시 인수의 개수를 동적으로 처리할 수 있어 유연성이 높아집니다.

자바스크립트의 class 키워드를 사용하여 클래스를 정의하고, 상속을 구현하는 방법은 무엇인가요?

자바스크립트에서 class 키워드는 클래스를 정의하고 상속을 구현하는 데 사용됩니다.

클래스 정의

class 키워드를 사용하여 클래스를 정의할 수 있습니다. 클래스는 객체를 생성하기 위한 템플릿으로, 속성과 메서드를 포함합니다. constructor 메서드는 객체를 초기화하는 데 사용되며, 클래스 내에 다양한 메서드를 정의할 수 있습니다.

상속 구현

extends 키워드를 사용하여 클래스를 상속할 수 있습니다. 이를 통해 하위 클래스는 상위 클래스의 속성과 메서드를 상속받아 사용할 수 있습니다. 상위 클래스의 생성자와 메서드를 호출할 때는 super 키워드를 사용합니다.

자바스크립트에서 배열의 filter 메서드가 무엇인가요?

자바스크립트에서 filter 메서드는 배열의 각 요소를 테스트하여 조건을 만족하는 요소들만으로 새로운 배열을 생성하는 메서드입니다. 이 메서드는 원본 배열을 변경하지 않고, 조건을 충족하는 요소들로 구성된 새로운 배열을 반환합니다.

주요 특징

  • 조건에 맞는 요소 선택: filter 메서드는 제공된 조건(콜백 함수)을 만족하는 배열의 요소들을 선택합니다.

  • 원본 배열 불변: 원본 배열은 변경되지 않으며, 새로운 배열이 반환됩니다.

  • 콜백 함수 사용: 콜백 함수는 배열의 각 요소에 대해 호출되며, 요소가 조건을 만족하면 true, 만족하지 않으면 false를 반환합니다.

사용 방법

  • 콜백 함수: 콜백 함수는 배열의 각 요소에 대해 실행되며, 세 개의 인수를 받습니다:
  1. currentValue: 현재 처리 중인 요소.

  2. index (optional): 현재 요소의 인덱스.

  3. array (optional): filter 메서드를 호출한 배열 자체.

자바스크립트의 비구조화 할당(Destructuring Assignment)에 대해 설명해 주세요.

자바스크립트의 비구조화 할당(Destructuring Assignment)은 배열이나 객체의 요소를 개별 변수로 추출하여 할당하는 문법입니다. 이를 통해 코드의 가독성과 유지보수성을 높일 수 있습니다.

주요 특징

  1. 배열 비구조화 할당:
  • 배열의 요소를 변수에 쉽게 할당할 수 있습니다.
  1. 객체 비구조화 할당:
  • 객체의 속성을 변수에 쉽게 할당할 수 있습니다.

사용 예시

  1. 배열 비구조화 할당:
  • 배열의 첫 번째와 두 번째 요소를 각각 firstsecond 변수에 할당합니다.
  1. 객체 비구조화 할당:
  • 객체의 nameage 속성을 각각 변수에 할당합니다.

장점

  • 가독성 향상: 복잡한 데이터 구조를 간결하게 표현할 수 있어 코드의 가독성이 높아집니다.

  • 유지보수성 향상: 필요한 데이터만 추출하여 사용할 수 있어 코드의 유지보수성이 향상됩니다.

  • 간편함: 배열이나 객체에서 특정 요소를 쉽게 추출할 수 있어 코딩이 간편해집니다.

자바스크립트에서 Promise.all 메서드의 역할과 사용 예를 설명해 주세요.

자바스크립트에서 Promise.all 메서드는 여러 개의 프로미스를 동시에 실행하고, 모든 프로미스가 해결될 때까지 기다린 후, 그 결과들을 배열로 반환하는 메서드입니다. 이 메서드는 병렬로 비동기 작업을 처리할 때 유용합니다.

역할

  • 병렬 실행: 여러 개의 프로미스를 병렬로 실행합니다.

  • 결과 집합 반환: 모든 프로미스가 성공하면 각 프로미스의 결과를 배열로 반환합니다.

  • 에러 처리: 하나의 프로미스라도 실패하면 Promise.all은 즉시 실패하고, 첫 번째 에러를 반환합니다.

사용 예

  1. 동시에 여러 비동기 작업을 실행: 예를 들어, 여러 API 호출을 병렬로 실행하고, 모든 호출이 완료되면 결과를 함께 처리할 수 있습니다.

  2. 모든 작업 완료 후 처리: 여러 파일을 동시에 읽고, 모든 파일의 내용을 한꺼번에 처리해야 할 때 유용합니다.

예시 설명

  • 여러 개의 프로미스가 모두 성공하면 결과를 배열로 반환합니다.

  • 하나의 프로미스라도 실패하면 전체가 실패로 처리됩니다.

자바스크립트의 fetch API가 무엇이며, 어떤 상황에서 사용하는지 설명해 주세요.

자바스크립트의 fetch API는 네트워크 요청을 보내고, 서버로부터 데이터를 받아오는 데 사용되는 현대적인 인터페이스입니다. 주로 AJAX 요청을 대체하며, 비동기적으로 HTTP 요청을 처리할 수 있습니다.

주요 특징

  • 비동기 통신: 웹 페이지를 다시 로드하지 않고 서버와 데이터를 주고받을 수 있습니다.

  • Promise 기반: fetch는 프로미스를 반환하여, 네트워크 요청의 성공과 실패를 처리할 수 있습니다.

  • 유연성: GET, POST, PUT, DELETE 등 다양한 HTTP 요청 메서드를 사용할 수 있습니다.

사용 예

  1. 데이터 가져오기: 서버로부터 JSON 데이터나 파일을 받아와서 웹 페이지에 표시할 때 사용합니다.

  2. 데이터 보내기: 폼 데이터를 서버에 제출하거나, 새로운 리소스를 생성할 때 사용합니다.

  3. API 호출: 외부 API와 통신하여 데이터를 교환할 때 사용합니다.

장점

  • 간단한 문법: XMLHTTPRequest에 비해 더 간결하고 이해하기 쉬운 문법을 제공합니다.

  • Promise 지원: 프로미스를 사용하여 비동기 작업을 간편하게 처리할 수 있습니다.

  • 응답 처리: 다양한 포맷(JSON, 텍스트, 블랍 등)으로 응답을 쉽게 처리할 수 있습니다.

'use strict'는 무엇이며, 왜 사용하는가요?

'use strict':

  • 자바스크립트 코드에서 엄격 모드를 활성화하는 지시어입니다.
  • 엄격 모드를 사용하면 더 엄격한 오류 검사가 적용되어, 실수로 발생할 수 있는 오류를 줄여줍니다.
  • 예를 들어, 변수를 선언하지 않고 사용하거나, 읽기 전용 속성에 값을 할당하는 등의 오류를 방지합니다.
  • 스크립트 전체나 특정 함수에 적용할 수 있습니다.

ES6의 템플릿 리터럴(Template Literals)이란 무엇이며, 어떻게 사용하는가요?

  • ES6에서 도입된 문자열 리터럴로, 백틱(`)을 사용합니다.
  • 다중 행 문자열과 문자열 내에 변수 및 표현식을 포함할 수 있습니다.
  • ${} 구문을 사용하여 변수와 표현식을 포함합니다.
const name = 'Alice';
const greeting = `Hello, ${name}!`;
console.log(greeting); // Hello, Alice!

const multiLine = `This is
a multi-line
string.`;
console.log(multiLine);