객체 리터럴
객체
자바스크립트엔 여덟 가지 자료형이 있으며 이 중 일곱 개는 오직 하나의 데이터(문자열, 숫자 등)만 담을 수 있어 '원시형,기본형(primitive type)'이라 부른다. 그런데 객체형은 원시형과 달리 다양한 데이터를 담을 수 있으며 키로 구분된 데이터 집합이나 복잡한 개체(entity)를 저장할 수 있다.
- 원시 타입은 단 하나의 값만을 나타내고, 원시 타입의 값은 변경이 불가능 한 값입니다.
- 객체 타입은 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료 구조이고, 객체 타입의 값을 변경 가능한 값입니다.
Javascript는 객체(Object) 기반의 프로그래밍 언어이고, Javascript를 구성하는 거의 모든 것은 객체로 구성되어 있으므로 객체(Object) 는 0개 이상의 프로퍼티로 구성된 집합이며, 하나의 프로퍼티는 Key와 Value로 구성되어 있다. 그러므로 자바스크립트를 잘 다루려면 객체를 잘 이해해야한다.
객체는 중괄호 {…}를 이용해 만들 수 있으며 중괄호 안에는 ‘키(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에는 프로퍼티가 두 개 있다.
- 첫 번째 프로퍼티 – "name"(이름)과 "John"(값)
- 두 번째 프로퍼티 – "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 동작 알고리즘은 다음과 같다.

- 먼저, try {...} 안의 코드가 실행된다.
- 에러가 없다면, try 안의 마지막 줄까지 실행되고, catch 블록은 건너뛴다.
- 에러가 있다면, 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 |