-
[Javascript] 프로토타입으로 상속 구현하기JavaScript 2022. 2. 19. 01:07
VanillaJs로 채용과제를 약 일주일정도 진행하게 되었습니다.
이때 클래스 키워드를 사용하지 않고 function으로 만들게 되었는데, prototype의 활용을 잘 하지 못한것 같아 아쉬움이 남았습니다.따라서 이번에 prototype을 통한 상속을 구현해 보면서 개념을 정리하고, 추후에 리팩토링을 해보려 합니다.
생성자 함수 만들기
function Foo(name) { this.name = `${name} success!`; console.log("constructor Foo"); } Foo.prototype.getName = function () { console.log(this.name, "prototype"); };
기본적인 함수를 만들어 주었습니다.
화살표 함수로 만들어주게 된다면 this binding을 할 수 없고, 생성자 함수로 호출 할 수 없기 때문에 함수 선언문을 사용하였습니다.
저는 Bar라는 함수가 Foo 함수를 상속받았으면 좋겠다는 생각을 했습니다.
어떻게 구현해야 할까요?
상속 구현하기
function Foo(name) { this.name = `${name} success!`; console.log("constructor Foo"); } Foo.prototype.getName = function () { console.log(this.name, "prototype"); }; function Bar(name) { this.name = name; } function extend(superFunc, subFunc) { function F() {} // 1 F.prototype = Foo.prototype; // 2 subFunc.prototype = new F(); // 3 subFunc.prototype.constructor = subFunc; // 4 }
extend함수로 상속을 구현해 보았습니다. extends 키워드이기 때문에 s를 빼고 네이밍을 지어주었습니다.
1번
비어있는 함수 F를 정의했습니다. 앞으로 왜 만들어 주었는지 확인해 보겠습니다.
2번
F의 프로토타입을 Foo의 프로토타입으로 지정해 주었습니다.
즉, F의 인스턴스들은 __proto__ 를 통해 이제부터 Foo함수의 constructor메서드가 아닌 Foo에서 prototype으로 정의한 메서드들에 접근할 수 있습니다.
아래의 사진은 3번을 나타낸것입니다.
3번
subFunc의 프로토타입에 F함수의 인스턴스를 할당해 주었습니다.
여기까지 본다면 subFunc의 프로토타입은 F함수의 인스턴스와 연결되어있습니다.
3번에서 우리는 F함수의 인스턴스가 Foo에 접근할 수 있는것을 알 수 있습니다.
따라서 우리는 subFunc의 프로토타입을 통하여 F함수의 prototype을 거쳐 Foo함수의 prototype까지 접근할 수 있습니다.
4번
함수의 prototype 프로퍼티는 생성 시점에 constructor프로퍼티만을 가지고 있습니다. constructor는 자신과 연결된 (생성자) 함수를 가리키며 이 프로퍼티를 통해 어떤 (생성자)함수를 통해 만들었는지 알 수 있습니다.
constructor가 Foo함수를 참조하기 때문에 인스턴스가 Foo함수를 통해 만들어졌다는것을 알 수 있다. 하지만 Bar의 prototype은 현재 F의 인스턴스이기 때문에 constructor 프로퍼티가 존재하지 않습니다.
따라서 Bar.prototype.constructor를 자기 자신으로 하여 순환참조를 할 수 있도록 합니다.
생성자 함수 호출하기
여기까지 했다면 모든 구현이 다 끝났지만 class 문법에서 생성자 함수는 인스턴스 생성 시 가장 먼저 호출이 됩니다.
하지만 위의 함수에서는 (생성자) 함수 Foo를 호출하고 있지 않습니다.
따라서 apply문법을 통해 호출합니다.
function Bar(name) { Foo.apply(this, arguments); this.name = name; }
apply문법은 Foo함수를 간접적으로 호출할 수 있게 해 줍니다. 두번째 인자로, Foo함수에 들어갈 인자를 배열 형태로 넣어줍니다.
함수 선언문에는 arguments객체가 존재하기 때문에 편리하게 넣어줄 수 있습니다.
코드
function Foo(name) { this.name = `${name} success!`; console.log("constructor Foo"); } Foo.prototype.getName = function () { return `${this.name} prototype`; }; function Bar(name) { Foo.apply(this, arguments); this.name = name; } function extend(parent, child) { child.prototype = Object.create(parent.prototype); child.prototype.constructor = child; } extend(Foo, Bar); const a = new Bar("Jin"); // constructor Foo console.log(Bar.prototype); // Foo { constructor: [Function: Bar] } //Bar의 인스턴스의 a는 어떤 함수로 만들어졌는지 확인하기 console.log(a.__proto__.constructor); [Function: Bar] console.log(a.getName()); //Jin prototype // Foo함수의 this.name = `${name} success!`;이 오버라이딩되어 사라진것을 알 수 있습니다. console.log(a.name); // Jin console.log(a instanceof Foo); // true console.log(a instanceof Bar); // true
다음으로 Object.create를 사용하여 약간의 코드를 수정합니다.
Object.create메서드의 경우 지정된 프로토타입 객체 및 속성(property)을 갖는 새 객체를 만듭니다.
function F() {} F.prototype = parent.prototype; child.prototype = new F(); // 위의 코드를 아래로 변경할 수 있습니다. child.prototype = Object.create(parent.prototype);
최종 코드
function Foo(name) { this.name = `${name} success!`; console.log("constructor Foo"); } Foo.prototype.getName = function () { return `${this.name} prototype`; }; function Bar(name) { Foo.apply(this, arguments); this.name = name; } function extend(parent, child) { child.prototype = Object.create(parent.prototype); child.prototype.constructor = child; } extend(Foo, Bar); const a = new Bar("Jin"); // constructor Foo console.log(Bar.prototype); // Foo { constructor: [Function: Bar] } //Bar의 인스턴스의 a는 어떤 함수로 만들어졌는지 확인하기 console.log(a.__proto__.constructor); [Function: Bar] console.log(a.getName()); //Jin prototype // Foo함수의 this.name = `${name} success!`;이 오버라이딩되어 사라진것을 알 수 있습니다. console.log(a.name); // Jin console.log(a instanceof Foo); // true console.log(a instanceof Bar); // true
'JavaScript' 카테고리의 다른 글
[함수형 프로그래밍] reduce, go, pipe, curry 로 풀어보는 코딩테스트 (0) 2022.03.09 [함수형 프로그래밍] generator 알아보기 (0) 2022.02.22 [함수형 프로그래밍] 잘 만들어진 이터레이터란? (well-formed iterator) (0) 2022.02.09 [함수형 프로그래밍] 이터레이터와 이터러블이란? (0) 2022.01.31 [JavaScript] 25 Beginner JavaScript Project Ideas 첫번째 만들기 (0) 2022.01.25