[Front] 프론트엔드 면접 대비 지식 정리하기(JavaScript) 2편

devicii·2024년 4월 15일
1

Front

목록 보기
7/8

this 🔥

this가 뭔가요? 🔥
this는 함수를 호출한 객체이다.
this는 어떤 일반 함수에서 어떻게 호출하느냐에 따라서 동적으로 결정되기 때문에 주의해야 함


// 일반 함수 호출
function showThis() {
  console.log(this);
}

showThis(); // 브라우저에서는 window 객체 출력, 엄격 모드에서는 undefined 출력

//메소드로서의 호출 
// 객체의 메소드로서 함수가 호출될 때, this는 해당 메소드를 호출한 객체를 가리킴
const myObject = {
  myMethod() {
    console.log(this);
  }
};

myObject.myMethod(); // { myMethod: [Function: myMethod] }

this 바인딩이란? 🔥
JavaScript에서 bind() 함수는 주어진 함수의 this 키워드 값을 전달된 값으로 바꾼다. 이렇게 하면, 해당 함수가 언제 어디서 호출되든지 간에 this 키워드가 가리키는 값이 고정할 수 있음.

const person = {
  name: 'John',
  greet: function() {
    console.log('Hello, my name is ' + this.name);
  }.bind({ name : '이름 바뀜'});
};

// setTimeout에서 호출될 때 this가 전역 객체(window)를 가리키는 문제를 해결하기 위해 bind 사용
person.greet(); // 'John'이 아닌 이름 바뀜이 출력됌

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

일반 함수의 this는 함수의 선언 위치와 상관 없이, 함수를 호출하는 방법에 따라 달라짐(this는 함수를 호출한 객체를 가리킨다.)

화살표 함수는 this의 호출 방법에 상관없이 함수를 선언한 위치에 의해 결정함(this는 함수를 감싸는 상위 스코프의 this를 가져다 씀)


const person = {
  name: 'John',
  greet: function() {
    console.log('Hello, my name is ' + this.name); // greet 함수 내부에서 this는 person 객체를 가리키고, 따라서 this.name은 person 객체의 name 속성인 'John'을 가리킵니다. 그 결과, "Hello, my name is John"이 출력된다.
  },
  waitAndGreet: function() {
    setTimeout(function() {
      console.log('Hello, my name is ' + this.name);  // 일반 함수: this는 전역 객체를 가리킴. person.waitAndGreet();에서 setTimeout 내부의 함수는 person 객체의 메서드가 아니라, 일반 함수로서 호출됩니다. 따라서 this가 전역 객체(window)를 가리키게 되고, 전역 객체에는 대개 name 속성이 정의되어 있지 않습니다. 이로 인해 "Hello, my name is "에서 이름이 출력되지 않는 것
    }, 1000);
  },
  waitAndGreetArrow: function() {
    setTimeout(() => {
      console.log('Hello, my name is ' + this.name);  // 화살표 함수: this는 person 객체를 가리킴
    }, 1000);
  }
};

person.greet(); // "Hello, my name is John"

person.waitAndGreet(); // "Hello, my name is " - this는 전역 객체를 가리킴 waitAndGreet 메소드 내부의 setTimeout에 전달된 일반 함수는 전역 컨텍스트에서 실행됨

person.waitAndGreetArrow(); // "Hello, my name is John" - this는 person 객체를 가리킴

실행 컨텍스트

실행 컨텍스트는 자바스크립트의 동작 원리를 담은 핵심 개념이다.
이를 잘 이해하면 자바스크립트가 스코프를 기반으로 식별자와 식별자에 바인딩된 값을 관리하는 방식과 호이스팅이 발생하는 이유, 클로저의 동작 방식, 그리고 태스트 큐와 함께 동작하는 이벤트 핸들러와 비동기 처리의 동작 방식을 이해할 수 있다.

자바스크립트에는 아래와 같은 두 개의 실행 컨텍스트가 있다.

Global Execution Context: 전역 실행 컨텍스트는 전역 코드가 실행될 때 생성된다.
이 컨텍스트에서는 전역 변수와 함수가 정의되고, 모든 소스코드는 최종적으로 전역 실행 컨텍스트에서 실행됌.

Function Execution Context: 함수가 호출될 때마다 새로운 함수 실행 컨텍스트가 생성된다. 이 컨텍스트에는 함수 내부의 변수와 매개변수를 포함하고, 함수 실행 컨텍스트는 전역 실행 컨텍스트의 스코프 체인에 포함됨.

스코프 체인 예제

var globalVar = 1; // 전역 변수 선언

function outerFunction() {
  var outerVar = 2; // 외부 함수의 변수 선언

  function innerFunction() {
    var innerVar = 3; // 내부 함수의 변수 선언
    console.log(globalVar); // 1 (전역 변수 접근)
    console.log(outerVar); // 2 (외부 함수의 변수 접근)
    console.log(innerVar); // 3 (내부 함수의 변수 접근)
  }

  innerFunction(); // 내부 함수 호출
}

outerFunction(); // 외부 함수 호출

클로저

클로저에 대해서 아나요?
클로저는 함수와 그 함수가 선언된 렉시컬 환경의 조합이다.
함수가 자신이 선언된 렉시컬 스코프를 기억하고 있어서 함수가 자신이 정의된 환경 밖에서 호출되어도 함수가 정의된 당시의 환경에 접근이 가능하다.

let outerFunction = function() {
  let outerVar = 'outside';

  let innerFunction = function() {
    console.log(outerVar); // 'outside'
  };

  return innerFunction;
};

let myInner = outerFunction();
myInner(); // 'outside'


// 1. outerFunction이 호출되면 outerVar가 생성되고 innerFunction이 정의된다.
// 2. outerFunction은 innerFunction을 반환.
// 3. outerFunction이 종료되어도 innerFunction은 outerVar에 접근할 수 있어서 outside가 출력된다.

function counterFactory() {
  let count = 0;

  return {
    increment: function() { count++; },
    decrement: function() { count--; },
    getCount: function() { return count; }
  };
}

const counter = counterFactory();
counter.increment(); // count is now 1
counter.increment(); // count is now 2
console.log(counter.getCount()); // 2
counter.decrement(); // count is now 1
console.log(counter.getCount()); // 1

// counterFactory는 count 변수와 3개의 메서드를 가진 객체를 반환.
// 반환된 객체의 메서드는 counterFactory 함수의 count 변수에 접근할 수 있다.
// 이를 통해 count 변수의 값을 유지할 수 있게됌.

