자바스크립트와 객체 지향 프로그래밍

    반응형

    객체 지향 프로그래밍

     

    자바스크립트를 공부하다 보면 "자바스크립트는 객체지향 언어이다" 혹은 "객체는 자바스크립트의 모든 것이다"라는 이런 내용이나 문구를 많이 보게 된다. 대체 객체지향 프로그래밍이 무엇이고 왜 객체지향 프로그래밍이라고 하는지 알아보고 자바스크립트에 대한 이해도를 더 높일 수 있도록 정리하려고 한다.

     

    객제치향 프로그래밍


    객체 지향 프로그래밍(Object-Oriented Programming)은 프로그래밍의 하나의 방법론으로 객체라는 기본 단위로 나누어 이들이 서로 상호작용을 통해 프로그래밍 하는 방식이다. 이때 객체는 관련이 있는 데이터, 함수, 변수 등을 하나의 단위 즉 객체로 묶는 것을 의미하는데 이 객체지향 프로그래밍에는 캡슐화, 상속, 다형성 등 다양한 특징을 가지고 있다. 객체지향의 반대의 의미를 가진 절차 지향 프로그래밍이 있는데 절차 지향은 말 그대로 절차대로 순차적이라고 생각하면 된다. 다만 프로젝트의 규모나 복잡도가 증가하면서 유지 보수가 어렵고, 현실 세계의 개체들을 추상화하는 과정에서 모델링 하기 어렵다는 단점과 더불어 여러 문제들이 발생했다. 그러한 상황에서 객체지향 프로그래밍은 새로운 패러다임으로 등장했다.

     

    객체지향 프로그래밍의 특징


    객체지향 프로그래밍의 특징으로 많은 부분을 찾아볼 수 있지만 여기서는 대표적인 몇 가지를 확인하려고 한다. class, 상속, 캡슐화, 다형성, 생성자 등 다양한 특징이 있다.

     

     

    1. 클래스

    자바스크립트는 ES5이전에 클래스 문법이 등장하지 않았다. 클래스를 통해 객체의 형태와 기능을 정의하고 생성자를 통해 인스턴스를 만들어서 사용할 수 있는 문법인 클래스 문법은 ES6 부터 등장했고 이 문법을 통해 좀 더 명확한 객체지향 문법을 제공할 수 있는 틀을 다졌다.

    function Person(name) {
        this.name = name;
    }
    
    Person.prototype.sayHello = function() {
        console.log("안녕하세요, " + this.name + "입니다.");
    };
    
    var person = new Person("홍길동");
    person.sayHello(); // 안녕하세요, 홍길동입니다.

     

    ES5 이전에는 클래스 문법이 존재하지 않았기 때문에 생성자 함수와 프로토타입을 통해 객체지향 프로그래밍을 구현했다. 하지만 이러한 방식은 자바스크립트의 함수는 일반함수로 혹은 생성자 함수로도 사용될 수 있다라는 특징과 this 바인딩에 차이가 발생하는 문제가 있었다. 그래서 생성자 함수를 통해 생성할 때는 첫글자를 대문자로 표기하는 것이 널리 알려진 컨벤션이다. 

     

    class Person {
        constructor(name) {
            this.name = name;
        }
    
        sayHello() {
            console.log(`안녕하세요, ${this.name}입니다.`);
        }
    }
    
    let person = new Person("홍길동");
    person.sayHello(); // 안녕하세요, 홍길동입니다.

     

    ES6부터 클래스 문법이 등장하면서 좀 더 명확하게 객체를 생성할 수 있고 생성자, 메서드, 상속등을 클래스 기반으로 쉽게 구현할 수 있게 되었다. 

     

    2. 상속

    자바스크립트의 클래스 문법이 등장하면서 extends 키워드를 통해 클래스를 상속받을 수 있다. 부모 클래스로부터 자식클래스가 특성, 기능을 물려받는 것을 말하는데 이러한 상속은 클래스의 재사용성을 높여준다.

    class Animal {
        constructor(name) {
            this.name = name;
        }
    
        speak() {
            console.log(this.name + "이(가) 소리를 냅니다.");
        }
    }
    
    class Dog extends Animal {
        speak() {
            console.log(this.name + "이(가) 멍멍 짖습니다.");
        }
    }
    
    let dog = new Dog("뽀삐");
    dog.speak(); // 출력: 뽀삐이(가) 멍멍 짖습니다.

     

    위 코드에서는 Animal이라는 클래스를 가진 부모 클래스에서 Dog이라는 자식 클래스로 특성과 기능을 그대로 물려받으면서 speak( )라는 특정 메서드만 다시 정의해서 사용하는 오버라이딩(overriding)까지 적용된 코드라고 볼 수 있다. 또한 instanceof를 통해 특정 객체가 어떤 클래스의 인스턴스인지 확인할 수 있다.

     

     

    instanceof 를 활용한 결과

     

     

    3. 캡슐화 

    캡슐화는 데이터와 데이터를 조작하는 메서드를 하나로 묶고 외부에서 접근하는 것을 제어하는 것을 말한다. 아래의 코드에서 let balance = initialBalance는 private 변수로 직접적인 접근이 불가능하고 메서드를 통해서만 조회나 변경이 가능한 것을 확인할 수 있다. 직접적인 데이터의 접근을 제한하면서 생각지 못한 데이터의 변형을 막을 수 있다.

    class BankAccount {
        constructor(initialBalance) {
            let balance = initialBalance;  // private 변수
    
            this.getBalance = function() {
                return balance;
            };
    
            this.deposit = function(amount) {
                if (amount > 0) {
                    balance += amount;
                    return true;
                }
                return false;
            };
    
            this.withdraw = function(amount) {
                if (amount > 0 && balance >= amount) {
                    balance -= amount;
                    return true;
                }
                return false;
            };
        }
    }
    
    const account = new BankAccount(1000);
    console.log(account.getBalance());  // 1000
    account.deposit(500);
    console.log(account.getBalance());  // 1500
    account.withdraw(200);
    console.log(account.getBalance());  // 1300
    
    console.log(account.balance);  // undefined (직접 접근 불가)

     

     

     

    4. 추상화

    필요한 부분 즉 중요한 부분만 드러내고 그 외에 부분들은 숨기는 것이라고 생각하면 조금 이해가 쉬울 거라고 생각한다.

    // Box 클래스 정의
    class Box {
        constructor(width, height, depth) {
            this.width = width;  
            this.height = height; 
            this.depth = depth;   
        }
    
        // 상자의 부피를 계산하는 메서드
        getVolume() {
            return this.width * this.height * this.depth;
        }
    }
    
    
    const myBox = new Box(10, 5, 3);
    
    
    console.log(`상자의 부피는 ${myBox.getVolume()}입니다.`);

     

    어떤 좋은 블로그 글을 봤는데 이해가 되는 내용을 작성해 주셔서 그 부분을 코드로 만들어봤다. 우리가 어떤 박스의 크기를 구하려고 할 때 박스의 가로, 세로, 높이 만 필요하다, 박스가 어떤 브랜드인지, 어떤 무늬를 가지고 있는지, 종이상자인지, 플라스틱 상자인지는 전혀 중요하지 않다. 꼭 필요한 속성들만 모아놓은 것을 추상화라고 이해하면 쉽게 이해할 수 있을 거라고 생각한다.

     

    기존에 객체지향 프로그래밍의 방식은 생성자 함수와 프로토타입을 통해 객체지향 프로그래밍을 수행했지만 ES6 이후에 등장한 클래스 문법으로 더욱 객체지향 프로그래밍 언어에 가까워지게 되었다. 또한 자바스크립트는 프로토타입을 통해 클래스 없이도 메서드와 상속을 구현할 수 있고 동적으로 추가. 변경이 가능하다. 그렇기 다른 객체 지향언어들과는 조금 다르다고 할 수 있지만 그만큼 유연하다고 볼 수 있을 것 같다. 

     

    반응형

    댓글