
헷갈리는 것들만 따로 정리할 예정.
deep dive 책을 함께 공부함.
16. 주석, 에러처리, 모듈
16-1. 주석(Comments)
// 주석 Comments
// 한 줄 짜리 주석을 작성할 때 씀.
// TODO(승민) : 해야 할 일을 작성.
// TODO(승민) : XX기능 구현하기.
/*
* 주석은 코드 자체를 설명하는 것이 아니라,
* 왜(WHY)와 어떻게(HOW)를 설명하는 것이 좋음.
* (단, 정말 필요한 경우에만 사용.)
*/
// 외부에서 많이 쓰이는 함수 API인 경우 JSDoc을 사용하면 좋음.
// 사용할 수 있는 주석 방법에 관하여 많이 나옴.
/**
* 제일 첫 줄에는 함수에 대한 설명을 적어주는 것 => 주어진 두 인자를 더한 값을 반환함.
* @param {*} a 숫자1
* @param {*} b 숫자2
* @returns a와 b를 더한 값
*/
/* 를 만들고 enter를 치면 됨 */
function add(a,b){
return a + b;
}
JSDoc에 가면 이 주석을 활용해서 문서를 만들 수 있음.
https://github.com/jsdoc/jsdoc
16-2. error-handling
function readFile(path) {
throw new Error("파일 경로를 찾을 수 없음");
// error를 강제로 발생시킬 때 사용.
return "파일의 내용";
// 이렇게 error를 던지게 되면 밑에 코드는 실행되지 않고 앱이 종료되게 됨.
// but, 파일을 못 읽었다고 해서 앱이 종료되는 것은 좋지 못한 사용 experience임.
}
function processFile(path) {
const content = readFile(path);
// 바로 호출하면 앱이 종료될 수 있음.
const result = "hi" + content;
return result;
}
const result = processFile("경로");
console.log(result);
그런데, error가 뜬다고 해서 앱이 종료되는 것은 좋지 못한 사용 experience임.
우리는 조금 더 우아하게 error를 처리하기 위해서 try...catch...finally문을 사용할 거임.
try...catch...finally문을 이용하여 error를 잡아주게 되면 더 이상 앱이 종료되지 않음.
function readFile(path) {
throw new Error("파일 경로를 찾을 수 없음");
return "파일의 내용";
}
function processFile(path) {
// const content = readFile(path);
// 바로 호출하면 error로 인해 앱이 종료될 수 있음.
let content;
try {
content = readFile(path);
// 함수를 호출하는 부분을 try 내에서 해줘야 함.
} catch (error) {
console.log(error.name);
console.log(error.message);
console.log(error.stack);
// 어떤 경로를 통해서 여기까지 와닿았는지.
content = "기본내용";
// error가 뜰시 content에 "기본내용"이 들어간 상태로 함수가 실행되도록. => hi기본내용
} finally {
console.log("성공하든 실패하든 마지막으로 리소스를 정리할 수 있음!);
}
const result = "hi" + content;
return result;
}
const result = processFile("경로");
console.log(result);
- error가 떴을 때 :
- error가 안 떴을 때 :
16-3. try...catch에 관하여 더 자세하게 알아보기
- try...catch문 :
아무리 프로그래밍에 능한 사람이더라도 error가 있는 코드를 작성할 수 있음.
error가 발생하면 앱은 죽고(즉시 중단되고) 콘솔에 error가 출력됨.
그러나, try...catch...finally문을 사용하면 앱이 죽는 것을 방지하고, error를 잡아서(catch) 더 합당한 무언가를 할 수 있음.
=> 실행한 코드블럭을 표시하고 예외(exception)가 발생(throw)할 경우의 응답을 지정.
try {
nonExistentFunction();
// 실행할 코드
} catch (error) {
console.error(error);
// 에러 핸들링
}
❌❌ try...catch는 오직 런타임 error에만 동작함.
try...catch는 실행 가능한(runnable) 코드에만 동작함. 실행 가능한 코드는 유효한 자바스크립트 코드를 의미.
중괄호 짝이 안 맞는 것처럼 코드가 문법적으로 잘못된 경우엔 try...catch가 동작하지 않음.
try {
{{{{{{{{{{{{
} catch(e) {
alert("유효하지 않은 코드이기 때문에, 자바스크립트 엔진은 이 코드를 이해할 수 없습니다.");
}
❌❌ try...catch는 동기적으로 동작함.
setTimeout처럼 "스케줄 된" 코드에서 발생한 예외는 try...catch에서 잡아낼 수 없음.
setTimeout에 넘겨진 익명 함수는 엔진이 try...catch를 떠난 다음에서야 실행되기 때문.
try {
setTimeout(function() {
noSuchVariable;
// 스크립트는 여기서 죽습니다.
}, 1000);
} catch (e) {
alert( "작동 멈춤" );
}
스케줄 된 함수 내부의 예외를 잡으려면, try..catch를 반드시 함수 내부에 구현해야 함.
setTimeout(function() {
try {
noSuchVariable;
// 이제 try..catch에서 에러를 핸들링 할 수 있습니다!
} catch {
alert("에러를 잡았습니다!");
}
}, 1000);
- try 선언의 구성 :
하나 혹은 그 이상의 선언을 포함한 try 블록 및 catch 항목이나 finally 항목 중 최소한 하나 혹은 둘 다 포함하여 이루어짐.
즉, try 선언에는 세 가지 형식이 존재.
- try...catch
- try...finally
- try...catch...finally
- 실행 순서 :
- 먼저, try {...} 안의 코드가 실행됨.
- error가 없다면, try 안의 마지막 줄까지 실행되고 catch 블록은 건너뜀.
- error가 있다면, try 안 코드의 실행이 중단되고, catch(err) 블록으로 제어 흐름이 넘어감. 변수 err(아무 이름이나 사용 가능)는 무슨 일이 일어났는지에 대한 설명이 담긴 error 객체를 포함함.
이렇게 try {…} 블록 안에서 에러가 발생해도 catch에서 에러를 처리하기 때문에 스크립트는 죽지 않음.
- 예시 살펴보기
1. 에러가 없는 예시: (1)과 (2)를 alert 창에 보여줌
try {
alert('try 블록 시작'); // (1) <--
<--// ...에러가 없습니다.
alert('try 블록 끝'); // (2) <--
catch(err){
alert('에러가 없으므로, catch는 무시됩니다.'); // (3)
}
2. 에러가 있는 예시: (1)과 (3)을 보여줍니다.
try {
alert('try 블록 시작');// (1) <--
lalala;
// 에러, 변수가 정의되지 않음!
alert('try 블록 끝(절대 도달하지 않음)'); // (2)
} catch(err) {
alert(`에러가 발생했습니다!`); // (3) <--
}
- error 객체 :
error가 발생하면 자바스크립트는 error 상세내용이 담긴 객체를 생성함.
그리고 catch 블록에 이 객체를 인수로 전달함.
try {
// ...
} catch(err) { // <-- '에러 객체', err 대신 다른 이름으로도 쓸 수 있음
// ...
}
내장 에러 전체와 에러 객체는 두 가지 주요 프로퍼티를 가짐.
name :
에러 이름.
정의되지 않은 변수 때문에 발생한 에러라면 "ReferenceError"가 이름이 됨.
message :
에러 상세 내용을 담고 있는 문자 메시지.
표준은 아니지만, name과 message 이외에 대부분의 호스트 환경에서 지원하는 프로퍼티도 있음.
stack은 가장 널리 사용되는 비표준 프로퍼티 중 하나임.
stack :
현재 호출 스택.
에러를 유발한 중첩 호출들의 순서 정보를 가진 문자열로 디버깅 목적으로 사용됨.
try {
lalala; // 에러, 변수가 정의되지 않음!
} catch(err) {
alert(err.name); // ReferenceError
alert(err.message); // lalala is not defined
alert(err.stack); // ReferenceError: lalala is not defined at ... (호출 스택)
// 에러 전체를 보여줄 수도 있음.
// 이때, 에러 객체는 "name: message" 형태의 문자열로 변환됨.
alert(err); // ReferenceError: lalala is not defined
}
- 선택적 "catch" 바인딩 :
에러에 대한 자세한 정보가 필요하지 않으면, catch에서 이를 생략할 수 있음.
try {
// ...
} catch { // <-- (err) 없이 쓸 수 있음
// ...
}
- "throw" 연산자 :
throw 연산자는 error를 생성함. 문법은 다음과 같음.
throw <error object>
이론적으로는 숫자, 문자열 같은 원시형 자료를 포함한 어떤 것이든 에러 객체(error object)로 사용할 수 있음.
하지만 내장 에러와의 호환을 위해 되도록 에러 객체에 name과 message 프로퍼티를 넣어주는 것을 권장함.
자바스크립트는 Error, SyntaxError, ReferenceError, TypeError 등의 표준 error 객체 관련 생성자를 지원함.
이 생성자들을 이용해 error 객체를 만들 수도 있음.
let error = new Error(message);
// or
let error = new SyntaxError(message);
let error = new ReferenceError(message);
// ...
일반 객체가 아닌 내장 생성자를 사용해 만든 내장 에러 객체의 name 프로퍼티는 생성자 이름과 동일한 값을 갖음.
프로퍼티 message의 값은 인수에서 가져옴.
let error = new Error("이상한 일이 발생했습니다. o_O");
alert(error.name); // Error
alert(error.message); // 이상한 일이 발생했습니다. o_O
16-3. error-bubbling(에러 버블링)
Bubbling up, Propagating🧼
error는 최종적으로 호출한 사람에게까지 전파됨. 그래서 최종적으로 error를 catch할 수 있음.
function a() {
throw new Error("error!");
}
function b() {
try {
a();
} catch (err) {
// console.log("Catch!");
// 최대한 근접한 곳에서 error catch해줘도 됨.
// 근접한 곳에서 error를 잡아주게 되면 밑에서 error가 catch된 것은 출력되지 않음.
console.log("생각해보니 이 error는 내가 핸들링할 수 없을 것 같군!");
throw err;
// 근접한 곳에서 error를 잡을 수 없을 것 같다면 error를 다시 던지면 됨.
}
}
function c() {
b();
}
try {
c();
} catch (error) {
console.log("Catched!");
// error는 전파가 되기 때문에 최종적으로 error를 catch해줘도 되고
// 위에서 error를 catch해줘도 됨.
}
console.log("done!");
16-4. module 작성 법
- 모듈(module) :
class를 사용할 때 class 내부에 상태값을 숨겨두고 외부에서 함수만을 통해서 상태를 업로드하는 것을 캡슐화라고 하는데,
자바스크립트 파일 별로 캡슐화를 할 수 있는 방법이 있음.
바로 모듈을 사용하는 거임.
자바스크립트 역시 브라우저랑 노드에서 모듈을 사용하는 방법이 조금 다름.
하지만, 최신 노드에서 자바스크립트에서 사용하는 것처럼 모듈을 사용할 수 있기 때문에
브라우저에서 모듈을 어떻게 사용하는지 살펴볼 거임.
먼저 index.html, counter.js, main.js 파일을 만들어줌.
index.html에 counter.js, main.js 파일을 연결시켜줌.
counter.js에서 변수 counter 생성 및 0 할당,
increase 함수를 만들어 함수가 실행될 때마다 1이 증가되어 출력되도록 할 거임.
// counter.js
let count = 0;
function increase() {
count++;
console.log(count);
}
이렇게 하면 main.js에서 변수 count와 함수 increase를 가져다 사용할 수도 있고 값을 변경할 수도 있음.
index.html을 통하여 파일을 공유하기 때문임.
하지만, 이렇게 파일끼리 서로서로 변경할 수 있다는 것은 버그에 치명적임.
이걸 방지하기 위해서 각각의 파일 별로 모듈처럼 만드는 것을 사용할 수 있음.
이렇게 type을 "module"로 지정해주게 되면 파일끼리 서로 접근을 할 수 없게 됨.
자동으로 변수 count 역시 main.js 쪽에서 찾을 수 없게 되기 때문에 error가 발생.
이렇게 모듈을 만들어두면
어떤 것을 외부에서 사용할 수 있게 허용할 건지, 어떤 것을 외부에서 사용하지 못하게 할 건지
조금 더 세부적인 컨트롤이 가능함.
함수 increase를 외부에서 사용할 수 있게 할 거라고 가정한다면,
함수 increase 앞에 export default를 붙여주면 됨.
(export는 외부에서 가져다 쓸 수 있게끔 하는 것이고, default는 이거 하나를 대표적으로 내보내겠다는 뜻.)
그리고 main.js에서 함수 increase를 가져다 쓸 거라면, increase를 import해주면 됨.
현재 export default를 이용해서 하나만 받아오고 있기 때문에 이름을 원하는 대로 설정해줄 수 있음.
이렇게 하면 정상적으로 함수 increase를 가져다 쓸 수 있음.
만약 export를 이용하여 여러 개를 받아올 경우 중괄호 안에 이름을 똑같이 넣어줘야 함.
만약 이런 경우에 이름을 수정하고 싶다면 as를 이용해야 함.
as 앞 쪽에는 기존의 이름을 넣어주고, 뒷쪽에는 사용하고 싶은 이름을 넣어주면 됨.
물론 아래의 이름 역시 변경해줘야 함.
여러 개를 외부에서 사용할 수 있게끔 할 거면 export를 해주면 됨.
그리고 그룹화해서 사용할 수도 있음. *는 전체를 의미함.
이 예시에서는 counter로 그룹화를 해줬기 때문에 export한 것들을 사용하기 위해서
모든 것들의 앞에 counter.을 붙여줘야 함.
'Javascript' 카테고리의 다른 글
다시 시작하는 자바스크립트 - 스코프 (0) | 2023.04.27 |
---|---|
다시 시작하는 자바스크립트 - 비동기 (0) | 2023.04.25 |
다시 시작하는 자바스크립트 - Operators(연산자들) (0) | 2023.04.23 |
다시 시작하는 자바스크립트 - Symbol (0) | 2023.04.22 |
다시 시작하는 자바스크립트 - Set를 이용한 Quiz (0) | 2023.04.22 |
github : https://github.com/dnjfht
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!