클래스

자바스크립트에서 클래스가 생기기 전에는 어떤 방식으로 객체지향 패턴을 구현했나요?
클래스가 도입되기 이전에는 주로 생성자 함수나 프로토타입을 이용해 객체지향 프로그래밍 패턴을 구축했다.


// 생성자 함수 사용 예제
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
};

const john = new Person('John', 30);
john.sayHello(); // 출력: Hello, my name is John and I'm 30 years old.

// 1. Person 생성자 함수는 name과 age 프로퍼티를 가진 객체를 생성합니다.
// 2. Person.prototype.sayHello는 모든 Person 인스턴스가 공유하는 메서드입니다.
// 3. new Person('John', 30)을 통해 새로운 Person 인스턴스를 생성할 수 있습니다.

// 프로토타입 체인을 이용한 상속 예제

// 생성자 함수
function Person(name, age) {
  this.name = name;
  this.age = age;
}

// 메서드를 프로토타입에 추가
Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
};

// 새로운 Person 객체 생성
const john = new Person('John', 30);
john.sayHello(); // Hello, my name is John and I'm 30 years old.

// 프로토타입 체인 확인
console.log(john.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true


// 1. Person 생성자 함수를 정의한다. 생성자 함수는 this를 사용하여 새로운 객체의 프로퍼티를 초기화 한다.

// 2. Person.prototype.sayHello를 통해 Person 인스턴스의 공유 메서드를 정의합니다. 이 메서드는 모든 Person 인스턴스에서 사용가능.

// 3. new Person('John', 30)을 통해 새로운 Person 인스턴스 john을 생성함.

// john.sayHello()를 호출하면 john 객체의 __proto__가 Person.prototype을 가리키는 것을 확인할 수 있다.

// Person.prototype.__proto__는 Object.prototype을 가리키고 있음. 이것이 프로토타입 체인의 끝이다.

생성자 함수와 클래스의 차이

아래 예제처럼 둘 다 비슷한 기능을 하지만 클래스 문법이 더 간결하고 직관적이다. 그러나 어찌 되었던 간에 클래스도 프로토타입을 기반으로 추상화 한다.



// 생성자 함수
function Person(name) {
  this.name = name;
}

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

const john = new Person('John');
john.sayHello(); // 'Hello, my name is John'

// 클래스 사용
class Person {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const john = new Person('John');
john.sayHello(); // 'Hello, my name is John'

클래스의 상속
클래스 상속은 extends 키워드를 사용한다.
자식 클래스는 부모 클래스의 모든 프로퍼티와 메서드를 상속받고, 자식 클래스는 자신만의 프로퍼티와 메서드를 추가할 수 있으며, super() 메서드를 통해 부모 클래스의 생성자를 호출할 수 있습니다.


// 부모 클래스
class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a sound.`);
  }
}

// 자식 클래스
class Dog extends Animal {
  constructor(name) {
    super(name);
  }

  bark() {
    console.log(`${this.name} barks.`);
  }
}

// 인스턴스 생성
const buddy = new Dog('Buddy');
buddy.speak(); // Buddy makes a sound.
buddy.bark(); // Buddy barks.

스프레드 문법

spread 문법이 뭔가요?
ES6에 도입된 문법으로 배열이나 객체의 요소를 펼칠 수 있게 된다. 덕분에 배열이나 객체를 쉽게 복사하거나 병합할 수 있음
어떤 상황에서 사용할 수 있죠?

  1. 배열 복사 및 병합

// 배열 복사
const originalArray = [1, 2, 3];
const copiedArray = [...originalArray];
console.log(copiedArray); // [1, 2, 3]

// 배열 병합
const array1 = [1, 2];
const array2 = [3, 4];
const mergedArray = [...array1, ...array2];
console.log(mergedArray); // [1, 2, 3, 4]
  1. 함수 호출 시 인자로 전달
// 전개 연산자로 인수 전달
function sum(a, b, c) {
  return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6
  1. 객체 복사 및 병합
// 객체 복사
const originalObject = { a: 1, b: 2 };
const copiedObject = { ...originalObject };
console.log(copiedObject); // { a: 1, b: 2 }

// 객체 병합
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const mergedObject = { ...obj1, ...obj2 };
console.log(mergedObject); // { a: 1, b: 2 }

구조 분해 할당

구조 분해 할당이 뭔가요?
배열이나 객체의 값을 개별 변수에 쉽게 할당할 수 있는 문법이다. 코드의 가독성이 좋고 복잡한 데이터 구조를 쉽게 다룰 수 있다.

구조 분해 할당은 크게 어떤 종류가 있나요?

배열 구조 분해 할당


// 기본 배열 구조 분해 할당
const [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3

// 기본값 지정
const [x = 0, y = 0] = [1];
console.log(x, y); // 1 0

// 나머지 요소 가져오기
const [first, ...rest] = [1, 2, 3, 4];
console.log(first, rest); // 1 [2, 3, 4]

객체 구조 분해 할당

// 기본 객체 구조 분해 할당
const { name, age } = { name: 'John', age: 30 };
console.log(name, age); // 'John' 30

// 새로운 변수 이름 지정
const { name: personName, age: personAge } = { name: 'John', age: 30 };
console.log(personName, personAge); // 'John' 30

// 기본값 지정
const { x = 0, y = 0 } = { x: 1 };
console.log(x, y); // 1 0

// 중첩 객체 분해
const { address: { city, country }} = { address: { city: 'Seoul', country: 'Korea' }};
console.log(city, country); // 'Seoul' 'Korea'

브라우저 렌더링 과정

브라우저의 렌더링 과정에 대해 설명해보세요
1. DOM(Document Object Model)트리 생성

변환 : 브라우저가 HTML의 원시 바이트를 읽어와서, HTML에 정의된 인코딩(예: UTF-8)에 따라 개별 문자로 변환.

토큰화 : 브라우저가 문자열을 W3C 표준에 지정된 고유 토큰으로 변환.

렉싱 : 토큰은 해당 속성 및 규칙을 정의하는 “객체”로 변환.

DOM 생성 : 마지막으로 HTML 마크업에 정의된 여러 태그 간의 관계를 해석해서 트리 구조로 완성된다.

  1. CSSOM(CSS Object Model) 생성
    HTML과 마찬가지로 작성된 스타일을 브라우저가 이해할 수 있는 형식으로 변환하여 처리한다.

이러한 과정을 거치면 CSSOM이라는 트리 구조가 완성된다.

  1. 렌더링 트리 생성
    DOM 트리와 CSSOM 트리가 만들어지면, 이 둘을 결합해서 렌더링 트리를 생성한다. 렌더링 트리에는 페이지를 렌더링 하는데 필요한 노드만 포함하게 된다.

  1. 레이아웃 단계
    레이아웃 단계에서 뷰포트 내의 각 요소의 위치화 크기를 정확히 계산한다.
  1. 페인팅 단계
    렌더링 트리의 각 노드를 실제 픽셀로 변환한다. 레이아웃 단계의 계산이 모두 완료되면, 화면에 요소를 그리는데 이를 페인팅이라고 함.

리플로우(Reflow) & 리페인트(Repaint)

사용자 액션 등으로 인해 HTML 요소가 추가/제거되거나 스타일이 변경되면 다음과 같은 과정이 일어난다.

리플로우(Reflow)
렌더링 트리 생성과 레이아웃 단계를 다시 수행하고, 변경된 요소와 그에 따라 영향받는 모든 노드들의 레이아웃 정보를 다시 계산한다.

리페인트(Repaint)
리플로우 결과를 바탕으로 실제 화면에 다시 그린다.

async & defer에 대한 설명

자바스크립트에서 script 태그를 사용하여 외부 스크립트 파일을 로드할 때, 기본적으로 HTML 파싱이 중단되고 스크립트의 로딩 및 실행이 완료될 때까지 기다린다. 이는 페이지 로딩 속도에 영향을 줄 수 있다. 이러한 문제를 해결하기 위해 async와 defer 속성이 생겨남.

script 태그를 body 태그 밑에 둬야하는 이유가 있을까요?

  1. DOM 참조 가능
    자바스크립트 코드에서 DOM 요소를 참조하려면 해당 요소가 이미 생성되어 있어야 한다. 태그 내부에 스크립트 태그를 두면 DOM이 준비된 상태에서 스크립트가 실행됨.
  2. 페이지 렌더링 지연 방지 태그 내부에 있는 스크립트는 페이지 렌더링을 차단할 수 있음. 사용자가 콘텐츠를 보기 전에 스크립트가 실행되어야 하는 경우가 아니라면, 태그 내부에 두는 것이 좋습니다.
  
// 1. DOM 참조 가능
  
<body>
  <div id="content">Hello, World!</div>

  <script>
    // DOM 요소 참조가 가능합니다.
    const contentElement = document.getElementById('content');
    contentElement.textContent = 'Updated content';
  </script>

 // 2. 페이지 렌더링 지연 방지
<head>
  <script>
    // 이 스크립트는 페이지 렌더링을 차단할 수 있습니다.
    alert('Page load is blocked!');
  </script>
</head>
<body>
  <div>Page content</div>
</body>

이벤트

마우스 이벤트 타입에는 뭐가 있나요? click 말고 클릭을 대체할 수 있는 이벤트가 있나요?
자바스크립트에서는 다양한 이벤트를 지원한다.

  
// mousedown과 mouseup  
element.addEventListener('mousedown', function() {
  console.log('마우스 버튼이 눌렸습니다.');
});
element.addEventListener('mouseup', function() {
  console.log('마우스 버튼에서 손이 떼어졌습니다.');
});

// mousemove 
element.addEventListener('mousemove', function(event) {
  console.log(`마우스 위치: ${event.clientX}, ${event.clientY}`);
});

그 외에 알고 있는 대표적인 이벤트가 있나요?

키보드 이벤트

  
document.addEventListener('keydown', function(event) {
  console.log(`눌린 키: ${event.key}`);
});

폼 이벤트

  
document.querySelector('form').addEventListener('submit', function(event) {
  event.preventDefault(); // 폼의 기본 제출 동작을 막습니다.
  console.log('폼이 제출되었습니다.');
});

document.querySelector('input').addEventListener('input', function() {
  console.log('입력 값이 변경되었습니다.');
});

이벤트 핸들러를 등록하는 방식에는 어떤 것들이 있나요?

인라인 이벤트 핸들러 (HTML 속성 사용)
인라인 이벤트 핸들러는 HTML 요소의 속성으로 직접 이벤트 핸들러를 등록하는 방식 이 방식은 간단하고 직관적이지만, HTML과 자바스크립트 코드가 혼합되어 유지보수가 어려워질 수 있다.

  
<button onclick="alert('버튼이 클릭되었습니다!')">클릭하세요</button>

속성을 이용한 이벤트 핸들러 등록
이 방식은 자바스크립트에서 HTML 요소의 이벤트 처리 속성에 함수를 할당하는 방법 인라인 방식보다는 유지보수성이 좋지만, 하나의 요소에 하나의 이벤트 핸들러만 등록할 수 있다는 단점이 있습니다.

document.getElementById('myButton').onclick = function() {
    alert('버튼이 클릭되었습니다!');
};

addEventListener()를 이용한 이벤트 핸들러 등록
addEventListener() 메서드를 사용하면 동일한 요소에 여러 이벤트 핸들러를 등록할 수 있고, 이벤트 캡처링과 버블링을 더 세밀하게 제어할 수 있다. 제일 권장되는 방식

  
function myClickFunction() {
    alert('버튼이 클릭되었습니다!');
}

document.getElementById('myButton').addEventListener('click', myClickFunction);

// 이벤트 핸들러 제거
document.getElementById('myButton').removeEventListener('click', myClickFunction);

이벤트 전파(propagation)에 대해서 알고 있나요?

이벤트가 발생할 경우 이벤트가 시작된 요소로부터 상위 방향으로 이벤트가 순서대로 전파된다. 이벤트 핸들러(event handler)는 모든 하위 요소에서 발생한 이벤트를 감지할 수 있는 것이다.
이벤트 전파에는 이벤트 버블링과 이벤트 캡처링으로 나뉜다.

이벤트 버블링(Event Bubbling)
이벤트 버블링은 이벤트가 발생한 요소에서 시작해 DOM 트리를 거슬러 올라가면서 상위의 요소들로 전파되는 현상. 대부분의 이벤트는 버블링을 사용하여 전파된다.

예를 들어, button 요소를 클릭하는 경우에 클릭 이벤트는 먼저 button에 발생하고, 그 다음 button의 부모 요소로, 그리고 계속해서 DOM 트리의 루트까지 이벤트가 전파된다.

  
// 위 예제에서 버튼을 클릭하면, 먼저 "버튼 클릭!" 경고창이 표시되고, 이어서 "div 클릭!" 경고창이 표시된다.
<div onclick="alert('div 클릭!')">
  <button onclick="alert('버튼 클릭!')">클릭하세요</button>
</div>
  

이벤트 캡처링(Event Capturing)
이벤트 캡처링은 이벤트가 DOM 트리의 가장 상위에서 시작하여 이벤트가 실제 발생한 요소로 내려가는 과정이다. 캡처링은 이벤트가 목표 요소에 도달하기 전에 상위 요소에서 이벤트를 잡아내고자 할 때 사용한다.

 
  
// 이벤트 캡처링을 사용하려면, addEventListener의 세 번째 인자를 true로 설정한다
<div id="parent">
  <button id="child">클릭하세요</button>
</div>

<script>
  document.getElementById('parent').addEventListener('click', function() {
    alert('div 클릭!');
  }, true); // 캡처링 단계에서 이벤트를 잡기 위해 true로 설정

  document.getElementById('child').addEventListener('click', function() {
    alert('버튼 클릭!');
  });
</script>
  

이벤트 전파 중단
이벤트 핸들러 내에서 event.stopPropagation() 메서드를 호출하여 이벤트의 추가적인 전파를 중단할 수 있다. 이를 통해 특정 요소에서 이벤트 처리를 완료하고 상위 요소로의 이벤트 전파를 방지할 수 있게 된다.

document.getElementById('child').addEventListener('click', function(event) {
  alert('버튼 클릭!');
  event.stopPropagation(); // 이벤트 버블링 중단
});

이벤트 위임(delegation)에 대해서 알고있나요?
여러 요소에 대하여 같은 이벤트 핸들러를 설정해야 할 때 유용하다. 개별 요소마다 이벤트 리스너를 지정하는 것이 아닌 공통 부모 요소에 이벤트 리스너를 설정하고, 이벤트가 발생했을 때 이벤트 타깃을 확인해 이벤트를 위임하는 것이다. 메모리 사용량을 줄일 수 있고, 요소가 동적으로 추가되거나 제거될 때 이벤트 리스너를 다시 설정할 필요가 없다.

아래 예제에서 클릭 이벤트는 할 일 목록(ul 요소)에 설정된다. 이벤트가 발생하면 이벤트 리스너는 이벤트의 타깃(event.target)을 확인하여, 그것이 실제로 li 요소인지 확인한 후에 만약 타깃이 li 요소라면, 해당 요소에 completed 클래스를 토글하여 사용자에게 해당 항목이 완료됨을 시각적으로 표시한다.

  
 <!DOCTYPE html>
<html lang="ko">
<head>
    <title>이벤트 위임 예제</title>
</head>
<body>
    <ul id="todoList">
        <li>JavaScript 공부하기</li>
        <li>이벤트 위임 이해하기</li>
        <li>예제 작성하기</li>
    </ul>

    <script src="script.js"></script>
</body>
</html>
 document.addEventListener('DOMContentLoaded', function() {
    // 할 일 목록의 부모 요소 선택
    var todoList = document.getElementById('todoList');

    // 할 일 목록에 대한 클릭 이벤트 리스너 설정
    todoList.addEventListener('click', function(event) {
        // 클릭된 요소가 LI 요소인 경우
        if (event.target.tagName === 'LI') {
            // 클릭된 요소에 'completed' 클래스 토글
            event.target.classList.toggle('completed');
        }
    });
});

e.preventDefault 에 대해 알고 있나요?
e.preventDefault() 메서드는 이벤트의 기본 동작을 취소할 수 있다. 여기서 e는 이벤트 객체를 나타내며, 이 메서드를 호출하면 웹 브라우저가 해당 이벤트에 대해 일반적으로 수행하는 기본 동작이 실행되지 않는다. 폼 제출, 링크 클릭 등 다양한 상황에서 유용하게 사용될 수 있다.

  
  <!DOCTYPE html>
<html lang="ko">
<head>
    <title>e.preventDefault() 예제</title>
</head>
<body>
    <form id="myForm">
        <label for="name">이름:</label>
        <input type="text" id="name" name="name">
        <button type="submit">제출</button>
    </form>

    <script src="script.js"></script>
</body>
</html>

document.addEventListener('DOMContentLoaded', function() {
   var form = document.getElementById('myForm');

   form.addEventListener('submit', function(e) {
       // 폼의 기본 제출 동작을 방지
       e.preventDefault();

       // 여기에 폼 데이터를 처리하는 코드를 작성할 수 있습니다.
       alert('폼 제출이 방지되었습니다!');
   });
});

타이머

호출 스케쥴링이 무엇인가요?
함수를 명시적으로 호출하면 함수가 즉시 실행된다.
만약 함수를 명시적으로 호출하지 않고 일정 시간이 경
과된 이후에 호출되도록 함수 호출을 예약하려면 타이머 함수를 사용한다
.
이를 호출 스케줄링이라한다
.

타이머 함수에는 어떤 것들이 있나요?

 
// setTimeout(callback, delay[, ...args]): 지정한 시간(밀리초) 후에 한 번 실행되는 타이머 함수
 
setTimeout(() => {
 console.log('This message will be printed after 2 seconds.');
}, 2000);
 
// setInterval(callback, delay[, ...args]): 지정한 시간(밀리초) 간격으로 반복 실행되는 타이머 함수

let count = 0;
const intervalId = setInterval(() => {
 console.log('This message will be printed every 1 second.');
 count++;
 if (count === 5) {
   clearInterval(intervalId);
   console.log('Interval stopped.');
 }
}, 1000);
 
 
// setImmediate(callback[, ...args]): 현재 실행 중인 이벤트 루프 사이클이 끝난 후 즉시 실행되는 타이머 함수.
 
console.log('Start');

setImmediate(() => {
 console.log('Immediate callback executed.');
});

console.log('End');

이벤트가 과도하게 호출되어 성능에 문제를 일으킬 경우에 할 수 있는 어떤 일을 통해 해결할 수 있나요?

이벤트가 과도하게 호출되면 성능에 문제가 발생할 수 있다. 그래서 아래와 같은 방법으로 대체할 수 있다.

1.디바운싱(debouncing) 연속적으로 이벤트가 발생할 때 일정 시간 동안 이벤트 처리를 일부러 지연시키는 방법. 이 덕분에 필요한 이벤트가 필요한 시점에만 이벤트 핸들러를 실행할 수 있다.

  
 // Lodash를 사용하여 debounce 함수를 생성
const debouncedResize = _.debounce(function() {
  console.log('윈도우 크기 조정 이벤트가 발생했습니다!');
}, 250); // 250 밀리초 동안 이벤트가 다시 발생하지 않으면 함수 실행

// 이벤트 리스너에 debounced 함수를 사용
window.addEventListener('resize', debouncedResize);

2.쓰로틀(throttle) throttle는 정해진 시간 간격으로만 함수가 실행되도록 제한하는 기법이다. 이는 함수 호출 사이에 최소한의 지연 시간을 강제하여, 빈번한 이벤트 발생 시에도 함수가 지나치게 많이 호출되는 것을 방지할 수 있다. throttle은 스크롤 이벤트나 마우스 이동 이벤트 처리와 같은 지속적으로 발생하는 이벤트에 적합하다.

const handleScroll = _.throttle(function() {
    console.log('스크롤 이벤트 처리');
}, 200);

window.addEventListener('scroll', handleScroll);

Debounce와 Throttle를 적절하게 선택하는 기준

  • 디바운스는 연속적인 이벤트가 끝난 후에만 함수를 실행하고 싶을 때 적절하다. 예를 들면 유저가 입력을 마친 후 검색을 실행하는 경우.

  • 쓰로틀은 이벤트가 지속적으로 발생하는 동안에도 일정 간격으로 함수를 실행해야 할 때 적합하다. 예를 들면 스크롤 이벤트나 브라우저 리사이징 이벤트 등.

비동기 프로그래밍

동기와 비동기의 차이점에 대해서 설명해줄 수 있나요?

동기
동기 방식에선 작업들이 순차적으로 실행된다. 한 작업이 완료된 이후에 다음 작업이 시작된다. 코드가 작성된 순서대로 실행되고, 작업이 수행되는 동안 다음 작업은 대기하게 된다.

장점
1. 코드의 흐름을 이해하기 쉽고, 예측하기 쉽다.
2. 디버깅이 비교적 간단하다

단점
1. 현재 수행 중인 작업이 완료될 때까지 다음 작업이 대기해야 하므로, 리소스 활용이 비효율적일 수 있다.

  
console.log("1. 첫 번째 작업 시작");
// 시간이 걸리는 작업을 가정
for(let i = 0; i < 1000000000; i++) {}
console.log("2. 첫 번째 작업 완료, 두 번째 작업 시작");
// 다음 작업
for(let i = 0; i < 1000000000; i++) {}
console.log("3. 두 번째 작업 완료");
  

비동기
비동기 방식에서는 현재 실행중인 작업이 완료되지 않았어도 다음 작업으로 넘어갈 수 있다. 주로 I/O 작업, 네트워크 요청, 파일 시스템 작업 등에서 많이 사용된다. 비동기 작업이 시작되면, 이 작업은 백그라운드에서 수행되며 완료되면 콜백 함수나 프로미스(Promise)의 then/catch 메소드를 통해 결과를 처리한다.

장점
1. 리소스를 효율적으로 사용하여, 프로그램의 성능을 향상
2. 여러 작업을 동시에 처리할 수 있다.

단점
1. 코드의 흐름이 직관적이지 않을 수 있으며, 복잡한 비동기 로직을 관리하기 어려울 수 있다.
2. 콜백 지옥(callback hell)과 같은 문제를 야기할 수 있다.


  
console.log("1. 첫 번째 작업 시작");

setTimeout(function() {
    console.log("2. 시간이 걸리는 작업 완료");
}, 2000); // 2초 후에 콜백 함수 실행

console.log("3. 첫 번째 작업 완료, 다음 작업으로 넘어감");
  

이벤트 루프와 태스크 큐에 대해서 알고 있나요?

이벤트 루프
이벤트 루프는 계속해서 호출 스택을 확인한다. 호출 스택이 비었을 때, 테스크 큐에서 대기 중인 작업을 호출 스택으로 이동시키고 실행함. 이 과정을 계속 반복하며, 이런 싸이클을 이벤트 루프라 한다.

테스크 큐
테스크 큐는 비동기 작업의 콜백 함수가 대기하는 곳이다. setTimeout, setInterval, HTTP 요청 등의 콜백이 여기에 대기한다. 호출 스택이 비었을 때 테스크 큐 첫 번째의 콜백을 호출 스택으로 가져간다.

마이크로테스크 큐에 대해서 알고 있나요?
마이크로테스크 큐는 테스크큐와는 별도인 후속 처리 메서드의 콜백 함수가 일시적으로 담기는 곳이다. 로미스(Promise)의 콜백이나 MutationObserver, process.nextTick(Node.js 환경)과 같은 다른 비동기 작업의 결과를 처리한다.

 
console.log('1. 시작');

setTimeout(() => {
  console.log('3. 매크로태스크(macro task) 처리');
}, 0);

Promise.resolve().then(() => {
  console.log('2. 마이크로태스크(micro task) 처리');
});

console.log('4. 종료');

태스크 큐와 마이크로태스크 큐 중 어떤 것이 먼저 실행되나요?

마이크로태스크 큐(Microtask Queue)의 작업들은 태스크 큐(Task Queue)의 작업들보다 먼저 실행된다. 이벤트 루프(Event Loop)에서 현재 실행 중인 스크립트가 완료되고, 렌더링이 필요한 경우가 아니라면, 이벤트 루프는 태스크 큐보다 마이크로태스크 큐의 작업을 우선적으로 처리한다.

Ajax

Ajax가 뭔가요 어떤 것을 담당하고 있죠?

Ajax(Asynchronous JavaScript and XML)는 비동기적 웹 애플리케이션의 제작을 위해 사용되는 개발 기법. 이 기술을 사용하면 웹 페이지 전체를 다시 로드하지 않고도 서버와 데이터를 교환하고 웹 페이지를 업데이트할 수 있다.
ajax의 주요 특징으로는 비동기성, 사용자 경험 향상, 서버 통신 등이 있다.

  1. 비동기성(Asynchronous) : 사용자의 액션에 따라 필요한 데이터만을 서버로부터 비동기적으로 요청하고 받아온다.

  2. 사용자 경험 향상 : 페이지 전체를 새로 고침하지 않고도 일부분만 업데이트할 수 있어, 사용자 경험이 크게 향상된다.

  3. 서버 통신 : XMLHttpRequest 객체를 사용해 서버와 통신한다.

Ajax를 사용하면 기존 방식과 어떤 차이가 있을까요?

■Ajax(Asynchronous Javascript And XML) 등장 배경

  • 웹 브라우저의 정보 요청에 서버는 해당 정보를 포함한 전체 페이지를 전달했다.

  • 브라우저와 서버는 매번 전체 페이지를 렌더링, 생성해야 했기에 부담이 되었다.

  • Ajax를 사용하지 않는 사이트가 특유의 깜빡거림 현상을 보이는 이유는 매번 페이지를 싹 지우고 처음부터 렌더링 하기 때문이다.

■Ajax(Asynchronous Javascript And XML) 역사

  • 1999.3 개념이 정립되어 IE5에 등장하였지만, 윈도우에 탑재된 ActiveX를 거쳐 사용해야 했기에 성능 문제로 잘 사용되지 않았다.

  • 2004.4 구글이 발표한 GMail과 구글 지도가 플러그인 없이 Ajax로 구현된 Web App이라는 사실이 밝혀진 열흘 후, Jesse James Garret에 의해 Ajax라는 용어로 불려 고유 명사로 굳어졌다.

  • axios나 oboe등 라이브러리는 비동기 HTTP 요청을 전문적으로 처리한다.

JSON 이 뭔가요?

기존에 사용하던 XML보다 JSON은 간결하고, 읽기 쉽고, 파싱 속도가 빠르다. 이러한 이유로, JSON은 데이터 교환의 주요 형식으로 자리 잡으며, XML을 대체하는 중요한 역할을 하게 되었다.

JSON(JavaScript Object Notation)은 데이터를 저장하거나 전송할 때 사용하는 경량의 데이터 교환 형식. JSON은 사람이 읽고 쓰기 쉬우며, 기계가 파싱하고 생성하기도 간단하다. JSON은 기본적으로 텍스트 형식이며, 자바스크립트 객체 표기법에서 유래함
JSON은 두 가지 구조를 기반으로 한다.

이름/값 쌍의 집합(자바스크립트에서는 "객체"라고 함)
값의 순서 있는 리스트(자바스크립트에서는 "배열"이라고 함)

// 객체 예제
 {
  "name": "Kim",
  "age": 30,
  "isStudent": false,
  "skills": ["JavaScript", "HTML", "CSS"],
  "address": {
    "city": "Seoul",
    "country": "South Korea"
  }
}
  
// 배열 예제
  
[
  {
    "name": "Kim",
    "age": 30
  },
  {
    "name": "Lee",
    "age": 25
  }
]

 

JSON이 제공하는 정적 메서드에 대해 몇가지 말해볼 수 있나요?

JSON.stringify()

이 메서드는 자바스크립트 객체나 값을 JSON 문자열로 변환한다. 서버에 데이터를 보낼 때 유용하게 사용함.

 const person = {
 name: "홍길동",
 age: 25,
 city: "서울"
};

const jsonStr = JSON.stringify(person);
console.log(jsonStr); // {"name":"홍길동","age":25,"city":"서울"}

JSON.parse()
이 메서드는 JSON 문자열을 파싱하여 자바스크립트 객체로 변환한다. 서버로부터 받은 JSON 형태의 문자열 데이터를 자바스크립트 객체로 변환할 때 사용함.

  
const jsonStr = '{"name":"홍길동","age":25,"city":"서울"}';
const person = JSON.parse(jsonStr);
console.log(person); // {name: "홍길동", age: 25, city: "서울"}

  

Ajax로 HTTP 요청을 보내기 위해서는 어떤 방법을 사용할 수 있나요?
. Ajax 요청을 보내기 위해 주로 사용되는 방법은 XMLHttpRequest 객체와 최근에는 더욱 간편한 fetch API를 활용할 수 있다.

XMLHttpRequest 사용 예제

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);

xhr.onload = function () {
  if (xhr.status >= 200 && xhr.status < 300) {
    // 요청이 성공적으로 완료됨
    console.log(xhr.responseText);
  } else {
    // 서버에서 오류 응답
    console.error('Request failed');
  }
};

xhr.onerror = function () {
  // 요청 처리 중 오류 발생
  console.error('Request failed');
};

xhr.send();
  

fetch 사용 예제

  
 fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('Fetch error:', error));
                                           

REST API

REST API가 뭔가요?
REST는 인터넷에서 웹 서비스를 개발하는 데 널리 사용되는 아키텍처 스타일이다. REST API를 통해 클라이언트와 서버 간에 데이터를 JSON, XML, TEXT 등의 형태로 주고받을 수 있으며, 이는 웹, 모바일 애플리케이션 등 다양한 클라이언트에서 활용한다.

REST API의 구성은 어떤 것이 있나요?

  1. 자원(Resource)
  • 자원은 REST API에서 조작하고자 하는 대상으로, 일반적으로 데이터베이스의 레코드나 문서 등이다

  • 웹에서 자원은 URI(Uniform Resource Identifier)로 표현한다. 특정 사용자의 정보를 나타내는 자원은 /users/123과 같은 URI로 표현할 수 있다.


  https://api.example.com/users/123
  1. 메서드(Method)
  • REST API에서는 HTTP 메서드를 사용하여 자원에 대한 조작을 정의한다. 주로 사용되는 메서드는 GET, POST, PUT, PATCH, DELETE 등이 존재한다.
  • 각 메서드는 자원에 대한 특정한 행동을 나타냅니다. 예를 들어, GET은 자원을 조회, POST는 새로운 자원을 생성하는 데 사용한다.
 
GET /users - 사용자 목록 조회
POST /users - 새로운 사용자 생성
GET /users/123 - 특정 사용자 조회
PUT /users/123 - 특정 사용자 정보 전체 업데이트
PATCH /users/123 - 특정 사용자 정보 일부 업데이트
DELETE /users/123 - 특정 사용자 삭제
  1. 표현(Representation)
  • 자원의 상태(데이터)는 클라이언트에게 전송될 때 특정 형식으로 표현한다. 가장 일반적인 형식은 JSON과 XML등이 있다.
{
  "id": 123,
  "name": "홍길동",
  "email": "hong@example.com"
}
  

REST API를 설계하는데 중요한 것이 있을까요?

  1. 자원(Resource) 중심의 설계
  • URI는 자원을 나타내는 데 집중해야 한다. 자원은 명사로 표현되어야 하며, URI는 자원의 구조를 직관적으로 반영해야 함.

     잘못된 예: GET /getUserById/1
     올바른 예: GET /users/1
  
  
 2. HTTP 메서드 활용
- 자원에 대한 행동은 HTTP 메서드(GET, POST, PUT, DELETE 등)를 통해 명확하게 표현해야 한다.
```json
// 자원 조회
GET /books (모든 책 조회), GET /books/1 (특정 책 조회)
// 자원 생성
POST /books (새 책 추가)
// 자원 업데이트
PUT /books/1 (특정 책 전체 업데이트), PATCH /books/1 (특정 책 일부 업데이트)
// 자원 삭제
DELETE /books/1 (특정 책 삭제)

참고자료
ajax

HTTP 요청 메서드에 대해서 아는대로 얘기해보세요

HTTP 상태 코드를 아는대로 말해주세요

1xx: 정보 응답

  • 100 Continue: 클라이언트는 요청을 계속 진행할 수 있음. 큰 데이터를 전송하기 전에 서버가 요청을 받을 준비가 되었는지 확인할 때 사용

2xx: 성공

  • 200 OK: 요청이 성공적으로 처리됨. 가장 일반적인 성공 응답.
    예: GET /users 요청에 대해 사용자 목록이 성공적으로 반환됨.
  • 201 Created: 요청이 성공적으로 처리되어 새로운 리소스가 생성됨.
    예: POST /users 요청으로 새 사용자가 생성됨.

3xx: 리다이렉션

  • 301 Moved Permanently: 요청한 리소스가 영구적으로 새 위치로 이동했음.
    예: 구 URL에서 새 URL로 접근해야 할 때 사용.

4xx: 클라이언트 에러

  • 400 Bad Request: 서버가 요청을 이해할 수 없음. 잘못된 요청 구문, 크기가 너무 크거나, 잘못된 요청 메시지 등이 원인일 수 있음.
    예: JSON 형식 오류.
  • 401 Unauthorized: 요청이 인증을 필요로 함. 클라이언트가 자신을 인증하지 않았음.
    예: 로그인하지 않고 보호된 리소스에 접근하려 할 때.
  • 403 Forbidden: 서버가 요청을 이해했으나, 권한 때문에 거부됨.
    예: 관리자 페이지에 일반 사용자가 접근하려 할 때.
  • 404 Not Found: 서버가 요청한 리소스를 찾을 수 없음.
    예: 존재하지 않는 URL에 대한 요청.

5xx: 서버 에러

  • 500 Internal Server Error: 서버 내부 오류로 요청을 수행할 수 없음.
    예: 서버 프로그램 오류.
  • 503 Service Unavailable: 서버가 오버로드되었거나 유지보수 중이어서 현재 요청을 처리할 수 없음.
    예: 서버 유지보수 중.

Promise

콜백이란 뭐라고 생각하나요?
콜백(callback)은 어떤 함수가 실행된 후, 그 결과를 다루기 위해 다시 호출되는 함수


 function sum(a, b, callback) {
  const tmp = a + b;
  callback(tmp); // 더하기 작업이 끝난 후 콜백 함수를 호출
}

function print(result) {
  console.log("계산 결과: " + result);
}

// sum 함수를 호출하며, 결과를 처리할 콜백으로 결과출력 함수를 전달
sum(5, 3, print);

콜백지옥
콜백 지옥(callback hell)은 여러 비동기 작업이 연속적으로 필요할 때, 각 작업의 결과를 다음 작업의 입력으로 사용해야 하는 경우 발생하는 문제다. 이러한 구조는 코드의 가독성을 떨어뜨리고, 유지보수를 어렵게 만듦.

  function sum(a, b, callback) {
  const tmp = a + b;
  callback(tmp);
}

sum(5, 3, function(result1) {
  console.log("첫 번째 계산 결과: " + result1);
  sum(result1, 10, function(result2) {
    console.log("두 번째 계산 결과: " + result2);
    sum(result2, 15, function(result3) {
      console.log("세 번째 계산 결과: " + result3);
      sum(result3, 20, function(result4) {
        console.log("네 번째 계산 결과: " + result4);
        // 이런 식으로 계속 중첩되는 콜백
      });
    });
  });
});

프로미스가 뭔가요?
프로미스(Promise)는 자바스크립트에서 비동기 작업을 편리하게 처리할 수 있도록 도와주는 객체이다. 프로미스는 비동기 작업의 최종 성공 또는 실패를 나타내는 값을 갖는다.
프로미스는 세 가지 상태를 가진다.

  • 대기(Pending): 비동기 처리 로직이 아직 완료되지 않은 상태
  • 이행(Fulfilled): 비동기 처리가 성공적으로 완료되어 프로미스가 결과값을 반환한 상태
  • 거부(Rejected): 비동기 처리가 실패한 상태
function fetchData(url) {
  return new Promise((resolve, reject) => {
    fetch(url) // fetch API를 사용해 데이터를 요청.
      .then(response => {
        if (response.ok) {
          return response.json(); // 응답이 성공적이면 JSON 데이터를 파싱합니다.
        }
        throw new Error('데이터 로딩 실패'); // 응답이 실패하면 에러를 발생시킵니다.
      })
      .then(data => resolve(data)) // 파싱된 데이터를 resolve합니다.
      .catch(error => reject(error)); // 오류가 발생하면 reject합니다.
  });
}

fetchData('https://api.example.com/data')
  .then(data => console.log(data)) // 데이터를 성공적으로 불러왔을 때의 처리
  .catch(error => console.error(error)); // 데이터 불러오기 실패시의 처리

프로미스 빌트인 객체가 제공하는 정적 메서드에 대해 알고 있나요?

Promise.all
Promise.all 메서드는 프로미스 배열을 인자로 받고, 모든 프로미스가 이행(fulfilled)될 때까지 기다림. 모든 프로미스가 성공적으로 이행되면, 각 프로미스의 결과값을 모아 배열로 반환. 그러나 하나라도 거부(rejected)되면, 그 거부 이유를 가지고 거부된다.

Promise.race
Promise.race 메서드는 프로미스 배열을 인자로 받고, 주어진 프로미스 중 하나라도 이행(fulfilled)되거나 거부(rejected)되는 즉시, 그 프로미스의 결과값 또는 거부 이유와 함께 프로미스를 반환.

Promise.resolve
Promise.resolve 메서드는 주어진 값으로 이행하는 Promise 객체를 반환. 이미 프로미스 객체가 주어진 경우, 그대로 반환.

Promise.reject
Promise.reject 메서드는 주어진 이유로 거부하는 Promise 객체를 반환.

제너레이터와 async await

제너레이터란 뭔가요? 일반 함수와는 어떤 차이가 있죠?

제너레이터(Generator)는 자바스크립트에서 ES6(ES2015)에 도입된 특별한 종류의 함수다. 일반 함수와 달리, 제너레이터는 함수의 실행을 중간에 멈췄다가 필요한 시점에 다시 재개할 수 있다.

제너레이터와 일반 함수의 차이점
정의 방법: 제너레이터 함수는 function 키워드 뒤에 별표(*)를 붙여 선언.

실행 흐름 제어: 제너레이터는 yield 키워드를 사용하여 함수의 실행을 중지시키고, next() 메서드를 호출하여 다시 재개할 수 있다.

반환 값: 제너레이터 함수는 호출될 때 함수의 실행 결과를 반환하는 대신, Generator 객체를 반환합니다. 이 객체를 통해 함수의 실행을 제어할 수 있다.

  
  function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

// 제너레이터 객체 생성
const gen = numberGenerator();

// next() 메서드를 호출하여 제너레이터 함수 실행
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
console.log(gen.next().value); // undefined

async/await 가 뭔가요? 기존의 Promise와는 어떤 차이가 있죠?

async/await는 자바스크립트에서 비동기 작업을 더 쉽게 작성할 수 있도록 ES2017(ES8)에서 도입된 문법이다. 비동기 코드를 동기 코드처럼 보이게 하고, 읽고 작성하기 쉽게 만들 수 있다.

async/await와 Promise의 차이점
가독성: async/await를 사용하면 비동기 코드를 마치 동기 코드처럼 순차적으로 작성할 수 있어, 가독성이 좋다. Promise의 then 체인은 가독성이 떨어짐.

에러 처리: async/await를 사용하면 try/catch 문을 통해 에러 처리를 할 수 있어, 동기 코드와 유사한 방식으로 에러를 핸들링할 수 있다. 반면, Promise에서는 catch 메서드를 사용함.

디버깅: async/await를 사용한 코드는 디버깅이 더 쉽다. Promise의 then 체인은 비동기 호출 스택이 연속되지 않아 디버깅 시 추적이 어려울 수 있다.

promise예제

function fetchUserData() {
return fetch('https://api.example.com/user')
  .then(response => response.json())
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error("Error fetching user data:", error);
  });
}

