본문으로 바로가기

Object 객체 정의하기

이번에 살펴볼 객체 리터럴(object literal)을 사용해 객체를 생성하는 방법은 Object 객체의 구조를 정의하고 생성하는 구문을 하나로 합칠 수 있어서 new와 Object 생성자를 이용해 객체를 생성하고 필요한구조를 만들어가는 과정을 좀 더 간소화할 수 있습니다.

그래서 코드가 간결해지고 가독성(readability)이 높이집니다.





객체 리터럴

이제 객체 리터럴을 이용해 객체를 만드는 방법을 알아보겠습니다.

다음의 방법은 표현의 간결함 때문에 객체 생성 구문으로 많이 사용됩니다.

javascript
var obj = {
    name: 'jaehee', // 멤버명을 'name' 처럼 인용부호로 감싸는 것도 가능
    age : 10,
    increaseAge : function (i) {
        this.age + i;
    }
};

위 코드가 바로 Object 객체를 생성하기 위해 객체 리터럴(Object literal) 표현 { ... } 을 이용하는 코드입니다.

전체 객체의 멤버가 { } 내부에 콤마(,)로 구분되어 있습니다. 다시 각 멤버는 콜론(:)으로 이름과 초기값이 구분되어 있습니다.


객체 리터럴을 이용해 객체를 생성하는 방법과 Object 생성자를 이용해 객체를 생성하는 방법의 내부적인 과정은 동일합니다.

일단 Object 생성자를 이용해 최초의 Object 객체가 생성되고 나서 리터럴 표현에서 정의한 멤버를 동적으로 추가하는 것입니다.


객체 리터럴을 사용해 객체를 생성하는 방법은 내부적으로 new Object를 수행한 후 멤버를 구성하는 방법과 동일한 과정을 따른다.


이렇게 정의된 멤버는 모두 외부에서 접근할 수 있는 공개 멤버입니다.

이 방법으로는 비공개 멤버를 구현할 수 없습니다. 비공개 멤버를 구현하는 방법은 추후에 다뤄보도록 하겠습니다.

객체 리터럴 표현에서 사용하는 this는 { } 로 생성되는 객체를 가리킵니다.

따라서 this.ageobj.age 와 동일한 표현이 됩니다.

만약 아무 멤버도 없는 Object 객체를 생성하고 싶다면 다음과 같이 하면 됩니다.

javascript
var obj = {}; // Object의 기본 멤버를 갖는 객체 생성

이 코드는 다음 코드와 동일합니다.

javascript
var obj = new Object();


앞에서 언급한 obj와 동일한 구조의 객체는 객체 리터럴 표현을 이용해 다음과 같은 방법으로도 만들 수 있습니다.

javascript
var obj = {};
obj.name = 'jaehee';
obj.age = 10;
obj.increaseAge = function (i) {
    this.age + i;
};


객체 리터럴을 사용해 속성에 다른 객체를 할당하는 중첩된 표현도 가능합니다.

다음은 obj 객체의 parent 속성에 다른 객체를 할당하는 코드입니다.

javascript
var anotherName = '자바스크립트';
var obj = {
    name :'jaehee',
    age : 10,
    parent : {
        name : '홍길동',
        job : 'Freelancer'
    },
    etc : function() {
            this.name + "의 또다른 이름 : " + anotherName
    }
};

parent의 job 속성에 대해서는 다음과 같이 접근할 수 있습니다.

javascript
console.log(obj.parent.job)


또한 etc 속성의 값처럼 객체 리터럴에서 속성의 값은 고정된 값뿐만 아니라 계산된 식이 반환하는 값을 할당할 수도 있습니다.


jQuery 같은 라이브러리를 보면 new Object 보다 Object 리터럴 표현을 자주 사용하고 있음을 알수 있습니다.

jQuery 라이브러리 코드 일부분의 작성방식은 다음과 같습니다.

javascript
jQuery.fn = {
    constructor : jQuery,
    init : function() { ... },
    selector : "",
    length : 0,
    size : function() { ... },
    toArray : function() { ... },
    each : function(callback, args) { ... },
    ready : function(fn) { ... }
};


함수를 호출할 때 전달할 인자값도 객체 리터럴 표현을 이용해 구성하는 코드를 자주 보게 됩니다.

다음과 같이 정의된 함수가 있다고 가정해 봅니다.

javascript
function OpenWindow(options) {
    var url = options.path || 'http://e-rooms.net';
    var name = options.windowName || 'eroomWindow';
    var option = options.windowOptions || 'width=100,height=100';
    window.open(url, name, option);
}


앞의 함수를 호출하는 코드에서 객체 리터럴을 이용해 options 객체를 구성해서 함수를 호출하는 데 사용하는 인자를 전달하는 값으로 사용할 수 있습니다.

javascript
var options = {
    path: 'http://e-rooms.tistory.com',
    windowName: 'jaeheeWindow',
    windowOptions : 'width=500, height=500'
};
OpenWindow(options);


함수 내부에서는 인자를 전달받는 options에서 path, windowName, windowOptions 속성이 있는지 체크합니다.

없다는 각 기본값을 이용하게 됩니다.




사용자 정의 객체 정의

일반 객체지향 언어에서 클래스를 사용해 객체를 생성하는 방법이 있습니다.

