All Articles

Javscript Prototype에 대하여 알아보자. (1)

Javascript는 Prototype 상속 언어이다!

"Javascript는 프로토타입 상속에
기반을 둔 객체 지향 언어이다."

이 말은 처음 Javascript를 배울 때 한번쯤은 듣게 되는 문구이다.
사실 JS를 접하게 되면 이 문구가 처음에는 와닿지도 않고 무슨 말인지도 잘 모른다.

하지만 JS를 깊이 배울수록 저 문구가 참 JS 본질을 꿰뚫는 핵심 문구라는 것을 느끼고 있다.
Java와 C++등 객체 지향 언어에서는 Class를 상속하기 위한 별도의 구문이 있다.
물론 ES6에 들어서 class라는 문법이 Javascript에 추가되었지만 Java나 C++와 같은 언어에서 사용하는 개념과는 다르다.

내가 만든 객체가 어떻게 생성되고 어떤 과정을 거쳐서 사용할 수 있게 되는 것인지 아는 것은 정말 중요하다.
따라서 Prototype 생성을 포스팅하여 내 머릿속에 추상적으로 잡혀있는 Prototype에 대한 정리를 해두려고 한다.

프로토타입 체인

모든 객체는 내부 프로퍼티 [[Prototype]]을 가지고 있다. 브라우저를 키고 아무 객체를 생성해보면 그 아래 __proto__가 있는 것을 볼 수 있을 것이다.
이 __proto__는 그 객체에게 상속을 해준 부모 객체를 가리킨다. 따라서 이 객체는 __proto__프로퍼티가 가리키는 부모 객체의 프로퍼티를 사용할 수 있다. 이를 프로토타입 체인이라고 한다.
예시를 들어보면 아래와 같다.

const personA ={
	name:"John",
	myName:function(){
		console.log(`Hello my name is ${this.name}!`);
	}
}

const personB = {
	name:"Yohan"
}
personB.__ proto__ = personA;
const personC ={};
personC.__proto__= personB;
personC.myName(); // "Hello my name is Yohan!"

분명 PersonC에는 myName이라는 메소드가 없다. 그러나 어찌된 일인지 'my name is Yohan'이라는 콘솔 로그를 찍어낸다.

이게 바로 프로토 체인이다.
우선 PersonC에서 찾아본 후 해당 메소드가 PersonC에 없으면 해당 proto의 부모인 PersonB로 간다.
만약 PersonB에서도 존재하지 않으면 PersonA에로 간다.
이런 식으로 점점 올라가 최종으로 PersonA에 있는 myName 메소드를 호출하게 되는 것이다.

하지만, 당연히 일반적으로 직접 __proto__를 써서 상속하지는 않는다.
두 가지의 방법이 있다.

  • 생성자(constructor)로 객체를 생성할 때 생성자의 prototype 프로퍼티에 추가하는 방법
  • Object.create() 메서드로 상속을 받을 프로토 타입을 지정하여 객체를 생성하는 방법

첫 번째 방법이 우리가 일반적으로 쓰는 방법이다. 즉, new를 사용하여 인스턴스를 생성하는 것이다.
그렇다면 new를 사용하면 어떤 과정이 내부에서 일어나서 상속을 하게 되는 것일까? JS는 다른 객체지향언어와 어떻게 다를까?

function Person(name, age){
	this.name = name;
	this.age = age;
}
Person.prototype.greet = function(){
	return console.log(`Hello my name is ${this.name} and my age is ${this.age}`);
}

const personA = new Person('John','27')`

  1. 빈 객체를 생성한다.
const newObj = {};
  1. Person.prototype을 생성된 객체의 프로토타입으로 설정한다.
newObj.__proto__ = Person.prototype;
그런데 이때 만약 Person.prototype이 가리카는 것이 객체가 아니라면 `Object.prototype`을 프로토타입으로 설정한다. <br><br>
  1. Person생성자를 실행하고 newObj를 초기화한다.
    이 때 this는 1에서 생성한 객체로 설정한다. 인수는 new연산자와 함께 사용한 인수를 그대로 사용한다.
Person.apply(newObj, arg);
  1. 완성된 객체를 반환한다.
return newObj;

이런식으로 진행되는 것이다. 이처럼 생성자를 new로 하여 생성하게 되면
객체 생성, 프로토타입 설정, 객체 초기화를 설정하게 된다.