본문 바로가기

JavaScript/기본 이론

Chapter 13. 객체의 이해

1. 객체의 이해

객체는 실세계에서 우리가 인식하는 사물을 말한다.

쉽게 말해 데이터의 집합을 객체라고 한다.

객체는 데이터의 집합이기 때문에 자바스크립트 또한 객체라고 할 수 있고, 자바 스크립트에서 사용되는 데이터도 객체로 볼 수 있다. 

자바스크립트에서는 숫자, 문자열, 불리언, 언디파인트 타입을 제외하면 모든 것이 객체에 해당한다. 하지만 이런 데이터들 또한 값이 정해진 객체로 취급된다. 

 

2. 객체의 프로퍼티 참조


객체이름.프로퍼티이름


프로퍼티(property)는 객체 지향 프로그래밍 언어에서 필드와 메소드 간 기능의 중간인 클래스 멤버의 유형으로, 쉽게 말해 객체와 연관된 값을 담고 있는 ‘변수’를 말한다.

객체에 포함된 프로퍼티는 객체라는 공통점을 가지고, 이 객체가 가진 특성을 값으로 할당하고 있다. 이에 객체에 할당된 데이터는 프로퍼티라는 상자에 담겨서 구조화된다.

하나의 변수를 객체로 만들어 다양한 데이터를 담고 싶다면 객체에 데이터를 담는 프로퍼티를 설정할 수 있다.

어렵게 보일 수 있으나 쉽게 말해 사람이라는 변수에 이름, 생년월일 등의 데이터를 직접 할당하는 것을 말한다.

이 프로퍼티에는 메소드 또한 담을 수 있다. 

 

var person = {
    name: "홍길동",      // 이름 프로퍼티를 정의함.
    birthday: "030219",  // 생년월일 프로퍼티를 정의함.
    pId: "1234567",      // 개인 id 프로퍼티를 정의함.
    fullId: function() { // 생년월일과 개인 id를 합쳐서 주민등록번호를 반환함.
        return this.birthday + this.pId;
    }
};
person.name    // 홍길동
person["name"] // 홍길동

 

이렇게 선언한 객체 데이터에 접근하는 방법은 접근하려는 데이터에 따라 . 을 통해 경로를 설정하는 것이다.

쉽게 말해 person.name 이라고 하면 person 변수에 생성된 name이라는 데이터에 접근할 수 있다.

메소드 또한 마찬가지다.

해당 접근 방법은 추후 다룰 DOM에서도 매우 중요한 개념이다. [  .  ] 이 ~안에 라는 의미임을 기억하자.

 

3. 객체의 생성

객체를 생성하는 방법은 위와 같이 변수를 선언해서 각각의 프로퍼티를 설정하는 방법이 있고 혹은 생성자 함수나 Objectcreate() 메소드를 이용하여 생성할 수 있다.

 

1) 리터럴 표기를 이용한 객체 생성

var 객체이름 = {
    프로퍼티1이름 : 프로퍼티1의값,
    프로퍼티2이름 : 프로퍼티2의값,
    ...
};

 

2) 생성자를 이용한 객체의 생성

new 연산자를 이용하여 객체를 생성하고 초기화 할 수 있다. 이때 사용되는 메소드를 생성자라고 하며, 이 메소드는 새롭게 생성되는 객체를 초기화한다.

자바스크립트는 이렇게 생성할 수 있는 데이터(객체)를 제공하고 있으며, 만약 내가 사용 혹은 구축하려는 객체가 자바스크립트가 이미 정의한 객체 데이터와 같으면 이를 사용하면된다.

 

var day = new Date(); // new 연산자를 사용하여 Date 타입의 객체를 생성함.
document.write("올해는 " + day.getFullYear() + "년입니다.");

(위 코드는 TCP 스쿨의 예제를 보면서 연습할 때 사용한 코드이다)

 

물론 사용자가 직접 객체 생성자 함수를 작성하여 사용하는 것 또한 가능하다.

이렇게 생성자를 만들어 놓으면 동일한 데이터를 다수의 사용자에게 받거나 혹은 설정해야할 때 더욱 편리하다. 

 

3) Object.create() 메소드를 이용한 객체의 생성

Object.create() 메소드는 지정된 프로토타입(prototype) 객체와 프로퍼티를 가지고 새로운 객체를 만들어 준다.

