자바스크립트는 에러가 발생하면 코드가 끝까지 실행되지 않고 에러 객체를 생성합니다. 에러를 다루는 방법을 알면 더욱 안정적인 프로그램을 만드는대 도움이 됩니다.

에러 타입

const title = '123';
console.log(title);
  • Reference Error : 존재하지 않는 변수 혹은 함수( 존재하지 않는 변수를 사용할 시 (variable))
  • TypeError : 잘못된 방식으로 자료형을 다룸 ( 함수가 아닌 변수를 함수처럼 사용할 시 ex. title())
  • SyntaxError : 문법에 맞지 않는 코드 작성 (변수 선언 시 -를 넣는 경우 ex. const ti-tle)

링크 - 위 3가지 타입을 제외한 에러 객체(오류 유형)

 

에러 객체 구성

  • name: 에러 객체의 타입
  • message: 에러 내용

 

의도적으로 에러를 만들고 발생시키는 법

new 키워드와 에러 객체 이름을 따서 만들 수 있다

const error = new TypeError('타입 에러 발생'); // 에러 객체 생성

throw error; // 의도적으로 발생

console.log('123'); // 에러 발생시키고 난 뒤의 코드는 실행 되지않음

 

try catch문

try catch 문 역시 if와 for문처럼 스코프를 생각해서 코드를 짜야합니다.(try {} 안에 변수 선언 시 중괄호 {} 안에서만 사용이 가능하다) try catch문을 사용하면 프로그램이 에러로 인해 멈추지 않고 catch {} 안에 있는 코드와 그 이후의 코드를 안전하게 실행시킬 수 있습니다. 만약 에러가 발생하지 않는다면 catch문의 코드는 실행되지 않습니다.

 try 문에서 에러가 발생하면 에러 객체가 생성되는데 그건 catch의 첫 번째 파라미터로 전달됩니다. 

try {
    //코드
} catch {
    //에러 발생 시 동작
}
try {
    const error = new TypeError('타입 에러 발생');
    
    console.log('12321')
    
    throw error;
    
    console.log('123'); //실행되지않음
} catch (err){
    console.log('456');
    console.error(err);
    console.log(err);
    console.log(err.name);
    console.log(err.message);
}

결괏값:

console.error는 우리가 평소에 보는 오류처럼 에러를 빨간색으로 처리해 보여줍니다. 이렇게 try catch문으로 에러를 처리하는 과정을 '예외 처리(Exception Handling)'라고 합니다.

 

finally문

finally문은 try catch 문 이후에 항상 발생하는 코드를 적을 때 사용합니다. 예를 들어 try catch문이 사용된 시간을 표시할 때 사용합니다. finally문에서 에러가 발생하면 try catch 문을 중첩으로 사용하여 예외 처리 할 수 있습니다.

try {
try {
  // 실행할 코드
} catch (err) {
  // 에러가 발상했을 때 실행할 코드
} finally {
  // 항상 실행할 코드
} 
} catch { // 첫번째 try문의 catch
// finally문에서 오류 발생시 코드
}

마무리

초보 개발자가 끄적이는 공부노트라 틀린 것이 있을 수 있습니다. 틀린 점 지적은 언제나 환영합니다!

 

 

'JS' 카테고리의 다른 글

[JS]모듈(Module) 모듈화(Modularization)/ Import/Export  (0) 2023.04.06
[JS] 다양한 배열 메소드  (0) 2023.04.06
[JS] 구조 분해(Destructuring)  (0) 2023.04.05
[JS] 옵셔널 체이닝(Optional Chaining)  (0) 2023.04.03
[JS] Spread 구문  (0) 2023.04.01

구조 분해(Destructuring)는 ES2015 이후에 객체와 배열을 분열하는 문법입니다.

 

배열 구조분해

배열은 인덱스 값으로 객체는 key값으로 구성되어 있는 차이점 때문에 배열과 객체에 각각 적용하는 방식이 다릅니다. 먼저 배열부터 살펴봅시다.

const person = ['Jenny','Tom','Yunji','Kevin','Brian'];

const leader = person[0];
const teamLeader = person[1];
const asstManager = person[2];
const teamMember = [person[3], person[4]];

console.log(leader); //Jenny
console.log(teamLeader); //Tom
console.log(asstManager); //Yunji
console.log(teamMember); // ['Kevin', 'Brian']

이렇게 값을 할당하려면 시간도 오래 걸리고 비효율적 이어 보이죠? 그럼 다음 코드를 살펴봅시다.

const person = ['Jenny','Tom','Yunji','Kevin','Brian'];

const [leader, teamLeader, asstManager,...teamMember] = person; //할당되는 값이 배열이 아니면 에러
console.log(leader); //Jenny
console.log(teamLeader); //Tom
console.log(asstManager); //Yunji
console.log(teamMember); // ['Kevin', 'Brian']

