🔥 학습목표
- 클로저 모듈 패턴에 대해 설명할 수 있다.
- 클래스와 인스턴스에 대해 설명할 수 있다.
- 자바스크립트 DeepDive 25장을 학습한다.
- '한 번 읽으면 두 번 깨닫는 객체지향 프로그래밍'을 복습한다.
(IIEE, Immediately Invoked Function Expression)
함수 정의와 동시에 즉시 호출되는 함수. 단 한 번만 호출되며 다시 호출할 수 없다.
(function () {
let a = 3;
let b = 6;
return a * b;
}());
네임 스페이스란?
└▷ 구분이 가능하도록 정해놓은 범위나 영역.
==▶ 객체나 변수가 겹치지 않는 안전한 소스코드를 만들자는 개념으로 사용 된다.
전역 범위에 다양한 함수, 객체, 변수들로 어지럽히지 않고, 단 하나의 전역 객체를 만든 뒤 모든 기능을 이 객체에 추가하는 패턴이다.
(더 자세한 네임스페이스 패턴의 종류는 후에 학습한다.)
아래 코드에는 생성자 함수 2개, 변수 1개, 객체 1개,
총 4 개의 전역변수가 존재한다.
function parent() {}
function child() {}
var var1 = 1;
var object = {
data: { a:1, b:2 },
// ...
};
이를 전역 객체에 넣어 네임 스페이스 패턴을 사용하면 다음과 같이 바뀐다.
var MyApp = {};
// constructor
MyApp.parent = function() {};
MyApp.child = function() {};
// 변수
MyApp.var1 = 1;
// 객체
MyApp.object = {
//...
};
(코드의 가독성을 위해 객체 이름은 모두 대문자로 쓴다.)
private
: 외부에서 접근 불가능한 변수. 접근 메소드를 따로 정의해줘야 한다.public
: 외부에서 접근 가능한 변수.
의존 관계란?
하나의 객체가 다르 객체에게 의존성을 제공하는 것. 부모, 자식과 같다.
ex) A 객체에서 B 객체의 기능을 필요로 하는 경우 의존 관계다.
예를들면, dom
은 지역이고 window.document
는 전역이다. dom
은 window.document
에 의존한다.
var dom = window.document;
var loc = window.location;
< 의존 관계를 선언해야 하는 이유 >
dom
과 같은 지역 변수는 window.document
전역변수에 계속 접근하는 것보다 훨씬 빠르다. 되도록 전역 객체 판별은 한 번만 하는 게 좋다.함수와 그 함수가 접근할 수 있는 변수의 조합
[S1U9] 에서 보았 듯이 클로저란
이미 실행 종료 된 함수의 "변수나 함수를 참조"할 수 있는 내부 함수를 뜻한다.
이러한 참조 범위, <스코프>를 활용해서 변수의 접근 범위를 닫을 수 있는 게 클로저의 핵심 기능이다.
위에서 설명한 네 가지 패턴을 조합한 게 모듈 패턴이다.
- 네임 스페이스 패턴
- 즉시 실행 함수
- private / public 멤버
- 의존 관계 선언
└▶ 오직 내부 함수에서만 접근 가능한 클로져의 특성을 이용해 이러한 모듈 패턴을 구현하 것이다.
예를 들어, 아래와 같이 exercise
라는 객체가 있다.
let exercise1 = {
minute: 0,
increseMin: function() {
this.minute += 30;
},
getMinute: function(){
return this.minute;
}
}
exercise1.increaseMin();
exercise1.increaseCal();
만약 운동 한 종류를 했을 때 위와 같이 객체의 값을 조정할 수 있다.
하지만 다양한 운동을 하게 됐을 땐 어떡할까?
exercise1
객체는 자기자신 단 하나의 객체일 뿐이다.
따라서 똑같이 시간을 기록해야하는 다른 운동을 해야할 경우, 같은 내용의 또다른 객체를 하나 더 만들어야 한다.
즉 재사용성이 떨어진다.
이러한 단점을 보완하려면 클로저를 사용해 매번 같은 내용의 새로운 객체를 만들도록 해야 한다.
function doExercise() {
let minute: 0;
return {
increseMin: function() {
minute += 30;
},
getMinute: function(){
return minute;
}
}
}
let running = doExercise();
running.increaseMin();
running.getMinute(); // 30
let personalTraining = doExercise();
personalTraining.increaseMin();
personalTraining.increaseMin();
personalTraining.getMinute(); // 60
이렇게 "운동" 이라는 똑같은 기능을 하는 running
과 personalTraining
을 따로 생성하여 분리할 수 있는 것이다.
'한 번 읽으면 두 번 깨닫는 객체지향 프로그래밍' 도서 참고
즉, 클래스란 코드로 작성한 설계도이며, 클래스 코드를 바탕으로 실제로 생성해 메모리에 올라가면 객체가 된다.
클래스 = 추상적
객체화 = 객체 = 구체적
이라고 볼 수 있다.
상태 데이터(프로퍼티)와 동작(메서드)를 하나의 논리적인 단위로 묶은 복합적인 자료구조
독립적인 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임
자바스크립트는 프로토타입 기반(prototype based) 객체지향 언어다.
프로토타입 객체 지향 언어란?
└▶ 클래스가 필요 없는(class free) 객체지향 프로그래밍 언어다.
이렇게 함수로 정의할 수 있다.
var Person = (Function () { // 즉시 실행 함수(함수 객체 생성을 위해)
// 생성자 함수
function Person(name) {
this.name = name;
}
// 프로토타입 메서드
Person.prototype.sayHi = function() {
console.log('bla bla');
};
// 생성자 함수 반환
return Person;
}());
// 인스턴스 생성
var me = new Person('Lee');
me.sayHi();
그러나 이러한 프로토타입 기반 프로그래밍 방식은
기존 클래스 기반 언어에 익숙한 프로그래머들에게 혼란을 가져다 주었다.
따라서,
ES6에서 도입된 클래스는 클래스 기반 객채지향 프로그래밍 언어와 매우 흡사한 새로운 객체 생성 매커니즘을 제시한다.
class Person {
// 생성자 함수 (인스턴스 생성 및 초기화)
constructor(name) {
this.name = name;
}
// 프로토타입 메서드
sayHi() {
console.log();
};
// 정적 메서드(인스턴스를 생성하지 않아도 호출할 수 있는 메서드)
static sayHello(){
console.log();
}
}
// 인스턴스 생성
const me = new Person('Lee');
me.sayHi();
그러나 사실 클래스는 함수이며 기존 프로토타입 기반 패턴을 클래스 기반 패턴처럼 사용할 수 있도록 만들었을 뿐이다.
prototype
: 원형 객체(original form). 인스턴스들의 원본 같은 것.constructor
: 인스턴스가 초기화 될 때 실행하는 생성자 함수this
: 함수가 실행될 때 해당 scope 마다 생성되는 고유한 실행 context. new 키워드로 인스턴스를 생성하면 해당 인스턴스가 바로 this의 값이 된다.function Car(brand, name, color) {
// 인스턴스가 만들어질 때 실행되는 코드
}
class Car {
constructor(brand, name, color){
// 인스턴스가 만들어질 때 실행되는 코드
}
}
let avante = new Car('hyundai', 'avante', 'black');
각각의 인스턴스는 Car라는 클래스의 고유한 속성과 메소드를 갖는다.
function Car(brand, name, color) {
this.brand = brand;
this.name = name;
this.color = color;
}
class Car {
constructor(brand, name, color){
this.brand = brand;
this.name = name;
this.color = color;
}
}
function Car(brand, name, color) { /*생략*/ }
Car.prototype.fefuel = function() {
// 연료 공급을 구현하는 코드
}
class Car {
constructor(brand, name, color){ /*생략*/ }
refuel() {
// 마찬가지
}
}
인스턴스에서의 사용법은 ES5와 ES6가 똑같다.
let mini = newCar('bmw', 'mini', 'white');
mini.brand; // 'bmw'
mini.refuel(); // 연료를 공급한다.