본문 바로가기

[OOP] JavaScript 객체 지향 프로그래밍 - 13. object inheritance, _proto_, Object.create(), 객체상속의 사용

 

 

들어가며

어느 정도 개발에 대한 감을 익혔다고 생각했습니다. 코드를 순서에 맞게 작성하는 능력들을 아주 조금이지만 쌓아 올릴 수 있었습니다. 하지만 시간이 지나면서 제 코드를 봤을 때 너무 더럽다고 느껴졌습니다. 중복되는 코드가 많았고, 비효율적인 코드들도 많이 볼 수 있었습니다. 코드를 조금 더 재사용성이 높게 작성한다면 더 효율적으로 시스템이 동작할 수 있었을 텐데, 아쉬움이 남았습니다. 이런 고민을 하면서 객체지향 프로그래밍에 대해 배워야겠다고 생각했습니다. 앞으로 객체지향을 배우면서 공부하고 느낀 점들을 정리해나가고자 합니다. 아래 내용은 생활코딩의 OOP 수업을 듣고 정리한 내용입니다.

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

object inheritance

주류 객체지향 언어에서 상속을 다룰 땐, sub class가 super class의 기능을 물려받기 위해서는 sub class가 super class의 자식이 되어야 합니다. 그리고 그렇게 만들어진 sub class를 통해 객체를 생성합니다. 그렇기 때문에 객체가 어떤 기능을 갖게 될 것인지는 class단에서 결정됩니다. 객체가 다른 객체를 상속받는 것은 불가능합니다.

 

하지만 자바스크립트는 이것보다 훨씬 더 자유롭습니다. 하지만 그만큼 복잡하고, 혼란스러운 면들이 있습니다. 그럼 자바스크립트에서 어떻게 상속을 구현할 수 있을까요?

 

만약 super object가 있을 때, 이 객체의 기능을 상속받으면서 추가적으로 기능을 추가하고 싶은 객체를 sub object라고 하겠습니다. 자바스크립트에서는 sub object가 super object로부터 직접 기능을 상속받을 수 있습니다. 주류 객체지향 언어에서는 클래스가 상속을 받는데, 자바스크립트에서는 객체가 직접 다른 객체에 상속을 받을 수 있고, 상속관계를 바꿀 수 있습니다. 

 

만약 super object한테 상속을 받았는데, 다른 객체에게 상속을 받고 싶을 땐, 링크만 바꿔주면 됩니다. 이를 prototype link라고 합니다. 이 맥락에서 sub object의 prototype link가 가리키고 있는 객체를 prototype object라고 합니다. 그렇다면 이제 자바스크립트의 객체지향은 어떻게 다른가를 살펴보겠습니다. 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

_proto_

자바스크립트 class문법이 아니라, 전통적인 방법으로 상속하는 방법을 배워보겠습니다. 먼저 superObj라는 객체를 construct function으로 만드는 것이 아니라 수작업으로 만들어보겠습니다. 객체에 기본적인 값을 적고, 그 후 subObj라는 객체도 만들겠습니다.

 

 

지금은 superObj와 subObj는 서로 남남입니다. 그런데 자바스크립트에서는 subObj라는 클래스가 아닌 인스턴스 즉 객체를 직접 다른 객체에 자식으로 만들어버릴 수 있습니다.

 

 

subObj의 원형이 무엇인가라는 것을 가리키는 프로토타입 링크를 정해주면 되는데, subObj에 __proto__라는 프로퍼티, 속성을 주고, 그 속성의 값으로 superObj를 지정하면 됩니다. 여기서 subObj는 superVal이라는 값을 갖고 있지 않은데, 이걸 출력한다면 결과가 어떻게 나올까요?

 

터미널의 결과를 보면 superVal이 super를 가리키고 있습니다. __proto__ 프로토타입 링크를 통해 subObj가 superObj의 자식이다라고 링크를 걸어주니까, 자바스크립트가 subObj에서 superVal이라는 프로퍼티가 있는지 찾아보고, 없으면 proto라는 속성이 담고 있는 객체에서 superVal를 찾아보고 있으면 그걸 사용하는 것입니다. 

 

 

