Javascript 입력한 날짜의 해당 달 기준, 주차 구하기
Javascript #2 자바스크립트의 객체 생성
2018-01-19
Explanation
자바스크립트는 객체지향 패러다임을 가지고 있는 프로토타입 기반의 언어입니다. ECMAScript6(이하 ES6) 에서 class 문법이 추가되었지만, 이는 완전히 새로운 객체지향 상속 모델을 의미하지는 않습니다.
이 글은 ES6 이전의 버전을 기준으로 작성하며 추후에 ES6에 관한 부분은 따로 정리하려 합니다.
생성자 함수를 활용하는 방법의 특징은 구조를 미리 정의하기 때문에 객체의 구조 파악에 있어 용이한 점과 함수의 prototype 속성을 사용할 수 있다는 점이 있습니다.
1 2 3 4 5 6 7 8 |
function Me(nickname, job) { this.nickname = nickname; this.jop = job; } var itsMe = new Me('cheolguso', 'developer'); console.log(itsMe.nickname); // 'cheolguso' |
위 예는 간단한 생성자함수를 활용한 객체 생성의 예 입니다. 여기에서 new를 통해 생성된 객체는 기본적으로 생성자 함수의 값들을 상속 받을뿐 아니라 프로토타입 체인으로 생성자 함수를 참조하고 있습니다. 위의 코드에 이어서 아래와 같이 작성한다면 다음과 같은 결과를 확인할 수 있습니다.
1 2 3 |
Me.prototype.phone = 'blackberry'; console.log(itsMe.phone); // 'blackberry' |
생성자 함수를 통한 객체의 속성과 프로토타입으로의 속성은 모두 객체에 .을 이어 호출하지만 둘의 단순한 표면적으로 보이는 차이는, 생성자 함수의 속성은 new를 통해 생성된 시점에서의 속성들을 가지고 있지만 프로토타입은 프로토타입의 속성을 사용하는 시점에서의 값을 가지고 있습니다.
생성자 함수의 속성은 아래와 같이 new로 인스턴스를 생성하기 이전의 속성만을 가지고 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var Test = function() { this.key1 = 'value1'; }; var testIns = new Test(); Test.key2 = 'value2'; Test = function() { this.key3 = 'value3'; }; console.log(testIns.key2); // undefined console.log(testIns.key3); // undefined |
그리고 프로토타입 속성은 아래의 예와 같이 해당 속성이 사용되는 시점 이전의 값을 가지고 있습니다.
1 2 3 4 5 6 7 8 9 |
var Test = function() { this.key1 = 'value1'; }; var testIns = new Test(); Test.prototype.key2 = 'value2'; console.log(testIns.key2); // 'value2' |
또한 생성자 함수에서의 속성명과 프로토타입의 속성명이 같을때에는 생성자 함수의 속성이 우선시되며 프로토타입의 속성은 __proto__를 사용하여 호출할 수 있습니다.
여기에서 사용된 __proto__는 ES6에서 추가된 표준으로 ES6 이전부터 Internet Explorer(이하 IE)를 제외한 대부분의 모던 브라우저들에서는 지원하던 속성입니다. 현재 많은 데스크탑, 모바일 모던 브라우저에 호환합니다.(IE11 이상)
1 2 3 4 5 6 7 8 9 10 |
var Test = function() { this.key1 = 'function value'; }; Test.prototype.key1 = 'prototype value'; var testIns = new Test(); console.log(testIns.key1); // 'function value' console.log(testIns.__proto__.key1); // 'prototype value' |
리터널이란 코드상 데이터를 표현하는 하나의 방식이며 고정된 값을 대표하는 용어로 모든 데이터 타입에 들어가는 데이터 값 그자체.. 정도로 설명될 것 같습니다. (직접적인 데이터 값 자체를 컴퓨터 메모리에 할애하는 방식?)
생성자 함수를 활용한 방식은 하나 이상의 함수를 거쳐 생성되기 때문에 prototype 속성을 사용할 수 있지만, 리터널 방식으로 생성된 객체는 prototype 속성을 사용할 수 없습니다.
1 2 3 4 5 6 7 8 9 10 11 12 |
function FncObject() { this.aaa = 'vvv'; } var a = new FncObject(); // 생성자 함수로 객체 생성 var b = { aaa : 'vvv' }; // 리터널 객체 생성 console.log(a.aaa); // 'vvv' console.log(b.aaa); // 'vvv' |
조금 더 세부적으로 객체를 참조하는 과정을 생각해보면 위 예제에서 a라는 변수는 FncObject라는 함수를 가리키고, new가 FncObject라는 함수를 객체로 리턴하게하여 vvv라는 값의 aaa라는 속성을 가지고 있는 FncObject라는 객체를 참조하게 됩니다.
1 |
a -> FncObject() -> new -> FncObject { aaa : 'vvv' } -> Object {aaa : 'vvv'} |
반면 b라는 변수는 바로 vvv라는 값의 aaa속성을 가지고 있는 Object(객체)를 바로 참조합니다.
1 |
b -> Object { aaa : 'vvv'} |
위 설명은 단순히 제가 이해한 방식이며 실제로 컴퓨터가 저렇게 해석하는지는 알 수 없으며, ‘리터널 방식이 더 간소화 되어 효율적이다’는 의미를 말하려는 것은 아닙니다.
create() 메서드를 활용해서 객체를 생성하여 사용해본 적이 거의 없고.. 이미 ES6를 많이 사용하게 되어서 앞으로도 사용할 일이 없을 것 같지만.. 간단하게나마 알아본 정보를 요약해보려 합니다.
이 부분은 MSDN(Microsoft Developer Network)의 내용과 거의 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var a = Object.create(null, { aaa : { value : 'vvv', writable: true, enumerable: true, configurable: true } }); console.log(a); // Object {aaa : 'vvv'} a.aaa = 'xxx'; console.log(b); // Object {aaa : 'xxx'} |
Object.create()의 첫번째 인자값은 프로토타입으로 사용할 개체이며 두번째 인자값은 하나 이상의 속성을 가진 자바스크립트 개체입니다. 첫번째 인자는 null이 사용될 수 있고 두번째 인자에서는 속성명과 value 라는 값이 필요하며 나머지 writable, enumerable, configurable 속성의 기본값은 false 입니다.
writable: 값을 수정할 수 있는지, configurable: 값을 삭제할 수 있는지, wnumerable: 반복문에서 값이 보이는지
첫번째 인자가 ‘null’ 로 생성된 객체는 prototype 속성을 사용할 수 없습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function TestObject () { this.aaa = 'vvv' }; var a = new TestObject(); var b = { aaa : 'vvv' }; var c = Object.create(null, { aaa : { value : 'vvv' } }); Object.getPrototypeOf(a); //Object { constructor: function } Object.getPrototypeOf(b); //Object { __definGetter__: function, __definSetter__: function, ... } Object.getPrototypeOf(c); //null |
객체 리터널로 만들어진 객체와 같은 프로토타입을 갖고자 한다면..
1 2 3 4 5 6 7 8 9 10 |
var a = Object.create(Object.prototype, { aaa : { value : 'vvv', writable: true, enumerable: true, configurable: true } }); Object.getPrototypeOf(a); // Object { __definGetter__: function, __definSetter__: function, ... } |
생성자 함수로 만들어진 객체와 같이 프로토타입 속성을 사용할 수 있는 객체를 만든다면..
1 2 3 4 5 6 7 8 9 10 11 12 |
var a = Object.create(Object.constructor, { aaa : { value : 'vvv', writable: true, enumerable: true, configurable: true } }); a.prototype.bbb = 'bbb'; console.log(a.bbb); // 'bbb' |
처럼 사용할 수도 있지 않을까…
Object.create() 메서드를 통한 객체 생성은 단순히 객체를 만드는 것보다는 객체의 어떤 값을 보호하며상위에 어떤 객체를 상속 받는 하위 객체를 생성하는 것에 주안점을 두고 있는 것 같습니다.