TIL

객체 리터럴(object literal), Error handling, 클래스(Class)

김영재0412 2022. 11. 26. 00:20

객체 리터럴

 

객체

 

자바스크립트엔 여덟 가지 자료형이 있으며 이 중 일곱 개는 오직 하나의 데이터(문자열, 숫자 등)만 담을 수 있어 '원시형,기본형(primitive type)'이라 부른다. 그런데 객체형은 원시형과 달리 다양한 데이터를 담을 수 있으며 키로 구분된 데이터 집합이나 복잡한 개체(entity)를 저장할 수 있다.

 

  • 원시 타입은 단 하나의 값만을 나타내고, 원시 타입의 값은 변경이 불가능 한 값입니다.
  • 객체 타입은 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료 구조이고, 객체 타입의 값을 변경 가능한 값입니다.

 

Javascript는 객체(Object) 기반의 프로그래밍 언어이고, Javascript를 구성하는 거의 모든 것은 객체로 구성되어 있으므로 객체(Object) 는 0개 이상의 프로퍼티로 구성된 집합이며, 하나의 프로퍼티는 KeyValue로 구성되어 있다. 그러므로 자바스크립트를 잘 다루려면 객체를 잘 이해해야한다.

 

객체는 중괄호 {…}를 이용해 만들 수 있으며 중괄호 안에는 ‘키(key): 값(value)’ 쌍으로 구성된 프로퍼티(property) 를 여러 개 넣을 수 있는데, 키엔 문자형, 값엔 모든 자료형이 허용되며 프로퍼티 키는 ‘프로퍼티 이름’ 이라고도 부른다.

 

서랍장을 상상하면 객체를 이해하기 쉽다. 서랍장 안 파일은 프로퍼티, 파일 각각에 붙어있는 이름표는 객체의 키라고 생각하시면 된다. 복잡한 서랍장 안에서 이름표를 보고 원하는 파일을 쉽게 찾을 수 있듯이, 객체에선 키를 이용해 프로퍼티를 쉽게 찾을 수 있으며 추가나 삭제도 마찬가지이다.

 

빈 객체(빈 서랍장)를 만드는 방법은 두 가지가 있다.
let user = new Object(); // '객체 생성자' 문법
let user = {};  // '객체 리터럴' 문법

 

 

객체 리터럴(object literal)

중괄호 {...}를 이용해 객체를 선언하는 것을 객체 리터럴(object literal) 이라고 부르며 객체를 선언할 땐 주로 이 방법을 사용한다. 객체 리터럴은 객체를 생성하기 위해 Class를 먼저 선언하고 new 연산자와 함께 생성자를 호출할 필요가 없이 일반적인 숫자, 문자열을 만드는것과 유사하게 객체를 생성할 수 있다.

 

let user = {     // 객체
  name: "John",  // 키: "name",  값: "John"
  age: 30        // 키: "age", 값: 30
};

//중괄호 {...} 안에는 ‘키: 값’ 쌍으로 구성된 프로퍼티가 들어간다.
//객체 리터럴은 중괄호 {} 내에 0개 이상의 프로퍼티를 정의해서 선언한다.

 

'콜론(:)'을 기준으로 왼쪽엔 키(key)가, 오른쪽엔 값(value)이 위치한다. 프로퍼티 키는 프로퍼티 ‘이름’ 혹은 '식별자’라고도 부른다.

객체 user에는 프로퍼티가 두 개 있다.

  1. 첫 번째 프로퍼티 – "name"(이름)과 "John"(값)
  2. 두 번째 프로퍼티 – "age"(이름)과 30(값)

 

 

서랍장(객체 user) 안에 파일 두 개(프로퍼티 두 개)가 담겨있는데, 각 파일에 “name”, "age"라는 이름표가 붙어있다고 생각하면 쉽다. 또한 프로퍼티 값엔 모든 자료형이 올 수 있으며 삭제 또한 가능하다.

user.isAdmin = true;

 

delete 연산자를 사용하면 프로퍼티를 삭제할 수 있다.

delete user.age;

 

메서드(Method) 란?

 

프로퍼티를 참조하고 조작할 수 있는 동작(behavior)을 나타내며 객체의 프로퍼티 값이 함수로 구성되어 있을 경우 메서드라고 부른다.

let objectLiteral = {
    key: 'Value', // 프로퍼티
    helloWorld: function () { // 메서드
        return "Hello world";
    }
};

console.log(objectLiteral.helloWorld()); // Hello world

 

 

 

에러 핸들링(Error handling)

 

아무리 프로그래밍에 능한 사람이더라도 에러가 있는 스크립트를 작성할 수 있으며 원인은 아마도 실수, 예상치 못한 사용자 입력, 잘못된 서버 응답 등의 수천만 가지 이유 때문일것이다. 에러가 발생하면 스크립트는 ‘죽고’(즉시 중단되고), 콘솔에 에러가 출력된다.

 

그러나 try..catch 문법을 사용하면 스크립트가 죽는 걸 방지하고, 에러를 ‘잡아서(catch)’ 더 합당한 무언가를 할 수 있게 된다.

 