async/await 예제

async function fetchUserData() {
try {
  const response = await fetch('https://api.example.com/user');
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error("Error fetching user data:", error);
}
}

에러

에러처리를 왜 해야 하나요?
에러 처리를 함으로서 프로그램이 예상치 못한 상황에서도 안정적으로 동작할 수 있게 하기 위함이다. 또한 사용자한테 적절한 피드백을 제공하여야 한다.

  • 안정성 향상
  • 사용자 경험 개선
  • 디버깅 용이

자바스크립트에서 에러를 처리하는 방법에는 뭐가 있을까요?
자바스크립트에선 try & catch문, throw문 등이 다양한 에러 처리가 존재한다.

1. try...catch 문
try...catch 문은 실행할 코드 블록(try 블록)을 지정하고, 에러가 발생하면 그 에러를 잡아서(catch 블록) 처리할 수 있게 한다.



try {
  // 시도할 코드
  let result = 2 / 0;
  if (result === Infinity) {
    throw new Error("0으로 나눌 수 없습니다.");
  }
} catch (error) {
  // 에러 처리 코드
  console.error(error.message); // "0으로 나눌 수 없습니다."
} 
  
  

Promise의 catch 메서드
Promise에서 발생하는 에러는 catch 메서드를 사용하여 처리할 수 있다. 이 방법은 비동기 작업에서 발생하는 에러를 처리하는 데 주로 사용한다.