위 코드에서는 변수 명을 대괄호[] 안에 배열처럼 선언하고 배열자체를 할당했습니다. 왼쪽의 선언된 변수들의 값이 person 배열에 왼쪽부터 차례대로 할당됩니다. (마지막 변수는 함수의 나머지 파라미터처럼 할당되고 나머지 값을 배열형태로 할당합니다.) 그렇다면 만약 person의 값이 더 적어진다면 어떻게 될까요? 다음 코드를 살펴보겠습니다.

const person = ['Jenny','Tom'];

const [leader, teamLeader, asstManager,...teamMember] = person; //할당되는 값이 배열이 아니면 에러
console.log(leader); //Jenny
console.log(teamLeader); //Tom
console.log(asstManager); //undefined
console.log(teamMember); // []

위 코드와 같이 변수는 undefined 그리고 배열은 빈 대괄호[]를 반환합니다. 이렇게 undefined 값으로 반환되었을 때 문제가 발생할 수도 있는대요. 이런 경우에는 그 값의 초기값을 다음과 같이 할당해 주면 됩니다.

const person = ['Jenny','Tom'];

const [leader, teamLeader, asstManager = 'John',...teamMember] = person; //할당되는 값이 배열이 아니면 에러
console.log(leader); //Jenny
console.log(teamLeader); //Tom
console.log(asstManager); //John
console.log(teamMember); // []

이런 식으로 배열 안에 선언된 변수에 값을 할당해 줌으로써 아무것도 할당 되지 않았을 때에 John을 반환할 수 있습니다. 또한 배열 구조 분해는 이미 저장된 두 변수의 값을 교환할 때도 사용할 수 있습니다.

let leader = 'Jenny';
let teamLeader = 'Tom';

console.log(leader,teamLeader); // Jenny Tom

[teamLeader, leader] = [leader,teamLeader];

console.log(leader,teamLeader); // Tom Jenny

위 코드와 같이 leader 였던 JennyTom으로, teamLeader였던 TomJenny로 바뀐 것이 보입니다. 만약 let 대신 const를 쓰면 각 변수의 값을 바꾸는 것이기 때문에 TypeError가 뜨는 것도 알아두시면 좋습니다.

 

객체 구조 분해

인덱스로 분해되었던 배열과 다르게 객체는 프로퍼티 네임으로 값이 구분이 되기 때문에 할당된 객체의 프로퍼티 네임과 같은 이름의 변수로 {}를 구성해야지 구조 분해가 됩니다. 이런 선언 방식으로 인해 간결하게 프로퍼티 네임을 변수 자체로 사용하려고 할 때 주로 사용합니다. 

const product = {
name: "사과",
price: 1000,
origin: "한국",
nutrition: {
    calorie: 52,
    carbohydrate: 14,
    protein: 0.3,
    fat: 0.2,
}};

const {name, price} = product;

console.log(name); //사과
console.log(price); //1000

중괄호{} 안에 name과 price같이 product의 같은 프로퍼티 네임으로 선언해서 값을 반환했습니다. 만약 프로퍼티 네임이 같지 않으면 어떻게 될까요?

const {name, color} = product;

console.log(name); //사과
console.log(color); //undefined

이런 식으로 undefined 값이 출력됩니다. 이것 또한 아래처럼 할당연산자로 변수의 값을 미리 정해줄 수 있습니다.

const {name,color = '빨간색'} = product;

console.log(name); //사과
console.log(color); //빨간색

또한 배열과 똑같이 마침표 3개(...)를 사용해서 남은 하나의 객체로 모아 할당시킬 수 있습니다.

const {name, ...rest} = product;

console.log(name); //사과
console.log(rest); //name을 뺀 product 객체

그렇다면 나머지 프로퍼티를 제외하고 변수의 이름은 항상 같아야 할까요? 변수명은 같아야하지만 변수명을 자신이 원하는 대로 바꿀 수도 있습니다.

const {name: title, ...rest} = product;

console.log(title); //사과
console.log(rest); //name을 뺀 product 객체

이렇게 콜론(:)기호를 이용해서 객체의 프로퍼티 네임을 선언하듯이 사용하면 가능합니다! 그리고 객체에는 변수이름으로 사용할 수 없는 경우가 있는대요 이럴 때도 위와 같이 이름만 정의해 준다면 변수로 사용할 수 있습니다.

const product = {
name: "사과",
price: 1000,
origin: "한국",
nutrition: {
    calorie: 52,
    carbohydrate: 14,
    protein: 0.3,
    fat: 0.2,
},
'id': '14321' //변수로 사용 불가
};

const {'id' : id} = product; //id로 이름정해주기

console.log(id); //14321

함수 파라미터로써의 활용