사용자가 프로토타입 객체를 직접 명시할 수 있어 유용하게 사용되고 있다. 

 
Object.create(프로토타입객체[, 새로운객체의프로퍼티1, 새로운객체의프로퍼티2, ...]);;

 

미리 만들어둔 프로토타입객체가 존재한다면 이를 대입해도 되지만 null로 설정하는 것 또한 가능하다.

그리고 객체의 프로퍼티를 설정하여 객체 데이터를 만들 수 있다. 

 

 
var obj = Object.create(null, {             // null 프로토타입을 사용하여 새로운 객체를 만들고
    x: { value: 100, enumerable: true },    // x좌표를 나타내는 열거할 수 있는 프로퍼티와
    y: { value: 200, enumerable: true }     // y좌표를 나타내는 열거할 수 있는 프로퍼티를 추가함.
});
obj.x;                      // x좌표
obj.y;                      // y좌표 
Object.getPrototypeOf(obj); // 객체의 프로토타입을 반환해 줌.

(위 코드는 TCP 스쿨의 예제를 보면서 연습할 때 사용한 코드이다)

 

4. 상속

상속은 새로운 클래스에 기존 클래스의 프로퍼티와 메소드를 사용하는 것을 말한다.

부모와 자식의 관계로 표현되기도 하며 부모 클래스의 데이터를 자식 클래스가 고스란히 물려받는다.

클래스 사이는 독립적인 형태이므로 자식클래스의 데이터를 수정한다고 부모 클래스의 데이터가 수정되지는 않는다. 

 

 상속을 이용하면 객체의 관계를 조직하는 것이 가능하다.

C++이나 Java와 같은 클래스 기반의 객체 지향 언어와는 다르게 자바스크립트는 ‘프로토타입 기반 객체 지향 언어’이다.

프로토 타입을 기준으로 하기때문에 클래스 기반의 상속과는 상이하다. 

 

 자바스크립트는 현재 존재하고 있는 객체를 프로토타입으로 사용하여, 해당 객체를 복제하여 재사용하는 것을 상속이라고 한다.

 

5. 프로토타입(prototype)

자바스크립트의 모든 객체는 ‘프로토타입’이라는 객체를 가지고 있다.

모든 객체는 그들의 프로토타입으로부터 프로퍼티와 메소드를 상속받는다.

자바스크립트의 모든 객체는 최소한 하나 이상의 다른 객체로부터 상속을 받고, 이때 상속되는 정보를 제공하는 객체가 프로토타입이다. 

 

1) 프로토타입 체인(prototype chain)

자바스크립트에서는 객체 이니셜라이저를 사용하여 생성된 같은 타입의 객체들은 모두 같은 프로토타입을 가진다.

new 연산자를 이용해 생성한 객체는 생성자의 프로토타입을 자신의 프로토타입으로 상속받는다. 

 

var obj = new Object(); // 이 객체의 프로토타입은 Object.prototype
var arr = new Array();  // 이 객체의 프로토타입은 Array.prototype
var date = new Date();  // 이 객체의 프로토타입은 Date.prototype

(위 코드는 TCP 스쿨의 예제를 보면서 연습할 때 사용한 코드이다)

 

하지만 Object.prototype 객체는 어떠한 프로토타입도 가지지 않으며, 아무런 프로퍼티도 상속받지 않는다.

또한, 자바스크립트에 내장된 모든 생성자나 사용자 정의 생성자는 바로 이 객체를 프로토타입으로 가진다.

 

var date = new Date(); // 이 객체는 Date.prototype 뿐만 아니라 Object.prototype도 프로토타입으로 가진다

 

위와 같이 프로토타입이 상속되는 가상의 연결 고리를 프로토타입 체인이라고 한다.

Object.prototype 객체는 이러한 프로토타입 체인에서 가장 상위에 존재한다.

따라서, 자바스크립트의 모든 객체는 Object.prototype 객체를 프로토타입으로 상속받는다.

 

2) 프로토타입의 생성

프로토타입을 생성하는 가장 기본적인 방법은 객체 생성자 함수를 작성하는 것이다.

생성자 함수를 작성하고 new 연산자를 사용해 객체를 생성하면 같은 프로토타입을 가지는 객체들을 생성할 수 있다. 

 