즉, 에러 핸들링은 에러를 관리하는 방법이고, 예상치 못한 상황에 대처하는 방식이다.

 

 

try / catch 

‘try…catch’ 문법은 서버에서 에러가 발생하지 않게 하기 위해 예외 처리를 진행하는 문법이다.

 

try {

  // 코드...

} catch (err) {

  // 에러 핸들링

}

/*                                  */

const users = ["Lee", "Kim", "Park", 2];

try {
  for (const user of users) {
    console.log(user.toUpperCase());
  }
} catch (err) {
  console.error(`Error: ${err.message}`);
}

// LEE
// KIM
// PARK
// Error: user.toUpperCase is not a function

try…catch 동작 알고리즘은 다음과 같다.

 

 

  1. 먼저, try {...} 안의 코드가 실행된다.
  2. 에러가 없다면, try 안의 마지막 줄까지 실행되고, catch 블록은 건너뛴다.
  3. 에러가 있다면, try 안 코드의 실행이 중단되고, catch(err) 블록으로 제어 흐름이 넘어간다. 변수 err(아무 이름이나 사용 가능)는 무슨 일이 일어났는지에 대한 설명이 담긴 에러 객체를 포함한다.

이렇게 try {…} 블록 안에서 에러가 발생해도 catch에서 에러를 처리하기 때문에 스크립트는 죽지 않는다.

 

 

throw

프로그래머의 입장에서 에러는 고의로 에러를 발생을 시켜야 할때도 있다. 예를 들어서 은행 어플리케이션의 현금 인출 서비스를 만든다고 할 때, 계좌의 잔고가 요청받은 금액보다 적다면 현금 인출을 막고 예외를 발생시켜야하며  이럴때 사용하는 것이 throw이다.

 

throw를 호출하면 그 즉시 현재 실행되고 있는 함수는 실행을 멈추게 됩니다.

 

function withdraw(amount, account) {
  if (amount > account.balance)
    throw new Error("잔고가 부족합니다.");
  account.balance -= amount;
	console.log(`현재 잔고가 ${account.balance}남았습니다.`); // 출력되지 않음
}

const account = { balance: 1000 };
withdraw(2000, account);

// Error: 잔고가 부족합니다.

이론적으로는 숫자, 문자열 같은 원시형 자료를 포함한 어떤 것이든 에러 객체(error object)로 사용할 수 있지만 내장 에러와의 호환을 위해 되도록 에러 객체에 name message 프로퍼티를 넣어주는 것을 권장한다.

 

 

finally

try / catch finally라는 코드 절을 하나 더 가질 수 있으며 다음과 같은 상황에서 실행된다.

  • 에러가 없는 경우: try 실행이 끝난 후
  • 에러가 있는 경우: catch 실행이 끝난 후

 

try {
   ... 코드를 실행 ...
} catch(e) {
   ... 에러 핸들링 ...
} finally {
   ... 항상 실행 ...
}

/*                              */

function errorException(isThrow) {
  try {
    console.log('자원을 할당하였습니다.');
    if (isThrow) throw new Error();
  } catch (error) {
    console.log('에러가 발생했습니다.');
  } finally {
    console.log('자원을 제거하였습니다.');
  }
}

errorException(false);
// 자원을 할당하였습니다.
// 자원을 제거하였습니다.
errorException(true);
// 자원을 할당하였습니다.
// 에러가 발생했습니다.
// 자원을 제거하였습니다.

 

 

 

 

클래스(Class)

 

클래스란 현실과 비슷한 개념(객체)을 나타내기 위한 도구이며 미리 정의해놓으면 필요할 때마다 해당 클래스로 동일한 틀을 가진 객체를 만들 수 있다. 여기서 동일한 클래스를 이용해 생성한 객체를 인스턴스(Instance)라고 부른다.

 

class User { 
}

const user = new User();
user.name = "이용우";
user.age = 28;
user.tech = "Node.js";

console.log(user.name); // 이용우
console.log(user.age); // 28
console.log(user.tech); // Node.js

 

여기서 변수 user는 실제 빵, User 클래스는 빵틀이라고 이해하면 쉽다.

 

생성자(Constructor)

 

클래스 내부에서 constructor()로 정의한 메서드를 "생성자"라고 부르며 미리 정의한 클래스를 기반으로 인스턴스를 생성할 때 Javascript 내부에서 호출되는 메서드이다.

 

class User {
  constructor(name, age, tech) { // User 클래스의 생성자
    this.name = name;
    this.age = age;
    this.tech = tech;
  }
}

const user = new User("이용우", 28, "Node.js"); // user 인스턴스 생성

console.log(user.name); // 이용우
console.log(user.age); // 28
console.log(user.tech); // Node.js

 

 

this

위에서 예시를 든 빵틀(User)과 빵(user)의 관계를 예로 한번 더 들자면 우리가 바꾸고 싶은 건 빵틀의 값이 아니라 실제 빵의 값이다. this 라고 표시함으로써, 빵틀 전체의 값을 바꾸는게 아니라 빵 하나의 값만 바꿀수 있다.

 

즉, 메서드 내부에서 this 키워드를 사용하면 객체에 접근할 수 있으며 자바스크립트에서 this는 모든 함수에서 사용할 수 있어 자유롭다.

 