앞서서 배열과 객체의 구조 분해 문법을 알아봤는대요. 이를 응용해서 함수의 파라미터 변수를 구조분해의 선언하는 방식으로 값을 할당 받을 수 있습니다.

function printTeam([leader,teamLeader,asstManager, ...teamMember])// 파라미터 구조분해 {
    console.log('Team Members');
    console.log(`Leader is ${leader}`);
    console.log(`Team leader is ${teamLeader}`);
    console.log(`Assist Manager is ${asstManager}`);
    for (let member of teamMember) {
        console.log(`Team Member is ${member}`);
    }
}

const team = ['Jenny','Tom','Yunji','Kevin','Brian'];
printTeam(team);
// Team Members
// Leader is Jenny
// Team leader is Tom
// Assist Manager is Yunji
// Team Member is Kevin
// Team Member is Brian

함수의 파라미터에 변수의 순서대로 배열로 선언해주었고 아규먼트 값으로 team이라는 배열을 전달했습니다. 이를 객체에서도 똑같이 이용할 수 있습니다.

const product = {
name: "사과",
price: 1000,
origin: "한국",
nutrition: {
    calorie: 52,
    carbohydrate: 14,
    protein: 0.3,
    fat: 0.2,
},
};

function printProduct({name, price, origin}) {
    console.log(name);
    console.log(price);
    console.log(origin);
}

printProduct(product);
// 사과
// 1000
// 한국

마무리

구조 분해는 뒤에서 나오는 React Framework나 자바스크립트 기반 라이브러리에서 자주 사용되므로 잘 기억해두는게 좋습니다. 초보 개발자가 끄적이는 공부노트라 틀린 것이 있을 수 있습니다. 틀린 점 지적은 언제나 환영합니다!

Reference

Codeit 모던 자바스크립트 구조분해

 

'JS' 카테고리의 다른 글

[JS] 다양한 배열 메소드  (0) 2023.04.06
[JS] 에러 객체와 try catch문  (0) 2023.04.05
[JS] 옵셔널 체이닝(Optional Chaining)  (0) 2023.04.03
[JS] Spread 구문  (0) 2023.04.01
[JS] 조건부 연산자(Conditional operator)  (0) 2023.03.31

ES 2020 이후에 추가된 방법입니다. 객체 내의 key에 접근할 때 그 참조가 유효한지 아닌지를 확인하고 접근할 수 있습니다. (?.)를 통해 사용이 가능하고 보통 중첩 객체에 사용하면 편리합니다. 다음 코드를 살펴봅시다.

const person = {
    jenny: {
        name: 'Jenny',
        age: 30,
        score: {
            korean: 40,
            english: 80,
            math: 40
        }
    },
    brian: {
        name: 'Brian',
        age: 25,
    }
};

console.log(person.jenny.score.korean); // 40
console.log(person.brian.score.korean); // Uncaught TypeError: Cannot read properties of undefined

객체에 존재하지 않는 값을 접근하려고 하니 바로 타입 에러가 나는 것을 볼 수 있습니다. 이럴 때 옵셔널 체이닝을 몰랐다면 다음과 같이 코드를 짜겠죠?

console.log(person.brian && person.brian.score && person.brian.score.korean); // undefined

딱 보기에도 너무 길고 코드의 가독성이 떨어집니다. 이런 불편함을 해결하기 위해서 등장한 게 바로 옵셔널 체이닝입니다.

console.log(person.brian?.score?.korean); //undefined

?. 이후의 값을 평가했을 때 undefined 혹은 null이라면 바로 undefined를 반환합니다. null 병합 연산자와 함께 활용하면 다음과 같이 응용할 수 있습니다.

function printScore(user) {
    console.log(user.jenny.score?.korean ?? '국어 시험을 안봤습니다.');
}

const user = {
    jenny: {
        score: {
            science: 10
        }
    },
}

printScore(user); //국어 시험을 안봤습니다.

주의할 점

1. 남용하지 마세요! 옵셔널 체이닝은 존재하지 않아도 괜찮은 대상에게만 사용해야 합니다. 에러를 피하기 위해 남용을 하게 되면 디버깅이 어려워질 수 있습니다. 만약 person 객체는 꼭 있어야 하는데 그 안에 age가 필수가 아니라면 아래와 같이 코딩해야 합니다.

console.log(person.jenny?.age); // person객체가 꼭 있을 필요 x
console.log(person?.jenny?.age); // person객체가 없으면 에러

2. 옵셔널 체이닝 앞에 오는 변수는 선언이 되어있어야 합니다. 당연한 얘기지요. 옵셔널 체이닝을 사용하더라도 앞에 변수가 선언되지 않으면 에러가 뜰 것입니다.

'JS' 카테고리의 다른 글