function Dog(color, name, age) { // 개에 관한 생성자 함수를 작성함.
    this.color = color;          // 색에 관한 프로퍼티
    this.name = name;            // 이름에 관한 프로퍼티
    this.age = age;              // 나이에 관한 프로퍼티
}
var myDog = new Dog("흰색", "마루", 1); // 이 객체는 Dog라는 프로토타입을 가짐.
document.write("우리 집 강아지는 " + myDog.name + "라는 이름의 " + myDog.color + " 털뭉치같은 강아지");

(위 코드는 TCP 스쿨의 예제를 보면서 연습할 때 사용한 코드이다)

 

3) 객체에 프로퍼티 및 메소드 추가

function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
}
var myDog = new Dog("흰색", "마루", 1);
myDog.family = "시베리안 허스키"; // 품종에 관한 프로퍼티를 추가함.
myDog.breed = function() {   // 털색을 포함한 품종을 반환해 주는 메소드를 추가함.
    return this.color + " " + this.family;
}
document.write("우리 집 강아지는 " + myDog.breed() + "입니다.");

(위 코드는 TCP 스쿨의 예제를 보면서 연습할 때 사용한 코드이다)

 

이미 생성된 객체에 변수 혹은 메소드를 추가하려면 해당 객체를 생성하고 추가하고자하는 프로퍼티를 설정하면 된다.

메소드 또한 마찬가지이다.

 

4) 프로토타입에 프로퍼티 및 메소드 추가

function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
    this.family = "시베리안 허스키"; // 프로토타입에 프로퍼티를 추가할 때에는 기본값을 가지게 할 수 있음.
    this.breed = function() {
        return this.color + " " + this.family;
    };
}
var myDog = new Dog("흰색", "마루", 1);
var hisDog = new Dog("갈색", "콩이", 3);
document.write("우리 집 강아지는 " + myDog.family + "이고, 친구네 집 강아지도 " + hisDog.family + "입니다.");

(위 코드는 TCP 스쿨의 예제를 보면서 연습할 때 사용한 코드이다)

 

만약 생성된 객체에 모두 동일하게 프로퍼티를 추가하고 싶다면 프로토타입에 해당 프로퍼티를 추가해야한다.

프로토타입에서 프로퍼티가 추가되면, 객체는 프로토타입을 복사하는 것이므로 데이터가 모두 적용된다.

 

5) prototype 프로퍼티

function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
}
// 현재 존재하고 있는 Dog 프로토타입에 family 프로퍼티를 추가함.
Dog.prototype.family = "시베리안 허스키";
// 현재 존재하고 있는 Dog 프로토타입에 breed 메소드를 추가함.
Dog.prototype.breed = function() {
    return this.color + " " + this.family;
};
var myDog = new Dog("흰색", "마루", 1);
var hisDog = new Dog("갈색", "콩이", 3);
 
document.write("우리 집 강아지는 " + myDog.family + "이고, 친구네 집 강아지도 " + hisDog.family + "입니다.");
document.write("우리 집 강아지의 품종은 " + myDog.breed() + "입니다.<br>");
document.write("친구네 집 강아지의 품종은 " + hisDog.breed() + "입니다.");

(위 코드는 TCP 스쿨의 예제를 보면서 연습할 때 사용한 코드이다)

 

prototype 프로퍼티를 이용하면 현재 존재하고 있는 프로토타입에 새로운 프로퍼티나 메소드를 추가할 수 있다.

 

 

6. 객체 다루기

1) this 

자바스크립트에서 this 키워드는 해당 위치의 상위 객체를 말한다.

체 내부에서 사용된 키워드는 해당 객체를 자신을 가리키는 것이다. 

 

2) 객체 프로퍼티의 삭제

객체의 프로퍼티는 삭제가 가능하다. delete 키워드를 사용하여 객체에 포함된 값인 프로퍼티를 삭제할 수 있다.

주의할 것은 값만 제거하는 것이 아니라 프로퍼티 자체가 삭제된다. 

 

function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
}
var myDog = new Dog("흰색", "마루", 1);
delete myDog.age; // age 프로퍼티를 삭제함.
// age 프로퍼티가 삭제되었기 때문에 undefined를 출력함.
document.write("우리집 강아지의 나이는 " + myDog.age + "입니다.");

(위 코드는 TCP 스쿨의 예제를 보면서 연습할 때 사용한 코드이다)

 

3) 객체 프로퍼티의 순회

객체의 프로퍼티는 배열과 같이 하나의 객체 내에 포함된 다수의 데이터이다.

때문에 for 혹은 in 문을 이용하여 객체의 프로퍼티 정보를 확인할 수 있다.

