자바스크립트에는 여덟 가지의 자료형이있습니다.
숫자형
- 정수, 부동 소수점 숫자 등의 숫자를 나타낼 때 사용합니다.문자형
- 빈 문자열이나 글자들로 이뤄진 문자열을 나타낼 때 사용합니다.불린형
- true, false를 나타낼 때 사용합니다.객체형
- 복잡한 데이터 구조를 표현할 때 사용합니다.심볼형
- 객체의 고유 식별자를 만들 때 사용합니다.null
- null 값만을 위한 독립 자료형입니다. null
은 알 수 없는 값을 나타냅니다. undefined
- 값만을 위한 독립 자료형입니다. undefined
는 할당되지 않은 값을 나타냅니다.bigint
- 길이나 제약 없이 정수를 나타낼 수 있습니다.이 중 일곱 개는 오직 하나의 데이터 (문자열, 숫자 등)만 담을 수 있어 원시형(primitive type)
이라 부릅니다.
그런데 객체형은 원시형과 달리 다양한 데이터를 담을 수 있습니다. 키로 구분된 데이터 딥합이나 복잡한 개체(entity)를 저장할 수 있죠.
객체는 중괄호{...}
를 이용해서 만들 수 있습니다. 중괄호 안에는 키(key): 값(value)
쌍으로 구성된 프로퍼티(property)를 여러 개 넣을 수 있는데, 키
엔 문자형, 값
엔 모든 자료형이 허용됩니다.
프로퍼티 키는 프로퍼티 이름
이라고도 부릅니다.
서랍장을 상상하면 객체를 이해하기 쉽습니다.
서랍장 안 파일은 프로퍼티
, 파일 각각에 붙어있는 이름표는 객체의 키
라고 생각하시면 됩니다.
복잡한 서랍장 안에서 이름표를 보고 원하는 파일을 쉽게 찾을 수 있듯이, 객체에선 키를 이용해 프로퍼티
를 쉽게 찾을 수 있습니다. 추가나 삭제도 마찬가지입니다.
빈 객체(빈 서랍장)를 만드는 방법은 두 가지가 있습니다.
let user = new Object(); // '객체 생성자' 문법
let user = {}; // '객체 리터럴' 문법
중괄호 {...}
를 이용해 객체를 선언하는 것을 객체 리터럴(obeject literal)이라고 부릅니다. 객체를 선언할 땐 주로 이 방법을 사용합니다.
중괄호 {...}
안에는 키:값
쌍으로 구성된 프로퍼티가 들어갑니다.
let user = { // 객체
name: "John", // 키: "name", 값: "John"
age: 30 // 키: "age", 값: 30
};
콜론(:)
을 기준으로 왼쪽엔 키가, 오른쪽엔 값이 위치합니다.
프로퍼티 이름
혹은 식별자
라고도 부릅니다.
객체 user
에는 프로퍼티가 두 개 있습니다.
name
(이름)과 John
(값)age
(이름)과 30
(값)서랍장(객체 user
)안에 파일 두개(프로퍼티 두개)가 담겨있는데, name
, age
라는 이름표가 붙어있다고 생각하시면 쉽습니다.
서랍장에 파일을 추가하고 뺄 수 있듯이 개발자는 프로퍼티를 추가, 삭제할 수 있습니다.
점 표기법(dot notation)을 이용하면 프로퍼티 값을 읽는 것도 가능합니다.
// 프로퍼티 값 얻기
alert( user.name ); // John
alert( user.age ); // 30
프로퍼티 값엔 모든 자료형이 올 수 있습니다. 불린형 프로퍼티를 추가해봅시다.
user.admin = true;
delete
연산자를 사용하면 프로퍼티를 삭제할 수 있습니다.
delete user.age;
여러 단어를 조합해 프로퍼티 이름을 만든 경우엔 프로퍼티 이름을 "따옴표(""
, ''
)"로 묶어줘야 합니다.
let user = {
name: "John",
age: 30,
"likes birds": true // 복수의 단어는 따옴표로 묶어야 합니다.
};
마지막으로 프로퍼티 끝은 쉼표(,
)로 끝날 수 있습니다.
let user = {
name: "John",
age: 30,
}
이런 쉼표를 trailing(길게 늘어지는)
혹은 hanging(매달리는)
쉼표라고 부릅니다. 이렇게 끝에 쉼표를 붙이면 모든 프로퍼티가 유사한 형태를 보이기 때문에 프로퍼티를 추가, 삭제, 이동하는게 쉬워집니다.
const
로 선언 된 객체는 수정될 수 있습니다. const user = {
name: "John"
};
user.name = "Pete"; // (*)
alert(user.name); // Pete
(*)
로 표시한 줄에서 오류를 일으키는 것처럼 보일 수 있지만 그렇지 않습니다.
const
는 user
의 값을 고정하지만, 그 내용은 고정하지 않습니다.
const
는 user=...
를 전체적으로 설정하려고 할 때만 오류가 발생합니다.
여러 단어를 조합해 프로퍼티 키를 만든 경우엔, 점 표기법을 사용해 프로퍼티 값을 읽을 수 없습니다.
// 문법 에러가 발생합니다.
user.likes birds = true
자바스크립트는 위와 같은 코드를 이해하지 못합니다. user.likes
까지는 이해하다가 예상치 못한 birds
를 만나면 문법 에러를 뱉어냅니다.
점
은 키가 유효한 변수 식별자
인 경우에만 사용할 수 있습니다.
유효한 변수 식별자엔 공백이 없어야합니다. 또한 숫자로 시작하지 않아야하며 $
와_
를 제외한 특수 문자가 없어야합니다.
키가 유요한 변수 식별자가 아닌 경우엔 점 표기법 대신에 대괄호 표기법
이라 불리는 방법을 사용할 수 있습니다. 대괄호 표기법은 키에 어떤 문자열이 있던지 상관없이 동작합니다.
let user = {};
// set
user["likes birds"] = true;
// get
alert(user["likes birds"]); // true
// delete
delete user["likes birds"];
이제 문법 에러가 발생하지 않죠, 대괄호 표기법 안에서 문자열을 사용할 땐 문자열을 따옴표로 엮어줘야합니다.
대괄호 표기법을 사용하면 아래 예시에서 변수를 키로 사용한 것과 같이 문자열뿐만 아니라 모든 표현식의 평가 결과를 프로퍼티 키로 사용할 수 있습니다.
let key = "likes birds";
// user["likes birds"] = true; 와 같습니다.
user[key] = true;
변수 key
는 런타임에 평가되기 때문에 사용자 입력값 변경 등에 따라 값이 변경될 수 있습니다. 어떤 경우든, 평가가 끝난 이후의 결과가 프로퍼티 키로 사용됩니다.
let user = {
name: "John",
age: 30
};
let key = prompt("사용자의 어떤 정보를 얻고 싶으신가요?", "name");
// 변수로 접근
alert( user[key] ); // John (프롬프트 창에 "name"을 입력한 경우)
그런데 점 표기법은 이런 방식이 불가능합니다.
let user = {
name: "John",
age: 30
};
let key = "name";
alert( user.key ) // undefined
객체를 만들 때 객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는 경우, 이를 게산된 프로퍼티(computed property)라고 부릅니다.
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {
[fruit]: 5, // 변수 fruit에서 프로퍼티 이름을 동적으로 받아 옵니다.
};
alert( bag.apple ); // fruit에 "apple"이 할당되었다면, 5가 출력됩니다.
위 에시에서 [fruit]
는 프로퍼티 이름을 변수 fruit
에서 가져오겠다는 것을 의미합니다. 사용자가 프롬프트 대화상자에 apple
을 입력했다면 bag
엔 {apple: 5}
가 할당되었을 겁니다.
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {};
// 변수 fruit을 사용해 프로퍼티 이름을 만들었습니다.
bag[fruit] = 5;
두 방식 중 계산된 프로퍼티를 사용한 예시가 더 깔끔해 보이네요.
실무에선 프로퍼티 값을 기존 변수에서 받아와 사용하는 경우가 종종 있습니다.
function makeUser(name, age) {
return {
name: name,
age: age,
// ...등등
};
}
let user = makeUser("John", 30);
alert(user.name); // John
위 예시의 프로퍼티들은 이름과 값이 변수의 이름과 동일하네요, 이렇게 변수를 사용해 프로퍼티를 만드는 경우는 아주 흔한데, 프로퍼티 값 단축 구문(property value shorthand)을 사용하면 코드를 짧게 줄일 수 있습니다.
name:name
대신 name
만 적어주어도 프로퍼티를 설정할 수 있죠
function makeUser(name, age) {
return {
name, // name: name 과 같음
age, // age: age 와 같음
// ...
};
}
한 객체에서 일반 프로퍼티와 단축 프로퍼티를 함께 사용하는 것도 가능합니다.
let user = {
name, // name: name 과 같음
age: 30
};
아시다시피 변수 이름(키)엔 for
, let
, return
같은 예약어를 사용하면 안됩니다.
그런데 객체 프로퍼티엔 이런 제약이 없습니다.
// 예약어를 키로 사용해도 괜찮습니다.
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 6
이와 같이 프로퍼티 이름엔 특별한 제약이 없습니다. 어떤 문자형, 심볼형 값도 프로퍼티 키가 될 수 있죠
자바스크립트 객체의 중요한 특징 중 하나는 다른 언어와는 달리, 존재하지 않는 프로퍼티에 접근하려 해도 에러가 발생하지 않고 undefined
를 반환한다는 것입니다.
이런 특징을 응용하면 프로퍼티 존재 여부를 쉽게 확인할 수 있습니다.
let user = {};
alert( user.noSuchProperty === undefined );
// true는 '프로퍼티가 존재하지 않음'을 의미합니다.
이렇게 undefined
와 비교하는 것 이외에도 연산자 in을 사용하면 프로퍼티 존재 여부를 확인할 수 있습니다.
문법은 다음과 같습니다.
"key" in object
let user = { name: "John", age: 30 };
alert( "age" in user ); // user.age가 존재하므로 true가 출력됩니다.
alert( "blabla" in user ); // user.blabla는 존재하지 않기 때문에 false가 출력됩니다.
in
왼쪽엔 반드시 프로퍼티 이름이 와야 합니다. 프로퍼티 이름은 보통 따옴표로 감싼 문자열입니다.
따옴표를 생략하면 아래와 같이 엉뚱한 변수가 조사 대상이 됩니다.
let user = { age: 30 };
let key = "age";
alert( key in user ); // true, 변수 key에 저장된 값("age")을 사용해 프로퍼티 존재 여부를 확인합니다.
그런데 이쯤 되면 "undefined
랑 비교해도 충분한데 왜 in
연산자가 있는 거지?"라는 의문이 들 수 있습니다.
대부분의 경우, 일치 연산자를 사용해서 프로퍼티 존재 여부를 알아내는 방법 (=== undefined
)은 꽤 잘 동작합니다. 그런데 가끔은 이 방법이 실패할 때도 있습니다. 이럴 때 in
을 사용하면 프로퍼티 존재 여부를 제대로 판별할 수 있습니다.
프로퍼티는 존재하는데, 값에 undefined
를 할당한 경우
let obj = {
test: undefined
};
alert( obj.test ); // 값이 `undefined`이므로, 얼럿 창엔 undefined가 출력됩니다. 그런데 프로퍼티 test는 존재합니다.
alert( "test" in obj ); // `in`을 사용하면 프로퍼티 유무를 제대로 확인할 수 있습니다(true가 출력됨).
obj.test
는 실제 존재하는 프로퍼티입니다. 따라서 in
연산자는 정상적으로 true를 반환합니다.
undefined
는 변수는 정의되어 있으나 값이 할당되지 않은 경우에 쓰기 때문에 프로퍼티 값이 undefiend
인 경우는 흔치않습니다.
for...in
반복문을 사용하면 객체의 모든 키를 순회할 수 있습니다.
for..in
은 앞서 학습했던 for(;;)
반복문과는 완전히 다릅니다.
for (key in object) {
// 각 프로퍼티 키(key)를 이용하여 본문(body)을 실행합니다.
}
let user = {
name: "John",
age: 30,
isAdmin: true
};
for (let key in user) {
// 키
alert( key ); // name, age, isAdmin
// 키에 해당하는 값
alert( user[key] ); // John, 30, true
}
for..in
반복문에서도 for(;;)
문 처럼 반복 변수(looping variable
)를 선언(let key)했다는 점에 주목해 주시길 바랍니다.
반복 변수명은 자유롭게 정할 수 있습니다. for(let prop in obj)
같이 key
말고 다른 변수명을 사용해도 괜찮습니다.