생성자의 바디에서 this 키워드를 사용한다. 이 this는 클래스를 사용해 만들어 질 객체 자신을 의미하고 this 뒤에 붙는 name, age, tech는 클래스를 이용해서 만들어질 객체의 속성(Propety)이다.

 

class User {
  constructor(name, age, tech) { // User 클래스의 생성자
    this.name = name;
    this.age = age;
    this.tech = tech;
  }
}

const user = new User("이용우", "28", "Node.js"); // user 인스턴스 생성
console.log(user.name); // 이용우
console.log(user.age); // 28
console.log(user.tech); // Node.js

생성자를 이용해 name, age, tech인자값을 입력받아 class 내부변수에 저장한다.

 

 

 

 

메서드(Method)

자바스크립트에서 사용할 수 있는 모든 값은 프로퍼티 값으로 사용할 수 있으며 프로퍼티 값이 함수일 경우에는 일반 함수와 구분하기 위해 메서드(Method)라고 부른다.

 

즉, 메서드는 객체(Object) 에 묶여 있는 함수를 의미한다.

 

클래스에서도 데이터를 나타내는 속성뿐만아니라 함수와 같이 특정 코드를 실행할 수 있는 문법을 사용할 수 있는데, 여기서는 Class라는 객체(Object)에 묶여있는 함수를 메서드(Method)라고 부른다.

 

let user = {
  name: "John",
  age: 30
};

user.sayHi = function() {
  alert("안녕하세요!");
};

user.sayHi(); // 안녕하세요!

함수 표현식으로 함수를 만들고, 객체 프로퍼티 user.sayHi에 함수를 할당해 주었다. 이제 객체에 할당된 함수를 호출하면 user가 인사를 해준다. 이렇게 객체 프로퍼티에 할당된 함수를 메서드(method) 라고 부르며 위 예시에선 user에 할당된 sayHi가 메서드이다.

 

또한 아래와 같이 이미 정의된 함수를 이용해서 만들 수도 있다.

 

let user = {
  // ...
};

// 함수 선언
function sayHi() {
  alert("안녕하세요!");
};

// 선언된 함수를 메서드로 등록
user.sayHi = sayHi;

user.sayHi(); // 안녕하세요!

 

또한 객체 리터럴 안에서 메서드를 선언할 때 단축문법을 이용할 수 있다.

 

user = {
  sayHi: function() {
    alert("Hello");
  }
};

// 위아래 두 객체는 동일하게 동작한다.
// 단축 구문을 사용하니 더 깔끔해 보이네요.

user = {
  sayHi() { // "sayHi: function()"과 동일합니다.
    alert("Hello");
  }
};

일반적인 방법과 단축 구문을 사용한 방법이 완전히 동일하진 않지만 객체 상속과 관련된 미묘한 차이가 존재하지만 지금은 이 차이가 중요하지않기에 넘어가겠다.

 

 

 

 

 

 

클래스 상속

 

일반적으로 클래스의 인스턴스는 선언한 클래스의 기능을 모두 상속하며 상속을 이용해 부모 클래스자식 클래스로 나뉠 수 있다.

부모 클래스의 경우 메서드, 내부 변수와 같은 정보를 자식 클래스에게 할당해줄 수 있다.

 

 

class Animal {
  constructor(name) {
    this.speed = 0;
    this.name = name;
  }
  run(speed) {
    this.speed = speed;
    alert(`${this.name} 은/는 속도 ${this.speed}로 달립니다.`);
  }
  stop() {
    this.speed = 0;
    alert(`${this.name} 이/가 멈췄습니다.`);
  }
}

let animal = new Animal("동물");

 

객체 animal과 클래스 Animal의 관계를 그림으로 나타내면 다음과 같다.

 

class User { // User 부모 클래스
  constructor(name, age, tech) { // 부모 클래스 생성자
    this.name = name;
    this.age = age;
    this.tech = tech;
  }
  getTech(){ return this.tech; } // 부모 클래스 getTech 메서드
}

class Employee extends User{ // Employee 자식 클래스
  constructor(name, age, tech) { // 자식 클래스 생성자
    super(name, age, tech);
  }
}

const employee = new Employee("이용우", "28", "Node.js");
console.log(employee.name); // 이용우
console.log(employee.age); // 28
console.log(employee.getTech()); // 부모 클래스의 getTech 메서드 호출: Node.js

 

❓ super 키워드는 무엇인가요?

 

super 키워드는 함수처럼 호출할 수도 있고, this와 같이 식별자처럼 참조할 수 있는 키워드이다.

super 키워드를 호출하면 부모 클래스생성자(constructor)를 호출한다.

super 키워드를 참조하면 부모 클래스메서드(Method)를 호출할 수 있다.

'TIL' 카테고리의 다른 글

Express.js  (0) 2022.11.26
HTTP / Web Server  (0) 2022.11.26
동기(Sync) & 비동기(Async) & Promise  (0) 2022.11.25
Node.js  (0) 2022.11.25
11일차 - Application Programming Interface (API)  (0) 2022.11.20