Languages/JavaScript

[HUFS/GnuVil] #26 에러 처리, 모듈

성중 2022. 11. 29. 15:22

에러 처리

console.log('[Start]');

foo(); // ReferenceError: foo is not defined
// 발생한 에러를 방치하면 프로그램은 강제 종료된다.

// 에러에 의해 프로그램이 강제 종료되어 아래 코드는 실행되지 않는다.
console.log('[End]');

에러가 발생하지 않는 코드를 작성하는 것은 불가능하며, 에러를 방치하면 프로그램은 강제 종료된다

 

// DOM에 button 요소가 존재하지 않으면 querySelector 메서드는 에러를 발생시키지 않고 null을 반환한다.
const $button = document.querySelector('button'); // null

$button.classList.add('disabled');
// TypeError: Cannot read property 'classList' of null

당장 에러가 발생하지 않더라도 예외적인 상황에 대응하지 않으면 에러로 이어질 수 있다

 

console.log('[Start]');

try {
  // 실행할 코드(에러가 발생할 가능성이 있는 코드)
  foo();
} catch (err) {
  // try 코드 블록에서 에러가 발생하면 이 코드 블록의 코드가 실행된다.
  // err에는 try 코드 블록에서 발생한 Error 객체가 전달된다.
  console.error(err); // ReferenceError: foo is not defined
} finally {
  // 에러 발생과 상관없이 반드시 한 번 실행된다.
  console.log('finally');
}

// try...catch...finally 문으로 에러를 처리하면 프로그램이 강제 종료되지 않는다.
console.log('[End]');

보통 try…catch…finally 문으로 에러를 처리할 수 있다

 

const error = new Error('invalid');

Error 생성자 함수로 에러 객체를 생성할 수 있다

 

에러 객체의 종류

try {
  // 에러 객체를 던지면 catch 코드 블록이 실행되기 시작한다.
  throw new Error('something wrong');
} catch (error) {
  console.log(error);
}

에러 객체를 생성한다고 에러가 발생하지는 않고 try 코드 불록에서 throw 문으로 에러 객체를 던져야 한다

 

const foo = () => {
  throw Error('foo에서 발생한 에러'); // ④
};

const bar = () => {
  foo(); // ③
};

const baz = () => {
  bar(); // ②
};

try {
  baz(); // ①
} catch (err) {
  console.error(err);
}

throw된 에러를 캐치하지 않으면 캐치될 때까지 호출자 방향으로 전파된다

 

모듈

모듈(Module)이란 애플리케이션을 구성하는 개별적 요소로서 재사용 가능한 코드 조각을 뜻하며, 일반적으로 기능을 기준으로 파일 단위로 분리한다. 이 때 모듈이 성립하려면 자신만의 파일 스코프(모듈 스코프)를 가질 수 있어야 한다 (캡슐화)

  • export: 모듈은 공개가 필요한 자산에 한정해 명시적으로 선택적 공개가 가능
  • import: 모듈이 공개한 자산 중 일부 또는 전체를 선택해 자신의 스코프 내로 불러들여 재사용

 

모듈의 export와 import

비표준 모듈 시스템들  (CommonJS, AMD)

 자바스크립트는 사실상 표준인 CommonJS를 채택해 모듈 시스템을 점진적으로 지원하게 되었다

 

<script type="module" src="app.mjs"></script>

ES6에 추가된 ES6 모듈(ESM)은 script 태그에 module 어트리뷰트와 mjs 확장자 파일을 사용한다

 

<!DOCTYPE html>
<html>
<body>
  <script type="module" src="foo.mjs"></script>
  <script type="module" src="bar.mjs"></script>
</body>
</html>

각각의 모듈 파일은 독자적인 모듈 스코프를 가지며 하나의 전역을 공유하지 않는다

 

// lib.mjs
// 변수의 공개
export const pi = Math.PI;

// 함수의 공개
export function square(x) {
  return x * x;
}

// 클래스의 공개
export class Person {
  constructor(name) {
    this.name = name;
  }
}

export 키워드로 다른 모듈들이 재사용할 수 있도록 공개할 수 있다

* 마지막에 객체로 묶어서 한 번에 export 가능

* default 키워드로 이름 없이 하나의 값 export 가능 / 원하는 이름으로 import

 

// app.mjs
// 같은 폴더 내의 lib.mjs 모듈이 export한 식별자 이름으로 import한다.
// ESM의 경우 파일 확장자를 생략할 수 없다.
import { pi, square, Person } from './lib.mjs';

console.log(pi);         // 3.141592653589793
console.log(square(10)); // 100
console.log(new Person('Lee')); // Person { name: 'Lee' }

import 키워드로 다른 모듈에서 공개한 식별자를 자신의 모듈 스코프 내부에서 로드할 수 있다

* 애스터리스크(*)로 전체 식별자 import 가능

* as 키워드로 이름을 변경해 import 가능

 

<!DOCTYPE html>
<html>
<body>
  <script type="module" src="app.mjs"></script>
</body>
</html>

이 경우 의존성(dependency)을 가지는 진입점(entry point)을 script 태그로 로드해야 한다

 

 내용은 위키북스의 '모던 자바스크립트 Deep Dive' 바탕으로 작성되었습니다.