다음은 자바에서 Person 이라는 클래스를 정의하는 코드입니다.

java
public class Person {
    public string Name;
    // 생성자
    public Person(name, age) { this.Name = name; ... }
}

// 객체 생성
mySon = new Person(...);

class 라는 키워드를 사용해 객체의 구조를 정의하는 코드와 초기화 작업을 하는 코드를 함께 묶을 수 있습니다.

일반 객체지향 언어에서는 이런 식으로 Person이라는 클래스 안에 구조를 정의하고 초기화를 담당하는 코드가 모두 통합되어 있습니다.


일반 객체지향 언어에서는 객체를 생성하고 나면 서전에 정의된 멤버 외에 다른 멤버를 추가하지 못합니다.

언어별로 런타임에 멤버 추가에 대한 기술적인 방법을 제공하기도 하지만 그것은 해당 언어에서만 제공하는 독자적인 기능이지 객체지향적인 사상에는 위배된다고 할 수 있습니다.



객체 정의

사용자 정의의 객체를 정의하기 위해 자바스크립트에서는 class라는 키워드 대신 function 을 사용합니다.

javascript
function Person(name) {
    this.name = name;
}

위의 코드는 일반 함수와 다를게 없습니다.

객체를 정의할 때 이렇게 function 키워드를 사용한다면 그냥 함수(일반함수)를 정의할 때 사용하는 function 과는 어떤 차이가 있을까?

실질적으로 함수의 function과 객체를 생성할 때의 function은 동일합니다.

자바스크립트 함수는 동일한 함수가 호출 가능한 요소로도 사용될 수 있고 다른 객체를 생성하는 요소로도 사용될 수 있습니다.

어떤 역할로 사용될 지는 주변 실행 환경, 즉 연산자에 따라 달라집니다.

new 와 함께 사용되면 메모리에 인스턴스를 생성하는 역할로 사용됩니다.

new 없이 단순히 () 연산자를 사용해 Person('재희')과 같이 호출하면 일반 함수처럼 사용됩니다.

그래서 암묵적인 약속으로 프로그래밍계에서는 일반 함수는 소문자로 시작하고 생성자는 대문자로 시작하게 작성하도록 권장하고 있습니다.



멤버 정의

자바스크립트에서는 객체의 멤버를 정의하는 것도 일반 객체향 언어와는 사뭇 다릅니다.

자바스크립트에서는 멤버를 추가할 때 this를 사용합니다.

this.name = name;

이 코드는 Person 객체에 name이라는 공개 속성(public property)을 정의합니다.

만약 메서드를 정의하고자 한다면 익명 함수를 이용할 수 있습니다.

javascript
this.setNewName = function (name) {
    this.name = name;
}


멤버가 정의된 Person 생성자는 다음과 같습니다.

javascript
function Person(name) {
    this.name = name;
    this.setNewName = function (name) {
        this.name = name;
    }
}



객체 생성

이제 앞에서 정의한 Person 생성자를 new와 함께 호출하면 객체를 생성할 수 있습니다.

javascript
var mySon = new Person('jaehee');

생성자는 최초 생성되는 객체의 멤버 구조를 정의하고 그 값을 초기화하는 역할을 합니다.


자바스크립트 생성자 = 객제구조 정의 & 객체초기화 를 담당한다.


자바스크립트에서는 new를 이용해 Person 생성자를 호출하는 구문이 다양합니다.

javascript
var mySon = new Person('jaehee');
var mySon = new Person(); // 생성자 매개변수 name은 undefined로 설정됨
var mySon = new Person; // 생성자 매개변수 name은 undefined로 설정됨

생성자를 new와 함께 사용할 때는 세번째 구문처럼 () 연산자를 생략해도 됩니다.

생성자를 호출할 때 new Person(), new Person 처럼 인자없이 인스턴스를 생성하면 생성자의 매개변수 name은 undefined로 설정됩니다.

외부로부터 값을 전달받지 못한 함수의 매개변수는 undefined로 초기화됩니다.

이런 일반 함수의 특징은 그대로 생성자에 적용되는 것입니다.


this를 통해 정의되는 멤버는 현재 생성되고 있는 객체의 공개 멤버로 정의됩니다.

this로 정의된 멤버는 new로 생성되는 인스턴스별로 별도로 존재하게 됩니다.

그래서 이 글에서는 생성자 내부에서 this를 이용해 추가한 멤버는 "인스턴스 멤버"라고 표현하고 있습니다.


인스턴스 멤버는 나중에 접하게 될 프로토타입 멤버(prototype member)와 대비되는 개념입니다.

프로토타입 멤버는 동일한 생성자로 생성되는 모든 객체(인스턴스)가 공유할 수 있는 멤버로서 그 값이 변경되면 해당 생성자로 생성된 모든 객체 영향을 줍니다.

그에 반해 인스턴스 멤버의 변경은 해당 객체에만 영향을 줄 수 있습니다.

사실 자바스크립트는 프로토타입 멤버 중심입니다.

객체를 설계하거나 상속을 설계할 때 모두 프로토타입 객체를 기준으로 합니다.

따라서 자바스크립트는 프로토타입 기반의 객체지향 언어라고 하는 것입니다.



Jaehee's WebClub