본문 바로가기
front-end/javascript

[javascript] ES6 클래스와 Prototype / 왜 Object instanceof Function은 true인가

by MOOB 2019. 11. 9.

ES6 Class와 Prototype

#dev

자바스크립트는 프로토타입 기반 객체지향 언어다. 프토로 타입 기반이므로 클래스가 없고, 따라서 상속 개념이 존재하지 않는다. ES5까지는 프로토타입 체인과 클로저 등으로 상속이나 캡슐화 등을 흉내내어 구현해왔다

프로토타입

프로토타입은 프로토타입 링크와 프로토타입 오브젝트로 구성된다.

프로토타입 객체

객체는 언제나 함수로부터 생성된디. 객체 뿐만 아니라 함수와 array도 모두 함수로 장의되어 있다.

function CreateItem(){};
const NewItem = new CreateItem(); // 함수를 통한 객체 생성

const obj = {}; //다음과 같이 객체를 선언하는 것은
const obj = new Object(); // Object 함수를 통해 obj 객체를 생성하는 것과 같다

함수를 정의할 때에는 두가지 일이 일어난다. 첫번째는 생성자 자격을 부여하는 것이다. 생성자가 아니면 new를 통해 새로운 객체를 정의할 수 없다.

const newObj = {};
const newNewObj = new newObj; // 에러남

또한 함수가 정의되면서 Prototype Object도 함께 생성된다. Prototype Obkect는 construnctor__proto__로 이루어져 있다. construnctor은 일반적인 객체이며 __proto__는 Prototype Link와 관련있다.

function Item(){}
Item.prototype.apple = 1; // 프로토타입 객체의 constructor에 저장됨
Item.prototype.banana = 4;

const FruitStore = new Item();
console.log(FruitStore.apple); // FruitStore은 Item의 prototype을 참조할 수 있기 때문에 1이 출력됨

FruitStoreItem의 prototype을 참조할 수 있는 이유는 __proto__Item의 prototype을 연결시켜주고 있기 때문이다. (Prototype link) __proto__는 모든 객체가 가지고 있는 속성으로 객체가 생성될 때 조상인 함수의 Prototype Object를 가리키고 있다. 즉 FruitStore.apple이 정상적으로 출력되었다고 해서, FruitStore가 apple을 직접 가지고 있는 게 아니라 모태가 되는 함수로부터 참조해 온 것이다.

Class와 Prototype의 차이

클래스의 constructor는 프로토타입의 생성자와 달리 객체 없이 접근이 불가능하다.

function Item(name){
  this.apple = name;
  return name
}

console.log(Item.prototype.constructor.apple('apple')); // apple
console.log(apple.name); //apple

class Item(){
  constructor(name){
    this.apple = name;
    return name
  }
}

console.log(Item.prototype.constructor.apple('apple')); // error

또한 super과 extends를 활용하여 자식 class 및 subclass를 만들 수 있게 되었다..

추가 공부

console.log(Object instanceof Function)은 트루트루 꿈 같아서 볼 꼬집어봐...

이번에 es6의 prototype을 공부하게 되면서 자바스크립트의 객체와 함수의 관계에 대해서 공부하게 되었다. 자바스크립트에서 함수는 객체이다라는 말을 자주 들었는데 나는 그 개념을 반대로 이해하고 있었다.

console.log(Object instanceof Function); //true
console.log(Function instanceof Object); //true

둘 다 true가 반환된다. 엥?

인터넷을 찾아봐도 제대로 된 답이 없길래 따로 조사해 보았다. (영문 자료도 딱 두개 있었다 ㅠㅠ)
스텍오버플로우 설명이 너무 어려워서 제끼고 다음 미디엄 글을 참고했다. (저 영어 잘 못하니까 틀렸으면 댓글로 알려주세요..제발..)

우리가 아는 __proto__는 객체가 참조하는 모체(?)의 프로토타입을 가리킨다. 모든 객체는 [[Prototype]]이라는 겉으로 드러나지 않은 내부의 프로퍼티이다. 이 프로토타입은 Object.getPrototypeOf()를 통해 읽어들일 수 있다. 새로운 객체가 생성되면 그 객체의 prototype은 이 내부 프로퍼티 [[Prototype]]을 초기화(initialize)시킨다.

function Test() {};
const testItem = new Test();
console.log(Test.prototype instanceof Object); //true
Object.getPrototypeOf(testItem) === Test.prototype // true

즉, 새로운 객체의 [[Prototype]]은 모체(이거 뭐라 부르는지 갑자기 생각이 안난다.)의 프로토타입을 가리킨다.

Function.prototype // function () {}
Object.getPrototypeOf(Function) // function () {}
Object.getPrototypeOf(Function) === Function.prototype // true

함수는 객체다. 그런데 객체는 객체를 만들어낸 함수 즉, Object Constructor를 참조하고 있다. Object의 [[Prototype]]Function.prototype을 가리키는데 얘는 함수이다. 그래서 Object instanceof Function이다.

공부하고 나니 굳이 파 볼 필요는 없었던 것 같다. 그냥 궁금해서 찾아보고 싶었다.
어차피 우리가 만드는 함수는 이 Object construnctor 함수에서 비롯된 것이므로 객체이고, window 객체 안에서 만들어지므로 이 또한 객체이다. 함수는 객체다!!! 여기서 말하는 Object constructor은 어차피 코어라 우리가 접근할 일 없는 부분 같고, 그냥 깊게 한 번 파본 경험으로 생각하겠다.

댓글