function divide(a, b) {
  return new Promise((resolve, reject) => {
    if (b === 0) {
      reject(new Error("0으로 나눌 수 없습니다."));
    } else {
      resolve(a / b);
    }
  });
}

divide(10, 0).catch(error => console.error(error.message)); // "0으로 나눌 수 없습니다."
  

async/await와 try...catch
async/await 구문을 사용하는 비동기 함수 내에서도 try...catch 문을 사용하여 에러를 처리할 수 있다.



async function asyncDivide(a, b) {
  try {
    let result = await divide(a, b); // 위의 Promise 예제에서 정의한 divide 함수 사용
    console.log(result);
  } catch (error) {
    console.error(error.message); // "0으로 나눌 수 없습니다."
  }
}

asyncDivide(10, 0);
  

모듈

모듈이 뭔가요?
모듈은 관련된 코드를 하나의 단위로 묶어서 관리하는 것을 의미한다. 자바스크립트에서 모듈은 재사용 가능한 코드의 집합으로 변수, 함수, 클래스 등을 한 집합으로 묶어서 다른 자바스크립트 파일에서 import해서 사용할 수 있다. 모듈 시스템 덕분에 코드의 가독성 및 유지보수성이 확장된다. 또한 네임스페이스 충돌 방지가 가능하다.

모듈 정의 및 내보내기
모듈을 만들기 위해서는 export 키워드를 사용하여 모듈에서 내보낼 변수나 함수, 클래스 등을 지정한다. math.js라는 파일에 두 수를 더하는 함수와 곱하는 함수를 모듈로 정의하고 내봰ㄹ 수 있다.

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

export function multiply(a, b) {
  return a * b;
}

모듈 가져오기
다른 파일에서 이 모듈을 사용하고 싶다면 import 키워드를 사용하여 필요한 기능을 가져올 수 있다. app.js 파일에서 위에서 정의한 math.js 모듈의 함수를 가져와 사용할 수 있다.

 // app.js
import { sum, multiply } from './math.js';

console.log(sum(1, 2)); // 3을 출력
console.log(multiply(3, 4)); // 12를 출력
 

전체 모듈 가져오기
때로는 모듈에서 모든 것을 한 번에 가져오고 싶을 수 있다 import * as 구문을 활용하면 된다.


// app.js
import * as math from './math.js';

console.log(math.sum(5, 6)); // 11을 출력
console.log(math.multiply(7, 8)); // 56을 출력
profile
흘러가는대로 사는

0개의 댓글