728x90

본 강의는 자바스크립트의 기초를 대충 안다고 가정하고 시작하는 조금 심도 깊은 포스팅이다.

완전 처음부터 배우고 싶다면 다른 블로그나 책의 글을 참조하기를 바란다.

특별한 추가 설명이 없다면 nodejs가 아닌 브라우저에서 사용하는 js를 의미한다.


참고:

javascript docs

ecmascript specification


프로그래밍을 하다보면 객체지향으로 자연스럽게 넘어갈 수밖에 없는 일이 생긴다.

아무래도 무언가를 property와 method로 묶는 객체라는 개념은 데이터를 관리하기 편리하게 해주니까.

js도 객체라는 개념이 존재한다.

그러나 기존의 객체와는 조금 개념이 다르다... 사실 조금 다른게 아니라 많이 다르다.


이번에는 객체에 대해서 알아보도록 할건데 이걸 읽으시는 분들이 이미 js의 객체를 어느정도 아는지 아니면 모르는지는 잘 모른다.

필자가 모든걸 다 설명할건 아니기 때문에 모르는 부분이 있다면 다른 포스팅들을 참조하길 바란다.


일단 여러분들이 js의 객체에 대해서 조금 환상같은게 있을 수 있다.

그러나 사실 이 환상이 개박살 나는게 바라 이번 포스팅일 것이다.


여러분은 var a = {};라는 문법이 있을 때 a는 뭐라고 생각하는가?

a는 바로 맵(딕셔너리, 연관배열, 해시맵 등등)이라고 부를것이다.

이를 보통 js에서는 object라고 부른다. 여러분은 "이름만 object지 사실 맵이지!"라고 생각했을지 모른다.

그런데 놀랍게도... 정말 저게 object이다. 객체지향에서 쓰는 객체 그 자체이다.

그렇다 사실 여러분들은 이 때까지도 객체를 주구장창 만지고 있었다.


아니?? 객체는 new 키워드를 써서 만든게 객체 아닌가? 라고 생각할 수 있다.

그 말도 맞다. 객체는 new 키워드를 써서 만든 것이다. 그런데 여기는 또 함정이 있다.


var a = {};
var a = new Object();

이 두 구문은 완전 동일한 구문이다.

여기서 2차충격이 올것이다.

여러분이 이 때까지 주구장창 써왔던 {}는 사실 문법적 설탕에 지나지 않았다.

실제로는 new Object()를 선언한 Object형 객체였던 것이다.

더 정확히 말하면 Object를 프로토타입으로 하는 인스턴스들이였다고 보는게 맞을 것이다.


이제 전형적인 객체의 생성 예시를 보도록 하자.

function Book(owner) {
this.owner = owner;
}
Book.prototype.page = 150;

var book = new Book('kukaro');

console.log(Book.prototype);
console.log(book);



이 예시는 사실 전형적인 생성자를 선언하고 객체 인스턴스를 만드는 예시이다.

여기서 한가지 눈여겨 봐야할 점은 Book이라는 생성자이다.

여러분은 생성자를 함수로 만든다고 알고 있었을 것이다. 필자역시 그렇게 가르치는 사람이 많았다.


하지만 반대다. 모든 함수는 사실 생성자다.


js에서는 함수를 생성자로 쓸 수있다. 이는 new 키워드를 붙힐 때만 가능하다.

위의 Book은 그냥 쓰면 그냥 일반적인 함수라고 할 수 있다. 그러나 new 키워드를 붙혀서 함수를 호출하는 순간 이는 생성자로 작동하게 된다.


여러분이 조금 어려워하는게 바로 prototype이라는 개념이다.

사실 이 역시 조금 이해하고 접근하면 쉽다.

여기서 선행해서 알아야할 점은 아래와 같다.


1. 모든 함수는 그 자체로 이미 객체이다. (js에서 모든 함수는 일등 객체이다.)

2. 함수는 객체이므로 프로퍼티를 가질 수 있다.

3. 함수는 생성 즉시 constructor와 prototype이라는 프로퍼티를 가진다.

4. 함수를 new키워드를 이용해서 객체를 생성시킨다는 표현은 사실 옳지 못하다. 그냥 prototype 객체를 연결하고 함수를 실행시킬 뿐이다.


4번이 되게 중요한 개념인데 1,2,3번은 설명을 추가적으로 할 필요가 없으므로 4번을 다시 설명하도록 하겠다.

여러분들은 prototype에대해서 뭔가 엄청 거창하게 생각하는 경향이 있는데 가령 위의 예시로 들어보자.


Book.prototype.page = 150;

Book에 prototype이라는 프로퍼티에 page를 할당했다.

현재 프로토타입에 추가적으로 값을 할당한건 없으므로 prototype은 page만 존재할 것이다.

물론 여러분이 추가적으로 할당한다면 더 값이 들어가는건 말할 것도 없다.


var book = new Book('kukaro');

이제 이 부분의 수순을 한번 보도록 하겠다.

매우 간단하다.

이 부분은 정말 쉽게 설명하면 아래와 같다.


먼저 book은 Book.prototype과 연결된다. 프로퍼티의 이름은 __proto__이다.

그 다음 함수의 본체가 실행된다(여기서는 Book 함수이다.)



여기서 여러분들이 아래와 같은 실수를 저지르는 경우가 있다.


<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
function Book() {

}

Book.prototype.page = 150;

var book = new Book('kukaro');

Book.owner = 'jiharu';

console.log(book.owner);

</script>
</body>
</html>

자. 이 코드의 결과는 무엇일까?

Book.owner를 붙혔으니 book까지 owner가 붙을까??
전혀 아니다.

Book 인스턴스와 book 인스턴스는 엄연히 다른 인스턴스다.

Book도 객체고 book도 객체다. 즉 Book에 직접 붙히면 그건 그냥 Book이라는 객체의 프로퍼티로 들어간거다.

만약 book의 프로퍼티로서 활용하고 싶다면 프로토타입객체 붙혀줘야한다.


<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
function Book() {

}

Book.prototype.page = 150;

var book = new Book('kukaro');

Book.prototype.owner = 'jiharu';

console.log(book.owner);

</script>
</body>
</html>

위 처럼 사용한다면 여러분이 원하는 결과를 얻을 수 있다.

객체에 대해서 깊게 들어간다면 더 할말이 많지만 일단 여기까지 하도록 하겠다.

다음에는 프로토타입이 아닌 클래스를 사용해서 만드는 법에 대해서 알아보도록 하자.


+ Recent posts