자바스크립트에서는 원시 값 빼고는 모두 객체로 사용된다.
즉, 함수, 정규 표현식, 배열 등 모두 객체로 구성되어있다. 또한, 객체는 원시 값과는 달리 immutable이 아닌, mutable한 값이다. 이는 추후에 다시 배워보도록 하자
자바스크립트에서의 객체 표현은 다음과 같다.
var person = {
name: 'lee', // key - value
age : 20 // key - value
}
person이라는 객체를 생성한 것이다. 객체는 property로 이루어지는데, name : 'lee' 와 age: 20 을 각각 property라고 부른다.
여기서 property는 key : value 형식을 띈다. 재밌는 것은 굳이 변수를 선언한다는 var, let을 써주지 않아도 된다는 것이다.
위의 예시에서 property의 key는 name, age이고 property의 값은 'lee'와 20이 되는 것이다.
즉, key로 접근하고 value를 받거나 변경하는 것이다.
property 값이 될 수 있는 대상은 자바스크립에서 사용되는 모든 값들이 가능하다.
즉, 함수도 배열도 원시 타입 값도 모두 가능하다는 것이다.
var counter = {
num : 0, //property -> 상태값
increase : function(){
this.num++;
} // 메서드
}
increase가 key가 되고, value는 function으로 this.num을 하나씩 더해준다.
이에 따라 객체지향관점에서 객체의 함수를 일반 함수들과 구분하기위해 메서드라고 표현하듯이 여기서도 메서드라고 표현한다.
또한, property는 좀 더 구체적으로 나누어 상태값으로 생각한다.
counter의 num이 바로 객체의 상태값이 되는 것이다.
객체를 생성하는 방법은 굉장히 많다.
1. 객체 리터럴
2. Object 생성자 함수
3. 생성자 함수
4. Object.create메서드
5. 클래스(es6)
위의 객체 생성 방식 중에 가장 일반적이고 쉬운 방법이 객체 리터럴이다.
리터럴이란 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용하여 값을 생성하는 표기법을 말한다.
객체 리터럴은 중괄호 {} 을 사용하여 0개 이상의 프로퍼티를 정의하면 된다.
변수에 할당되는 시점에 자바스크립트 엔진은 객체 리터럴을 해석해 객체를 생성한다.
var empty = {};
var person = {
name : 'lee',
hello : function(){
console.log('hello');
}
};
console.log(empty) // {}
console.log(person) // { name: 'lee', hello: [Function: hello] }
객체 리터럴의 중괄호는 코드 블록을 의미하지 않는다. 함수나 if문 같은 중괄호 블럭에는 세미콜론(;)을 붙이지 않지만, 객체 리터럴에는 붙여줄 수 있다.
가장 큰 이유는 객체 리터럴은 값이기 때문이다.
이렇게 객체리터럴을 생성하는 것이 어떤 장점이 있을까??
자바의 경우를 생각해보자, 아무리 간단한 객체라도 class를 정의해놓고 new를 해야한다. 그러나 객체 리터럴은 아주 간단하게 객체를 생성할 수 있다. 또한 객체를 생성한 이후에 프로퍼티를 동적으로 추가할 수도 있다.
객체 리터럴 방식 이외에는 모두 함수를 이용한 객체 생성 방법을 취한다. 이에 대해서는 이후에 알아보자
객체는 프로퍼티의 집합이며 , 프로퍼티는 key - value로 구성된다.
var person = {
name : 'lee',
age : 20
}
프로퍼티를 사용할 때는 쉼표(,)로 구분한다. 일반적으로 마지막 프로퍼티 뒤에는 쉼표를 사용하지 않으나 사용해도 된다.
프로퍼티의 키와 값으로 사용할 수 있는 것들은 다음과 같다.
- property key : 빈 문자열을 포함하는 모든 문자열 또는 심벌값
- property value : 자바스크립트의 모든 값
중요한 것은 프로퍼티 값에 접근할 수 있는 식별자 역할을 key가 해준다는 것이다.
심벌 값도 프로퍼티 키로 사용할 수 있지만, 일반적으로 문자열을 사용한다. 이 때 프로퍼티 키는 문자열이므로 '' , "" 로 감싸야 한다.
그런데, 자바스크립트에서 사용 가능한 유효한 이름인, 네이밍 규칙을 따른다면 따옴표를 생략할 수 있다.
반대로 식별자 네이밍 규칙을 어기면 반드시 따옴표를 사용해야 한다.
var person = {
firstName : 'park-young',
'last-name' : 'Lee'
};
firstName은 네이밍 규칙을 따르기 때문에 따옴표를 생략할 수 있었다.
그러나 'last-name'은 그렇지 않다. 왜냐하면 따옴표가 없다면 - 을 연산자 -로 생각하기 때문이다.
문자열 이외의 값을 사용할 경우, 자동으로 문자열로 암묵적 변환을 하게 된다.
즉, 키로 숫자나 심벌을 사용하면 문자열로 바꾸어 준다는 것이다.
var foo = {
0 : 1,
1 : 2,
2 : 3
}
console.log(foo) // { '0': 1, '1': 2, '2': 3 }
또한, 동적으로 key-value를 추가할 수도 있다. 이때 []을 이용하여 key-value를 넣어줄 수 있다.
var obj = {};
var key = 'hello';
obj[key] = 'world';
console.log(obj); //{ hello: 'world' }
주의 할 점
1. key로 var, function과 같은 keyword를 사용할 수 있지만 권장하지않는다.
2. key가 중복되면 먼저 선언한 property value를 덮어쓴다.
프로퍼티에 접근할 수 있는 방법으로는 두 가지가 있다.
마침표 표기법은 c에서는 구조체, c++/java에서는 일반적으로 객체에서 맴버 변수나 메서드에 접근할 때 사용하는 방법이다.
대괄호 표기법은 위에서 사용한 방식으로 c/c++, java에서 hashMap을 사용할 때 주로 사용하는 방법이다. 위에서 언급한 것과 같이 key는 문자열로 바뀌므로 문자열을 적어주어야 한다.
var person = {
name : 'lee'
};
console.log(person.name); // lee
console.log(person['name']); // lee
만약 대괄호 표기법을 사용하는데, 문자열로 적어주지 않는다면 식별자로 생각하여 변수인 줄 알고 에러를 뱉는다.
참고로, 객체에 없는 property에 접근하려고 한다면 에러가 아닌 undefined가 발생한다. 이는 c++에서 map을 사용해보았다면 익히 보았을 경우이다.
추가적으로 어떤 것은 대괄호 표기법으로 호출이 되는데, 어떤 것들은 마침표 표기법으로는 호출이 안되는 경우가 있다.
var person = {
'last-name' : 'park'
};
console.log(person.last-name) // error
console.log(person['last-name'])
다음과 같이 일반적인 자바스크립트 property key 네이밍 규칙을 지키지 않으면 마침표 연산자로 불러올 때 에러가 발생하므로 네이밍 규칙을 지켜주는 것이 좋다.
만약 없는 프로퍼티에 접근하여 값을 넣어준다면, 이는 프로퍼티를 동적으로 생성하는 경우가 된다.
var person = {
name : 'lee'
};
person.age = 20;
console.log(person) // { name: 'lee', age: 20 }
삭제는 delete 연산자를 이용하여 객체의 프로퍼티를 삭제할 수 있다.
만약, 삭제할 값이 존재하지 않는다해도 에러를 뱉진 않는다.
var person = {
name : 'Lee'
}
person.age = 20;
delete person.age;
delete person.address;
console.log(person); // name: 'Lee' }
프로퍼티 축약 표현
말 그대로 프로퍼티를 적어줄 때 축약하여 표현할 수 있다는 것이다. 굳이 key - value를 이쁘게 적어줄 필요가 없다는 것이다.
let x = 1;
let y = 2;
const obj = {x, y};
console.log(obj); // { x: 1, y: 2 }
변수명은 자동으로 key가 되고, 해당 변수의 값이 자동으로 property value가 되는 것이다.
계산된 프로퍼티 이름
문자열 또는 문자열로 타입 변환할 수 있는 값으로 평가되는 표현식을 사용해 프로퍼티 키를 동적으로 생성할 수 있다. 단, 프로퍼티 키로 사용할 표현식을 대괄호 [] 로 묶어야 한다.
es5에서는 객체 생성 이후에나 해줄 수 있었지만, es6에서는 객체 리터럴 내부에서 가능하다.
var prefix = 'prop';
var i = 0;
var obj = {};
obj[prefix + '-' + ++i] = i;
obj[prefix + '-' + ++i] = i;
obj[prefix + '-' + ++i] = i;
console.log(obj); // { 'prop-1': 1, 'prop-2': 2, 'prop-3': 3 }
위의 방식이 es5방식이다. 객체 생성 이후에 대괄호로 키를 생성해준 것을 확인할 수 있다.
const prefix = 'prop';
let i = 0;
const obj = {
[`${prefix} - ${++i}`] : i,
[`${prefix} - ${++i}`] : i,
[`${prefix} - ${++i}`] : i
};
console.log(obj); // { 'prop - 1': 1, 'prop - 2': 2, 'prop - 3': 3 }
메서드 축약 표현
es5에서는 메서드를 표현할 때 function() 키워드를 사용해야만 했다. 그러나, es6에서는 function() 키워드를 생략하고 메서드를 생성할 수 있다.
const obj = {
name : 'lee',
sayHello(){
console.log('hi ' + this.name);
}
}
obj.sayHello(); // hi lee
객체 메서드에 대해서는 추후에 더 자세히 다룰 예정이다.