그런데 여기서 subObj.superVal를 sub로 바꿨다면, superObj의 superVal의 값이 바뀔까요? 콘솔에 보이는 것처럼 여전히 super입니다. 왜냐하면 superObj라는 객체 값을 바꿨을 뿐, __proto__가 가리키는 객체를 바꾼 것이 아니기 때문에, 객체의 property를 바꾸면, 객체를 바꾸는 것이지, 객체의 proto를 바꾸는 것이 아닙니다. 즉 객체에서 prototype link를 바꿔주면 객체는 다른 객체의 자식이 될 수 있습니다. 여기서, 객체에 객체를 상속하는 것에 대해서, proto 뿐 아니라, 다른 방법으로도 상속할 수 있습니다. Object.create를 통해 상속받는 방법에 대해 공부해보겠습니다.

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

Object.create()

__proto__를 통해 객체 간의 상속을 구현했다면, 이제는 Object.create를 통해 객체 간의 상속을 구현해보겠습니다. 이를 위해 먼저 아래두 줄의 코드를 교체해보겠습니다. 

 

 

시작하기 앞서, 자바스크립트에게 superObj를 부모로 하는 새로운 객체를 만들어달라고 요청할 땐, 표준화된 방법은 Object.create라는 메서드를 사용해야 합니다. 메서드의 인자로 superObj를 지정하면, 메서드가 새로운 객체를 만드는데, 그 새로운 객체는 superObj를 부모로 하는 새로운 객체다라는 뜻입니다.

 

 

subObj의 subVal을 sub로 바꾸면 주석처리를 한 코드와 똑같이 동작하는 코드가 됩니다. 그래서 __proto__보다 Object.create를 사용해서 객체와 객체 간의 상속관계, 명확하게는 프로토 링크를 지정해주는 것이 더 좋은 방법입니다.

 

그렇다면, __proto__와 Object.create를 통해 객체의 상속을 다루는 방법에 대해 더 익혀보겠습니다.

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

객체 상속의 사용

먼저 kim과 lee라는 두 개의 객체를 만들어보겠습니다. 만약 lee라는 객체에서 kim 객체의 sum 메서드를 사용하고 싶다면? __proto__를 활용하면 됩니다. 

 

 

아래 lee.__proto__ = kim이라는 코드를 통해 lee라고 하는 객체는 sum이라는 메서드를 갖고 있지 않음에도 sum 메서드를 실행할 수 있었습니다. 그 이유는 lee.sum()을 하면 lee라는 객체에 sum이 있는지 찾아보고 없으면 객체의 __proto__의 프로퍼티로서 sum이 있는지 찾아보고, 있다면 메서드를 실행합니다.

 

 

그렇다면, 상속이 아닌, lee에서만 추가하고 싶은 기능이 있다면 어떻게 해야 할까요?

 

 

lee 객체에 avg 메서드를 추가한다면, kim이 갖고 있지 않은 avg 메서드를 가질 수 있습니다. 이처럼 자바스크립트가 갖고 있는 Proto를 통해 상속받는 것은 유용합니다. 그렇다면, __proto__가 아닌, Object.create를 활용해서 상속받는 것에 대해 알아보겠습니다. 

 

 

 

let lee = Object.create(kim); lee.name은 lee라고 하고, lee의 first는 10, second는 10이라고 하고 lee의 avg를 정의해보겠습니다. 그리고 실행시켜보면, 똑같이 잘 동작하는 것을 볼 수 있습니다. Object.create라는 권장되는 방법을 통해 상속을 받을 수 있습니다. 그런데 Object.create는 __proto__가 불편해서 나온 것이어서, 아주 오래된 브라우저에서는 사용할 수 없습니다. 이를 위해 polyfill을 활용해서 옛 브라우저에서도 사용할 수 있게 변환할 수 있습니다.

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

마치며

객체지향에 대한 기본을 쌓아가고 있습니다. 앞으로 포기하지 않고, 하나씩 지식을 쌓아 가다 보면 언젠가는 기초가 튼튼한 개발자가 될 수 있을 것이라 믿습니다. 제대로 된 방향으로 하나씩 공부하고 싶습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

출처