10-1. 객체란?
자바스크립트를 공부해오면서 정말로 많이 들었던 말이 객체라는 단어다. 이유는 잘 몰랐지만 객체기반의 프로그래밍 언어라고 알고 있었고, 자바스크립트를 구성하는 거진 모든 것이 객체라고 한다. (원시값을 제외한 나머지 값이 객체) 그렇다면 객체는 무엇일까?
원시 타입은 단 하나의 값만 나타내지만 객체 타입은 다양한 타입의 값 (원시 값 또는 다른 객체)을 하나의 단위로 구성한 복합적인 자료구조(data structure)라고 한다. 객체 내부값은 변경이 가능한데, 이는 11장에서 좀 더 자세히 다뤄보도록 하자.
객체는 0개 이상의 프로퍼티로 구성된 집합이며, 프로퍼티는 키(key) 와 값(value) 로 구성된다.
자바스크립트에서 사용할 수 있는 모든 값은 프로퍼티 값이 될 수 있다. 위 그림처럼 키와 값으로 구성된 부분을 프로퍼티라고 한다. 만일 프로퍼티 값이 함수라면 일반 함수와 좀 구별을 짓기 위해 메서드(method) 라고 칭하기로 했다.
이렇게 프로퍼티와 메서드로 구성된 집합체를 객체라고 할 수 있겠다. 각각의 역할은 다음과 같다
- 프로퍼티: 객체의 상태를 나타내는 값
- 메서드 : 프로퍼티(상태 데이터)를 참조하고 조작할 수 있는 동작(behavior)
쉽게 생각해 프로퍼티는 값이며, 메서드는 그 객체내의 프로퍼티를 참조하여 동작하게 된다. 한마디로 상태와 동작이 같이 있다고 할 수 있겠다.
10-2. 객체 리터럴에 의한 객체 생성
자바스크립트는 다양한 객체 생성 방법을 지원한다. 여러가지가 존재하는 데 그 중에서 가장 친숙하게 객체를 생성하는 방식은 객체 리터럴을 활용하는 것이다. 리터럴은 앞에서 살펴보았듯이 인간이 이해할 수 있는 기호를 사용하여 값을 생성하는 표기법이다. 역시나 객체 리터럴도 객체를 생성하기위한 일종의 약속된 기호 표기법이라 생각하면 된다.
var person = {
name: "Lee",
sayHello: function(){
console.log(this.name);
}
};
console.log(person); // { name: "Lee", sayHello: f }
// 빈 객체
var empty = {};
위에 this 는 객체 person 을 가리킨다. this 역시 전역과 지역으로 나뉘기도 하고, 이에 따른 함수 선언도 달라질 수 있어 자세한것은 this 파트에서 더 알아보도록 하자.
특이점은 객체 중괄호 마지막에 세미콜론을 붙이는데, 이유는 객체는 값으로 평가받는 표현식이기 때문이다. 종료의 의미가 아니다.
10-3. 프로퍼티
- 프로퍼티 키 : 빈 문자열을 포함하는 모든 문자열 또는 심벌 값
- 프로퍼티 값: 자바스크립트에서 사용할 수 있는 모든 값
프로퍼티를 나열할때는 쉼표로 구별하고, 마지막 프로퍼티에는 붙이던 안붙이던 관계는 없다.
객체는 프로퍼티의 집합이라 할 수 있기에, 프로퍼티에 접근 하는 방식 또한 여러가지가 있다. 보통 접근을 할 때는 프로퍼티의 키를 통해서 접근을 하게 되는데, 그렇기에 키의 네이밍을 규칙에 맞게 작성하는것이 유리하다. 왜냐하면 규칙에 맞게 작성 시 키를 불러올 수 있는 루트 자체가 다양해지기 때문이다. 굳이 안맞게 작성하지말고 최대한 규칙에 맞게 작성을 하자.
일반적으로 키 값은 문자열을 사용하기 때문에, "" 을 붙여줘야 하지만 규칙을 따르면 이를 지키지 않아도 된다. 반대로 얘기하면 식별자 규칙을 따르지 않는다면 반드시 "" 을 붙여주어야 한다.
var person = {
firstName: "ddd",
'last-name': "choi",
}
console.log(person); // { firstName: "ddd", last-name: "choi" }
// 만일 따옴표를 생략한다면 연산자로 해석을 해버린다.
var person = {
last-name: "choi", // syntaxError: Unexpected token -
};
last-name 은 식별자 규칙이 지켜지지 않은 네이밍이기에 따옴표를 추가해주어야 제대로 작동한다. 붙이지 않는다면 중간의 - 를 연산자로 파악하여 에러를 발생하게 된다.
다음, 문자열 혹은 문자열로 평가할 수 있는 표현식을 사용해 프로퍼티 키를 동적으로 생성할수도 있다. 대괄호로 묶어서 사용하고 아래 예시를 참고하자
var obj = {};
var key = "hello";
obj[key] = "world";
console.log(obj);
// { hello: "world" }
키값에는 빈 문자열을 사용할 수도 있고, 숫자를 사용하면 암묵적으로 문자열로 타입 변경을 시켜준다. 또한 var, function. 과 같은 예약어도 키값으로 설정해줄 수 있다. 또한 중복 선언도 오류를 일으키지 않는다.
다만, 예상했다싶이 이렇게 키값을 설정하는것은 프로그래밍을 하는 입장에서 하나도 도움되는 점이 없다. 객체의 프로퍼티 키값을 설정해줄 때는 최대한 규칙에 맞게 설정을 하며, 의미를 가지는 네이밍을 하도록 하자.
10-4. 메서드
프로퍼티가 다른 프로퍼티의 값에 동적 변화르 줄 수 있는 것을 메서드라고 하였다. 앞서서 프로퍼티의 값에는 자바스크립트에서 사용할 수 있는 모든 값을 사용할 수 있다고 하였다. 과연 함수도 값인가? 그래야만 이 정의가 성립하게 된다.
나중에 함수 파트에서 설명이 나오겠지만 자바스크립트의 함수는 일급 객체라고 한다. 객체 역시 값으로 취급할 수 있기 때문에 프로퍼티의 값으로 사용이 가능하다. 메서드의 첫 객체설명의 코드에서 확인할 수 있다.
10-5. 프로퍼티 접근
객체를 생성하였으니 그 내부 프로퍼티에 접근할 수 있어야 의미가 있다. 접근하는 방법은 크게 2가지로 나뉘게 된다.
- 마침표 프로퍼티 접근 연산자(.)를 사용하는 마침표 표기법(dot notation)
- 대괄호 프로퍼티 접근 연산자([ ... ])를 사용하는 대괄호 표기법(braket notation)
차이점은 마침표 프로퍼티 접근방식은 네이밍 규칙을 따른 키값에만 적용이 가능하고, 동적 변화를 줄 수는 없다. 반면 대괄호 프로퍼티 접근방식은 모두 사용 가능하다.
var person = {
name: "Lee",
}
console.log(person.name); // "Lee"
console.log(person["name"]); // "Lee"
console.log(person[name]); //ReferenceError: name is not defined
console.log(person.age); // undefined
주의할 점은 대괄호 접근방식 시 따옴표를 써주어야 한다. 안쓰면 변수 name 을 찾으려고 하기 떄문이다. 위 오류 메세지를 보면 알 수 있다. 또한 객체 내부에 없는 키값을 접근하려 하면 undefined 가 뜬다. 이게 에러가 아니라 undefined 를 반환하는것이 참 안좋다. 에러가 나면 사람이 인지를 할 수 있는데, undefined 를 반환을 해버리니 에러발생이 아니게 된다.
&&참고
var person = { 'last-name' : 'Lee', 1: 10, }; person.'last-name'; // SyntaxError: Unexpected string person.last-name; // 브라우저 환경: NaN // node.js 환경 : ReferenceError: name is not defined person.1; // SyntaxError: Unexpected number; person[1]; // 10 (따옴표 생략가능)
우선 숫자의 경우 대괄호 접근 시 따옴표를 생략할 수 있다.
그리고 왜 브라우저 환경과 node.js 환경의 에러가 다르게 나오는 것일까? 앞서 살펴본 바에 의하면 name 이라는 선언자를 찾는다고 했었는데, 브라우저 환경에서는 ReferenceError 가 뜨지 않는다.
그렇다면 name 이라는 선언자가 이미 있다는 이야기인데, 실제로 그러하다. 브라우저에서는 전역 변수로서 name 이 존재를 하고 있다. 기본값은 빈 문자열이다. 따라서 last-name 은 undefined - '' 가 되기 때문에 NaN 을 띄우는 것이다.
객체의 접근 방식 외 객체 내 값 갱신, 프로퍼티 생성 및 삭제는 다음과 같다.
var person = {
name: "Lee",
};
// 갱신
person.name = "choi";
// 생성
person.age = 20;
// 삭제
delete person.age;
// 없는 프로퍼티르 삭제하려 한다면 그냥 무시한다. 에러가 뜨지 않는다
delete person.address; // 무시
참고 : ES6 에서 추가된 객체 리터럴의 메서드 축약 표현
프로퍼티 축약 부터, 계산된 프로퍼티 이름 등 추가된 부분이 있지만, 개인적으로 가장 편리하다 할 수 있는 부분이라면 메서드의 축약 표현이 아닐까싶다.
//ES5
var obj = {
name: "Lee",
sayHi: function(){
console.log('Hi! ' + this.name);
}
};
obj.sayHi();
//ES6
const obj = {
name: 'Lee',
// 메서드 축약 표현
sayHi(){
console.log('Hi ' + this.name);
}
};
obj.sayHi();
기존과 달리 키값을 축약하여 fucntion 을 생략하여 사용할 수 있다.
자바스크립트를 공부하면 서 애를 먹게 했던 부분은 객체파트였다. 뭔가 접근하는 메서드도 낯설고, 저장 형식 자체도 낯선느낌이 많이 있었다. 지금 포스팅 한 글에서는 객체에 일부를 설명한 것일 뿐, 자바스크립트에서 가지고 있는 성질들에 대해서는 추후에 좀 더 공부할 것이다.
글을 정리하면서 이전에 기억으로 남아있던 객체의 프로퍼티와 메서드, 그리고 프로퍼티 키의 네이밍 방식과 값의 접근 방식에 대해 다시 한번 상기한 계기가 된 것 같다.
다음에는 자바스크립트의 원시 타입과 객체 타입간의 차이에 대해 다뤄보겠다.
'Programing > Javascript' 카테고리의 다른 글
[Deep Dive] 함수 (0) | 2022.10.27 |
---|---|
[Deep Dive] 원시값과 객체 (0) | 2022.10.25 |
[Deep Dive] 타입 변환과 단축 평가 (0) | 2022.10.22 |
[Deep Dive] 제어문 (0) | 2022.10.21 |
[Deep Dive] 연산자 (0) | 2022.10.19 |