상세 컨텐츠

본문 제목

[자바스크립트] 섹션 5. 객체와 클래스

[SW]/[JavaScript] 2025

by 시원00 2025. 1. 18. 14:46

본문

제대로 파는 자바스크립트(JavaScript) - by 얄코

(https://www.inflearn.com/course/제대로-파는-자바스크립트/dashboard)

섹션 5. 객체와 클래스

5-1. 객체의 기본 사용법들

I. 객체 생성과 프로퍼티 접근

 

식별자 명명 규칙에 벗어나는 키 이름 사용 시

변수명 등으로 사용할 수 없는 이름의 키인 경우

 

표현식으로 키값 정의하기
대괄호 [] 사용

 

객체나 배열을 키값으로 사용 시

실제로 해당 객체나 배열의 내용이나 참조값이 키가 되는 것이 아님

객체는 '[object Object]'라는 값으로, 배열은 배열의 값을 문자열로 치환하여 들어감

   *객체는 내용이 다른 모든 객체로 접근 가능, 배열은 동일한 값의 문자열로 접근 가능

참조값을 키값으로 사용하려면 Map 이용

 

II. 프로퍼티 삭제: delete 연산자

 

III. 키의 동적 사용

 

IV. ES6 추가 문법

1. 객체 선언 시 프로퍼티 키와 대입할 상수/변수명이 동일할 시 단축 표현

 

2. 메서드 method: 객체에 축약표현으로 정의된 함수 프로퍼티

ES6부터는 2번째 표현으로 정의된 함수만 메서드라고 부름

일반 함수 프로퍼티와 특성이 다름


5-2. 생성자 함수

생성자 함수의 필요성

아래처럼 같은 형식의 객체들을 다수 만들어야 할 때 생성자 함수 사용

 

I. 생성자 함수로 객체 만들기

생성자 함수명은 일반적으로 대문자로 시작: 파스칼 케이스

생성자 함수로 만들어진 객체를 인스턴스 instance라 부름

this.~로 생성될 인스턴스의 프로퍼티들 정의

생성자 함수는 new 연산자와 함께 사용

암묵적으로 this 반환

생성자 함수에서는 메서드 정의 불가 (객체 리터럴과 클래스에서는 가능)

 

new를 붙이지 않으면 undefined 반환

호출 시 new를 붙이는가 여부에 따라 호출 원리가 다름

 

vs. 객체를 반환하는 함수

 

II. 생성자 함수로 만들어진 객체

1. 프로토타입 prototype: 자바스크립트 객체지향의 중심

타 언어의 클래스와는 다르며 사용하기에 더 강력함

introduce와 introEng은 종류가 다름 (인스턴스 vs. 프로토타입)

   *introEng는 Prototype에 들어가있음

 

2. 타 방식으로 만든 객체와의 차이

 

세 가지 방식 log 상세 비교

객체 자체의 로그도 상세가 다름 유의 (앞에 생성자 함수명이 붙음)

instanceof: 객체가 특정 생성자 함수에 의해 만들어졌는지 여부 반환

프로토타입의 constructor의 체인이 해당 생성자 함수 포함하는지 여부

   *콘솔에서 [[Prototype]] 펼쳐서 확인

 

3. 생성자 함수 자체의 프로퍼티와 함수

 

4. new 생략 실수 방지하기

해당 함수가 new 연산자 없이 호출되었을 경우 재귀호출을 통해 생성해 내보냄

클래스는 new가 없으면 오류가 발생하므로 필요없음


5-3. 클래스

I. 클래스 class를 사용하여 인스턴스 만들기

Syntactic Sugar - 문법을 보다 읽기 쉽게 만드는 것

자바 등 타 언어에 익숙한 사람들을 위해 생성자 함수, 프로토타입 기반인 자바스크립트 문법을 타 언어의 클래스와 비슷한 문법으로 포장

 

클래스와 생성자 함수의 동작이 동일하지는 않음

차이 1. 클래스는 호이스팅되지 않음

 

차이2. 클래스는 new 없이 사용하면 오류

생성자 함수는 오류 없이 undefined 반환

 

II. constructor 메서드

- 인스턴스 생성 시 인자를 받아 프로퍼티를 초기화함

- 클래스에 하나만 있을 수 있음 (초과 시 오류 발생)

- 다른 메서드 이름을 쓸 수 없음

- 기본값 사용 가능

- 필요없을 시 생략 가능 (인자가 없을 때 등)

- 값을 반환하지 말 것! (생성자 함수처럼 암묵적으로 this 반환)

 

III. 클래스의 메서드

생성자 함수에 넣은 함수와의 차이 (로그 확인)

   *클래스의 함수는 프로토타입으로 들어감

 

IV. 필드 field

constructor 밖에서 this.~없이 인스턴스의 프로퍼티 정의

 

V. 정적 static 필드와 메서드

 

인스턴스의 수와 관계없이 메모리 한 곳만 차지

인스턴스 없이 클래스 차원에서 호출
정적 메서드에서는 정적 필드만 사용 가능

 

클래스는 함수

typeof 시 function으로 구분

 

일급 객체, 다른 곳에 할당 가능


5-4. 접근자 프로퍼티와 은닉

I. 접근자 프로퍼티

getter, setter 함수라고도 부름

   getter

   - 반드시 값을 반환해야 함

   - 특정 프로퍼티(들)를 원하는 방식으로 가공하여 내보낼 때 사용

   setter

   - setter는 하나의 인자를 받음

   - 특정 프로퍼티에 값이 저장되는 방식을 조작하거나 제한하는데 사용

스스로는 값을 갖지 않음 (다른 프로퍼티의 값을 읽거나 저장할 때 사용)

get, set을 앞에 붙임

함수처럼 지정되었지만 프로퍼티처럼 사용

 

클래스에서도 사용 가능

클래스에서는 프로토타입이 됨 (콘솔에서 객체의 [[Prototype]] 확인)

 

필드 이름과 setter의 이름이 같을 때: 오류 발생

constructor도 setter 함수를 이용하여 할당하기 때문에 무한루프에 빠짐

 

해결책

setter와는 다른 필드명을 사용하여 자기반복호출을 방지

constructor의 no는 setter를 가리키고 실제 필드명은 _no가 됨

 

II. 은닉

캡슐화 encapsulation

객체지향의 주요 요소 중 하나: 객체 내부의 값은 감추는(은닉하는) 것

인스턴스의 프로퍼티 값을 함부로 열람하거나 수정하지 못하도록

자바스크립트의 필드는 기본적으로 public (은닉되지 않음)

 

private 필드를 통한 은닉

필드명 앞에 #을 붙임

클래스 바로 안쪽에 정의해야 함 (constructor에만 하면 안됨)

console.log(emp1.#name); 에서 오류 발생해야 하는데, 접근이 됨

(크롬 초기화 등 여러 방법 써봤는데 안 됨)

REPL 모드로 하니 에러 메시지가 정상적으로 뜸 (아래)

 

클래스 내에서는 private 필드에 접근 가능

constructor, 접근자 프로퍼티 또는 기타 함수에서 접근 가능

인스턴스에서 바로 접근은 못하도록 은닉 (아래 방법들로 제어)


5-5. 상속

상속 inheritance

서로 다른 클래스나 생성자 함수가 같은 속성들을 공유할 때 이들의 관계를 정의함으로써 코드의 중복을 줄이고 효율을 높임

 

I. 클래스의 상속 문법

 

클래스에서는 extends (부모클래스)로 상속관계 정의

자식 클래스에서 또 다른 클래스가 상속받을 수 있음

자식 클래스는 부모 클래스의 속성을 기본적으로 가져옴

자식 클래스의 인스턴스는 부모 클래스의 인스턴스로 인식됨

[[Prototype]]으로 상속관계 살펴보기 (최종적으로 Object)

 

II. 오버라이딩 overriding

자식 클래스에서 부모로부터 물려받은 속성이나 기능을 덮어씀

 

III. super

부모 클래스의 constructor 또는 메서드 호출

super는 다른 클래스에서 상속받은 클래스에서만 사용 가능

- 자식 클래스의 constructor 내에서는 부모 클래스의 constructor를 가리킴

- 자식 클래스의 메서드 내에서는 부모 클래스를 가리킴

부모 클래스의 constructor나 메서드에 추가적인 동작을 넣기 위해 사용

 

정적 메서드


5-6. 객체의 스프레드와 디스트럭쳐링

I. 스프레드 spread

1. 기본 문법

 

2. 특정 객체의 프로퍼티를 포함하는 다른 객체 생성에 유용

 

3. 중복되는 프로퍼티는 뒤의 것이 덮어씀

 

4. 복사의 깊이

해당 객체 바로 안쪽의 원시값은 복제하지만 참조값은 같은 값을 가리킴

원시값만 있는 객체만 값에 의한 복사: 얕은 복사

복합적인 객체의 완전한 깊은 복사는 이후 다룸

 

참조복사와 비교

 

II. 디스트럭쳐링 destructuring

1. 문법

기존 코드 vs. 디스트럭쳐링

 

일부만 가져오는 것도 가능

 

2. 활용

필요한 프로퍼티 값을 짧은 코드로 변수/상수에 담을 때

 

함수 인자값의 가독성을 위해 객체를 사용할 때


5-7. 중간점검 퀴즈

1. lunchMenu 객체에 대해 아래 사항들을 실행하세요.

vegan 이란 프로퍼티를 추가하고 false 를 값으로 넣으세요. 
price 를 500 증가시키세요. 
flavor 프로퍼티를 삭제하세요. 
name 프로터피를 두 가지 방식으로 출력해보세요.
const lunchMenu = {
   name: '떡볶이',
   price: 5000,
   flavor: 'hot'
}

예상 답:

   lunchMenu.vegan = false;
   lunchMenu.price += 500;
   delete lunchMenu.flavor;
   console.log(lunchMenu['name']);
   console.log(lunchMenu.name);

정답:  
    lunchMenu.vegan = false;
    lunchMenu.price += 500;
    delete lunchMenu.flavor
    
    console.log(
     lunchMenu.name,
     lunchMenu['name']
    );

 

2. 직사각형을 나타내는 객체를 만들어내는 Rectangle 생성자 함수를 작성하세요. 조건은 아래와 같습니다.

각 직사각형은 width 값과 height 값을 갖습니다. 
describe 함수는 ‘면적: (width * height)’ 형식의 문자열을 로그로 출력합니다.
// 활용예
myRect = new Rectangle(20, 30);
myRect.describe();

예상 답:

   const Rectangle = function(width, height) {
      this.width = width;
      this.height = height;

      this.describe = function() {
         console.log(`면적: ${this.width * this.height}`);
      }
   }

정답:

   function Rectangle (width, height) { //생성자 함수
       this.width = width;
       this.height = height;
       this.describe = function () {
           console.log(
               `면적: ${this.width * this.height}`
           );
       }
   }

 

3. 위 2번의 생성자 함수를 클래스로 작성해보세요. 정적 필드로 thickness를 추가한 뒤(기본값2) 이를 로그로 출력해보세요.

예상 답: 

   class Rectangle {
      thickness = 2; // 앞에 static 붙여야 함 (정적 필드)
    
      constructor(width, height) {
         this.width = width;
         this.height = height;
      }
    
      describe() {
         console.log(`면적: ${this.width * this.height}`);
      }
   }

정답:

    class Rectangle {
     static thickness = 2;
    
        constructor(width, height) {
            this.width = width;
            this.height = height;
        }
    
        describe() {
            console.log(`면적: ${this.width * this.height}`);
        }
    }
    
    console.log(Rectangle.thickness);

 

4. 위 코드의 width 와 height 필드들을 private 필드로 수정한 뒤 getter와 setter를 추가하세요. setter에서는 양수만 적용되도록 작성해보세요.예상 답:

    class Rectangle {
        #width;
        #height;
        
        constructor(width, height) {
            this.#width = width;
            this.#height = height;
        }
        
        describe() {
            console.log(`면적: ${this.width * this.height}`); // this.#width this.#height로 접근 (#)
        }
    
        get width() {
            return this.#width;
        }
        get height() {
            return this.#height;
        }
    
        set width(width) {
            if (width <= 0) return;
            else this.#width = width;
        }
        set height(height) {
            if (height <= 0) return;
            else this.#height = height;
        }
    }

정답:

    class Rectangle {
        #width;
        #height;
    
        constructor(width, height) {
            this.#width = width;
            this.#height = height;
        }
    
        get width() {
            return this.#width;
        }
    
        set width(newWidth) {
            if (newWidth > 0) this.#width = newWidth;
        }
    
        get height() {
            return this.#height;
        }
    
        set height(newHeight) {
            if (newHeight > 0) this.#height = newHeight;
        }
    
        describe() {
            console.log(`면적: ${this.#width * this.#height}`);
        }
    }

 

5. 상속 관계에 있는 Animal 과 Cat 클래스를 작성해보세요. Animal 은 sex 필드를, Cat 은 이에 더하여 breed 필드를 가지며, 사용방법과 메소드의 호출내용은 아래와 같습니다.

const myAnimal = new Animal('수컷');
myAnimal.describe(); // 성별: 수컷

const myCat = new Cat('암컷', '페르시안');
myCat.describe(); // 페르시안 (암컷)

예상 답:

    class Animal {
        constructor(sex) {
            this.sex = sex;
        }
        describe() {
            console.log(`성별: ${this.sex}`);
        }
    }
    class Cat extends Animal {
        constructor(sex, breed) {
            super(sex);
            this.breed = breed;
        }
        describe() {
            console.log(`${this.breed}(${this.sex})`);
        }
    }

정답:

    class Animal {
        constructor(sex) {
            this.sex = sex;
        }
    
        describe () {
            console.log(`성별: ${this.sex}`);
        }
    }
    
    class Cat extends Animal {
        constructor(sex, breed) {
            super(sex);
            this.breed = breed;
        }
    
        describe () {
            console.log(`${this.breed} (${this.sex})`);
        }
    }

 

 

FIN.

관련글 더보기

댓글 영역