혹은 이미 정의된 메소드를 이용하여 프로퍼티와 해당 프로퍼티의 값을 확인할 수 있다.

 

function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
}
var myDog = new Dog("흰색", "마루", 1);
 
// color 프로퍼티의 enumerable 속성을 false로 설정함.
Object.defineProperty(myDog, 'color', {enumerable : false} );
// 객체가 가진 고유 프로퍼티 중에서 열거할 수 있는 프로퍼티 이름을 배열에 담아 반환함.
document.write(Object.keys(myDog) + "<br>");       // name, age
// 객체가 가진 모든 고유 프로퍼티의 이름을 배열에 담아 반환함.
document.write(Object.getOwnPropertyNames(myDog)); // color, name, age

(위 코드는 TCP 스쿨의 예제를 보면서 연습할 때 사용한 코드이다)

 

4) 객체간의 비교

 자바스크립트에서 별개의 두 객체는 프로퍼티의 값이 모두 같아도 객체가 완전히 같다고 할 수 없다.

이는 객체가 기본적으로 객체에 저장된 ‘주소 값’을 참조하여 데이터를 추출하기 때문이다.

다르게 말하자면 객체가 완전히 동일한 데이터를 가지고 있어도 객체의 이름이 다르다면 각각 다른 주소값으로 데이터를 참조하는 것이다.

때문에 객체 자체는 아무리 프로퍼티가 같아도 동일한 데이터가 아니다. 다만 프로퍼티의 값을 비교하면 다른 객체일지라도 프로퍼티의 값이 동일하면 데이터 자체는 같다고 할 수 있다.

 

 

7. 객체 메소드(method)

메소드 모양 내용
hasOwnProperty() hasOwnProperty() 메소드는 특정 프로퍼티가 해당 객체에 존재하는지를 검사한다.
해당 객체에서 직접 선언된 프로퍼티만을 검사하며, 같은 이름의 프로퍼티라도 상속받은 프로퍼티는 false 값을 반환한다.
propertyIsEnumerable() propertyIsEnumerable() 메소드는 특정 프로퍼티가 해당 객체에 존재하고, 열거할 수 있는 프로퍼티인지를 검사한다.
isPrototypeOf() isPrototypeOf() 메소드는 특정 객체의 프로토타입 체인에 현재 객체가 존재하는지를 검사한다.
isExtensible() isExtensible() 메소드는 객체에 새로운 프로퍼티를 추가할 수 있는지 여부를 반환한다.
기본적으로 모든 객체는 새로운 프로퍼티를 추가할 수 있으나 ,
preventExtensions() 메소드를 이용하여 프로퍼티 추가가 불가능하도록 설정할 수 있기 때문에 프로퍼티 추가 여부를 확인할 필요가 있다.
toString() toString() 메소드는 이 메소드를 호출한 객체의 값을 문자열로 반환한다.
valueOf() valueOf() 메소드는 특정 객체의 원시 타입(primitive type)의 값을 반환한다.
자바스크립트에서는 원시 타입의 값이 기대되는 곳에 객체가 사용되면, 내부적으로 이 메소드를 호출하여 처리한다. 

만약 어떤 객체가 원시 타입의 값을 가지고 있지 않다면, 이 메소드는 객체 자신을 반환한다.

 

 

8. getter와 setter 메소드의 정의

게터와 세터는 특정 프로퍼티 값을 호출하거나 설정하는 용도로 사용한다.

변수의 스코프 혹은 접근 권한 등의 문제로 변수 자체에 접근이 어려울 때 사용한다.

JAVA의 경우 접근 권한이 설정되지만 자바스크립트의 경우, 특정 블록에서 처리한 지역변수를 전역으로 끌어오고 싶을 때 사용할 수 있다. 

물론 프로퍼티의 값 자체를 가져오는 것도 가능하다. 

 

1) Getter

var gildong = { age: 18 };
document.write(gildong.age + "<br>"); // 18
 
Object.defineProperty(gildong, "americanAge", { get: function() { return this.age - 1; } });
document.write(gildong.americanAge); // 17

 

2) Setter

var gildong = { age: 18 };
gildong.age = 20;
document.write(gildong.age + "<br>"); // 20
 
Object.defineProperty(gildong, "changeAge", { set: function(n) { this.age = this.age - n; } });
gildong.changeAge = 5;
document.write(gildong.age); // 15