티스토리 뷰

반응형

부제: 프로토타입 체이닝. JavaScript 객체지향 패턴.


 이번 포스팅은 JavaScript의 prototype에 대해 다루는 글이다. 이미 이전 포스팅들에서 prototype에 대해 어느정도 다루었다. 프로토타입에는 두가지 의미가 있으며, 이를 명확하게 숙지하는 것이 중요하므로 다시 한 번 짚고 넘어가려고 한다.





1. JavaScript의 모든 객체는 '__proto__' 라는 숨겨진 프로퍼티를 갖고 있다. __proto__는 자신의 부모인 프로토타입 객체를 가리킨다. 이러한 링크를 'prototype Link'라고 부른다.


2. JavaScript의 모든 함수는 'prototype' 라는 숨겨진 프로퍼티를 갖고 있다. prototype은 자신에 new 키워드를 붙여 생성한 객체의 부모를 가리킨다.


 이해가 잘 안되면 여기를 참고하자.



1. 프로토타입 체이닝

 JavaScript에는 Java와 같은 언어와 달리 JavaScript에는 Class 개념이 없다. 그래서 JavaScript는 프로토타입 기반의 객체지향 프로그래밍을 지원한다. 자신의 부모 객체를 가리키는 prototype Link를 활용하여 객체지향 프로그래밍을 할 수 있다. 다음 예제를 보자.


function Student (name, age, email) {
    this.name = name;
    this.age = age;
    this.email = email;
}

var preamtree = new Student('preamtree', 20, 'preamtree@tistory.com');

console.log(preamtree.hasOwnProperty('name')); // 출력결과: true


 hasOwnProperty()라는 메소드는 Object.prototype에 속한 메소드다. 그리고 예제에서 이 메소드가 정상적으로 호출이 되었다. 이 상황을 그림으로 나타내면 다음과 같다.


 prototype Link를 타고 올라가며 Object.prototype에도 접근이 가능함을 알 수 있다. 이를 프로토타입 체이닝이라고 한다. 그리고 프로토타입 체이닝의 종점은 Object.prototype 객체다. 



2. 프로토타입을 활용한 OOP 구현

 앞서 JavaScript는 클래스의 개념이 없다고 했다. 그렇지만 JavaScript의 new 키워드와 이를 활용하여 객체를 생성하는 방식(생성자 함수를 활용하는 방식)은 어쩐지 JAVA와 같은 객체지향 언어와 비슷한 느낌이 든다! 다음 예제를 느긋하게 보자.


function Student(name, age) {
    this.name = name;
    
    this.getName = function() {
        return this.name;
    }
    
    this.setName = function(name) {
        this.name = name;
    }
}

var preamtree = new Student(name);


 JAVA에서 정말정말 많이쓰이는 자바빈(Java Bean)패턴과 꽤 유사한 것 같다! JavaScript에서도 위와 같은 방식으로 객체를 생성할 수 있다. 다만 위와 같은 방식은 객체를 만들 때마다 getter 메소드와 setter메소드가 객체 내부에 각각 할당된다. 


function Student(name, age) {
    this.name = name;
}
Student.prototype.getName = function() {
    return this.name;
}

Student.prototype.setName = function(name) {
    this.name = name;
}
var preamtree = new Student(name);


 메모리 절약을 위해서 위와 같이 개선해봤다. 프로토타입도 객체도 결국에는 '객체'니까 그곳에 getter및 setter 메소드를 할당했다. 이렇게 하면 프로토타입 체이닝을 통해 getter와 setter에 접근할 수 있다. 보너스로 이와 같이 OOP의 클래스 및 생성자, 메소드 구현에 대해 더글라스 크락포드가 제안한 패턴을 소개한다.


//
//prototype에 프로퍼티를 추가하는 함수
Function.prototype.method = function(name, func) {
    if(!this.prototype[name]) {
        this.prototype[name] = func;
    }
}

function Student(name, age) {
    this.name = name;
}

// prototype에 프로퍼티를 추가할 때마다 '.prototype'을 반복할 필요가 없음.
Person.method('getName', = function() {
    return this.name;
});

Person.method('setName', function(name) {
    this.name = name;
});



3. 상속

 어느정도 예측(?)했겠지만 JavaScript는 상속을 제공하지 않는다. 하지만 프로토타입 체이닝을 활용하여 상속을 구현할 수 있다. 먼저 Object.create()를 활용하는 방식이다. 그냥 쓰면 된다 매우 간단하다. Object.create()는 내부적으로 다음과 같이 구현되어 있다.



function create(o) {
    function F() {};
    F.prototype = o;
    return new F(); // o를 부모로하는 객체 리턴
}


 다른 방법으로 extends 키워드를 이용하는 방법이 있다. 계속해서 JavaScript에는 class가 없다는 것을 강조했지만, 사실 ECMAScript 6부터 함수의 형태로 class 키워드를 제공한다. 또한 extends도 제공한다. (한층 더 객체지향언어스러워진(?) 모습이다.) 자세한 내용은 아래 링크를 확인하자.


https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes#Class_%EC%A0%95%EC%9D%98



4. 캡슐화(정보은닉)

 JAVA와 같은 언어에서는 private, protected 등의 접근 지정자를 활용하여 정보은닉을 구현할 수 있다. 하지만 JavaScript에서는 이러한 키워드를 지원하지 않는다. 그래도 보통 클로저를 활용하여 캡슐화를 구현한다.


 var Student = function(input) {
     var name = input ? input : 'preamtree';
     
     return {
         getName : function(){
             return name;
         },
         setName : function(input) {
             name = input;
         }
     };
 };

var foo = new Student();
console.log(foo.name);      //  출력결과: undefined
console.log(foo.getName()); //  출력결과: preatree


  위 함수의 멤버 변수를 this 키워드를 사용하지 않고, var로 선언했기 때문에 외부에서 정상적으로 접근할 수 없는 모습이다. 그러나 getName, SetName이라는 클로저를 통해 name에 접근할 수 있다.


 다만, 클로저를 통해 객체나 배열을 반환할 경우 얕은 복사로 인한 참조가 반환됨에 유의해야한다. (Call-By-Reference. 이해가 안되면 여기 참조) 이 참조를 통해서 객체 밖에서도 멤버 변수의 값을 바꿀 수 있기 때문이다. 그래서 객체나 배열을 반환할 경우에는 깊은복사를 활용하여 구현해야한다. 



깊은 복사에 대한 자세한 내용은 아래 링크를 확인하자.

https://hyunseob.github.io/2016/02/08/copy-object-in-javascript/


 



-끝-




출처 및 참고

송형주, 고현준, 『인사이드 자바스크립트』, 한빛미디어(2016)

http://visualize.tistory.com/435

http://www.nextree.co.kr/p7323/




«   2022/05   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
글 보관함
Total
800,128
Today
22
Yesterday
127