코딩팍

 

자바스크립트는 아직까지는 좀 지저분한 언어라는 편견이 있다. 다른 언어와는 다르게 프레임워크 없이는 정리가 잘 안되 보이기 때문 일 수도 있다. 그래서 요즘에는 자바스크립트를 프레임워크와 함께 이용하는 경우가 더 흔하다. 하지만 자바스크립트 버전이 업데이트 될 수록 점점 더 정돈되고 있다. 

 

과연 자바스크립트로도 객체지향 프로그래밍 (Object-Oriented Programming)을 이용할 수 있을까?

 

물론이다!

 

객체지향 프로그래밍 (OOP)

객체지향 프로그래밍은 오브젝트/객체의 컨셉을 이용해서 코드를 쓰는 패러다임이다 (코드를 쓰는 스타일). 객체는 데이타와 함수를 가지고있다. 객체는 앱을 만드는 조각이고 API를 통해서 상호작용한다. 궁극적으로 유지하기 쉬운 정돈된 코드를 쓰는데 도움이 된다. 객체지향 프로그래밍은 아래와 같은 4가지 특성이 있다:

  • 추상화 (Abstraction): 알 필요 없는 상세한 코드의 내용은 숨긴다. 클래스의 더 큰 틀을 볼 수 있게 도와줌.

  • 캡슐화 (Encapsulation): 변수와 함수를 클래스 밖에서 접근할 수 없게 한다. 바깥 코드가 내부 속성을 실수로 바꾸는것을 방지

  • 상속 (Inheritance): 공통되는 코드를 재사용

  • 다형성 (Polymorphism): 자식 클래스가 부모 클래스에서 물려받은 함수를 바꿔 쓸 수 있다.

 

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

자바스크립트의 가장 큰 특성은 프로토타입 상속이다. 모든 객체들이 프로토타입과 연결되어있고 프로토타입에 있는 함수를 이용할 수 있다. 

 

자바스크립트에서 프로토타입 상속을 이용하는 방법은 크게 3가지가 있다:

  1. 생성자 함수 (Constructor Function): 객체를 함수에서 만드는 방법.
  2. ES6 클래스: 위의 방법과 같지만 ES6에서 소개된 새로운 syntax

 

생성자 함수 (Constructor Function)

객체를 만들 때 'new' 키워드를 이용한다.

const Phone = function(maker, model) {
	this.maker = maker;
    this.model = model;
}

const iPhoneXR = new Phone('Apple', 'XR');

이렇게 만들어진 객체는 모두 새로만든 프로토타입에 연결되어있다. 프로토타입에 함수를 만들려면 다음과 같이 만든다. 

Phone.prototype.printMaker = function() {
	console.log(this.maker);
}

iPhoneXR.printMaker();

연결된 프로토타입을 체크해보자:

console.log(iphoneXR.__proto__);
console.log(iphoneXR.__proto__ === Phone.prototype); //true
console.log(Phone.prototype.isPrototypeOf(iphoneXR)); //true

그리고 이 클래스에 새로운 속성을 더해보자:

Phone.prototype.electronic = true;
console.log(iphoneXR.species); // 상속받은 속성

console.log(iphoneXR.hasOwnProperty('maker')); // true
console.log(iphoneXR.hasOwnProperty('electronic')); // false

하지만 이런식으로 프로토타입에 속성을 더하는 것은 좋은 방법이 아니다.

  1. 자바스크립트가 언제 똑같은 속성/함수를 같은 프로토타입에 추가할지 모른다.
  2. 다른 개발자와 일할 때 헷갈리거나 버그를 만들 수 있다.

 

ES6 클래스

클래스를 만드는 좀더 나은, 현대적인 방법이 ES6부터 소개되었다!

이젠 수동으로 프로토타입과 씨름하지 않아도 된다.

class PhoneCL {
	constructor(maker, model) {
    	this.maker = maker;
        this.model = model;
    }
    
    printMaker() {
    	console.log(this.maker);
    }
}

const note10 = new PhoneCL('Samsung', 'note10');
note10.printMaker();

console.log(note10.__proto__ === PhoneCL.prototype);

클래스 안에서 만든 함수는 모두 프로토타입에 링크된다.

 

ES6 클래스에 대해 알아야 할점:

  1. 클래스는 호이스트 되있지 않다 => 선언되기 전에 사용 불가
  2. 클래스는 1급 객체이다 => 함수로 리턴할 수 있다
  3. 클래스는 엄격모드 (strict mode)를 사용한다 

 

정적함수 만들기 (Static Methods)

정적함수는 프로토타입에 연결되지 않아서 상속되지 않는다.

실제 객체에 연관없는 함수를 만들기 위해서 사용된다.

class Phone {
	static test() {
    	console.log('test static');
    }
}

 

클래스 상속

생성자 함수

const Phone = function(maker, model) {
	this.maker = maker;
    this.model = model;
}

Phone.prototype.printMaker() = function() {
	console.log(this.maker);
}

// 자식 클래스 만들기
const Galaxy = function(maker, model, year) {
	Phone.call(this, maker, model);
    this.year = year;
};

const note = new Galaxy('Samsung', '20 Ultra', 2020);

// 상속하기
Galaxy.prototype = Object.create(Phone.prototype);

// 주의점: Galaxy.__proto__ = Phone.prototype 는 안됨

// 새로운 함수 만들기
Galaxy.prototype.phoneModelYear = function() {
	console.log(this.model, this.year);
}

note.phoneModelyear(); //사용가능

console.log(note instanceof Galaxy); // true
console.log(note instanceof Phone); // true
console.log(note instanceof Object); // true

 

클래스 상속은 Object.create()를 이용해서 한다

 

ES6 클래스

class PhoneCL {
	constructor(maker, model) {
    	this.maker = maker;
        this.model = model;
    }
    
    printMaker() {
    	console.log(this.maker);
    }
}

class StudentCl extends PersonCl {
	constructor(maker, model, year) {
    	super(maker, model); // 부모 클래스의 생성자 함수를 부름
        this.year = year
    }
    
    phoneModelYear() {
    	console.log(this.model, year);
    }
    
    // 다형성, 함수 내용을 바꿀수 있음
    printMaker() {
    	console.log(`Maker is ${this.maker}`);
    }
}

const note = new StudentCl('Samsung', 'note20', 2020);
note.printMaker();
note.phoneModelYear();

 

ES6 클래스 상속은 extends를 이용한다.

 

캡슐화: private 변수

  • 클래스 밖에서의 코드가 클래스 내부 속성과 상호작용하는 것을 방지
  • 작은 인터페이스를 통해서 코드가 무너지는것을 확인

자바스크립트는 아직 private 키워드가 없다. 그래서 접두어 를 붙이는 규칙이 있다.

// 접두어 _를 붙이는 규칙
// 실제로 접근을 방지하지는 않음
this._servers = [];
this._pw = pw;

_changeUserId() {
	return true;
}

 

이 글을 공유합시다

facebook twitter googleplus kakaoTalk kakaostory naver band