[JS] 에러 객체와 try catch문  (0) 2023.04.05
[JS] 구조 분해(Destructuring)  (0) 2023.04.05
[JS] Spread 구문  (0) 2023.04.01
[JS] 조건부 연산자(Conditional operator)  (0) 2023.03.31
[JS] 화살표 함수(Arrow Function)  (0) 2023.03.31

 ES 2015에서 새롭게 등장한 문법으로 배열에서 주로 유용하게 사용합니다. "펄치다"라는 단어의 뜻과 연관되어 하나로 묶인 값을 여러 개로 펼치는 개념입니다.

const array = ['Google','Naver'];

console.log(array); // ['Google', 'Naver']
console.log(...array); // Google Naver

코드 출력 결과와 같이 Spread를 사용하면 목록의 값이 출력되는 것을 알 수 있습니다. 일반적으로 배열을 복사하려고 하면 다음과 같이 기존의 값도 변경시키기 때문에 복사를 하려면 다른 방법을 사용해야 하는대요.

const array = ['Google','Naver'];
const array2 = array;

array2.push('Tistory'); // push는 array2에 했지만 array1에도 추가됨

console.log(array);  // ['Google', 'Naver', 'Tistory']
console.log(array2); // ['Google', 'Naver', 'Tistory']

이런 문제를 해결하려면 배열의 slice 메서드를 이용할 수 있겠지만 Spread 구문을 사용해서 복사해도 같은 리턴값을 가지는 것을 볼 수 있습니다.

const array = ['Google','Naver'];
const array2 = array.slice();

array2.push('Tistory');

console.log(array);  // ['Google', 'Naver']
console.log(array2); // ['Google', 'Naver', 'Tistory']
const array = ['Google','Naver'];
const array2 = [...array];

array2.push('Tistory');

console.log(array);  // ['Google', 'Naver']
console.log(array2); // ['Google', 'Naver', 'Tistory']

이 외에도 concat 메소드를 사용해서 배열을 합치는 것도 대체할 수 있죠.

const arr1 = ['Google','Naver','Tistory'];
const arr2 = ['Explorer', 'Firefox', 'Bing'];

const arr3 = [...arr1, ...arr2];

const arr4 = arr1.concat(arr2);

console.log(arr3); // ['Google', 'Naver', 'Tistory', 'Explorer', 'Firefox', 'Bing']
console.log(arr4); // ['Google', 'Naver', 'Tistory', 'Explorer', 'Firefox', 'Bing']

또한 함수에 여러개의 파라미터가 있는 경우에 배열을 펼쳐서 arguments로 사용할 수도 있습니다.

function print (first, second, third)
{
    console.log(first, second, third)
}

const arr = [3,4,5]

print(...arr); //3 4 5

 

그런데 Spread구문은 한 가지 주의할 점이 있는대요. 하나의 값을 가진 배열을 펼칠 경우에는 에러가 발생합니다.

const numbers= [1];
const number = ...numbers; //Uncaught SyntaxError: Unexpected token '...'

Spread구문은 하나로 묶인 값을 여러 개로 펼친 개념이기 때문에 하나의 값으로 평가되는 게 아니라 목록의 값으로 평가되기 때문에 이런 문제가 발생하는 것입니다.

객체로의 활용

ES2018이후로 객체에도 Spread 구문을 사용할 수 있다는 표준이 등장함으로써 객체에서도 Spread구문을 사용할 수 있게 되었습니다. 현재는 기존의 객체를 가지고 새로운 객체를 만들 때 Spread 구문을 사용이 가능합니다.

const cat = {
    name: 'Gorong',
};

const catClone = {
    ...cat,
    age : 6,
}

console.log(cat); // {name: 'Gorong'}
console.log(catClone); // {name: 'Gorong', age: 6}

객체를 spread하는 걸로 새로운 배열이나 함수의 아규먼트로 사용이 불가능함.

const cat = {
    name: 'Gorong',
};

const catClone = {
    ...cat,
    age : 6,
}

[...cat]; // Uncaught SyntaxError

(function meow(...args) {
    console.log(args);
})(...catClone); // Uncaught TypeError

 

자바스크립트에서 유일하게 세 개의 피연산자를 가지는 특성으로 인해 삼항 연산자(Ternary operator)라고도 불립니다.

if 문과 비슷한 원리로 작동하는 조건부 연산자는 간단한 조건식을 구성할 때 주로 사용됩니다.

function checker(pass) {
    return console.log(pass ? '통과했습니다' : '재수강해야합니다');
}

checker(true); //통과했습니다
checker(false); //재수강해야합니다.

이런 식으로 간단한 문자열을 출력할 때 if 문 보다 훨씬 간결하게 표현할 수 있는 것을 볼 수 있습니다.

그러나 삼항 연산자는 표현식이기 때문에 일반 if문에서 처럼 변수나 함수를 선언할 수 없어 한계가 명확하다는 단점이 있습니다.

 

+ Recent posts