[javascript]자바스크립트 객체

rondido·2022년 9월 4일
0

Javascript

목록 보기
13/21

객체

  • 자료쳥 챕터에서 배웠듯이 자바스크립트엔 여덟 가지 자료형이 있다. 이 중 일곱 개는 오직 하나의 데이터만 담을 수 있어 '원시형'이라 부릅니다.

  • 그런데 객체형은 원시형과 달리 다양한 데이터를 담을 수 있습니다. 키로 구분된 데이터 집합이나 복잡한 개체를 저장할 수 있다. 객체는 자바스크립트 거의 모든 면에 녹아 있는개념이므로 자바스크립트를 잘 다루려면 객체를 잘 이해야 함

  • 객체는 중괄호 {...}를 이용해 만들 수 있다. 중괄호 안에는 '키(key): 값(value)'쌍으로 구성된 프로퍼티를 여러 개 넣을 수 있는데, 키엔 문자형, 값엔 모든 자료형이 허용


  • 서랍장을 상상하면 객체를 이해하기 쉽다. 서랍장 안 파일은 프로퍼티, 파일 각각에 붙어있는 이름표는 객체의 키라고 생각하시면 됩니다. 복잡한 서랍장 안에서 이름표를 보고 원하는 파일을 쉽게 찾을 수 있듯이, 객체에선 키를 이용해 프로퍼티를 쉽게 찾을 수 있다.


let user=  new Object();//'객체 생성자'문법
let user = {} //'객체 리터럴'문법

  • 중괄호 {...}를 이용해 객체를 선언하는 것을 객체 리터럴이라고 부릅니다. 객체를 선언할 떈 주로 이 방법을 사용

리터럴과 프로퍼티

  • 중괄호 {...}안에는 '키:값' 쌍으로 구성된 프로퍼티가 들어가닙니다.
let user = { //객체
	name:"john",  // 키:'name', 값: "john"
    age: 30       // 키:'age', 값:30
}
  • 콜론(:)을 기준으로 왼쪽엔 키가, 오른쪽엔 값이 위치합니다. 프로퍼티 키는 프로퍼티 '이름'혹은 '식별자'라고 부릅니다.

객체 user에는 프로퍼티가 두 개 있습니다.
1. 첫 번째 프로퍼티 - "name"(이름)과 "john"(값)
2. 두 번째 프로퍼티 - "age"(이름)과 30(값)

  • 서랍장에 파일을 추가하고 뺄 수 있듯이 개발자는 프로퍼티를 추가,삭제할 수 있습니다.

  • 점 표기법을 이용하면 프로퍼티 값을 읽는 것도 가능합니다.
//프로퍼티 값 얻기
console.log(user.name)//John
console.log(user.age)//30
  • 프로퍼티 값엔 모든 자료형이 올 수 있습니다. 불린형 프로퍼티를 추가해봅시다.
user.inAdmin = true;

  • delete 연산자를 통해 프로퍼티를 삭제
delete user.age;


  • 여러 단어를 조합해 프로퍼티 이름을 만든 경우엔 프로퍼티 이름을 따음표로 묶어줘야 함.
let user = {
	name: "John",
    age: 30,
    "likes birds": true; //복수의 단어는 따음표로 묶어야 함
}

  • 마지막 프로퍼티 끝은 쉼표로 끝날 수 있음
let user = {
	name: "John",
    ange: 30,
}

  • 상수 객체는 수정될 수 있다.

    • 주의 하세요. const로 선언된 객체는 수정될 수 있습니다.
const user = {
	name:"John"
};
user.name = "Pete" //(*)
console.log(user.name) //pate
  • (*)로 표시한 줄에서 오류를 일으키는 것처럼 보일 수 있지만 그렇지 않습니다. 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" = ture;와 같다
user[key] = true;
  • 변수 key는 런타임에 평가되기 떄문에 사용자 입력값 변경 등에 따라 값이 변경, 어떤 경우든, 평가가 끝난 이후의 결과가 프로퍼티 키로 사용
let user = {
  name: "John",
  age: 30,
};

let key = "name";

// 변수로 접근
console.log(user[key]);
  • 그런데 점 표기법은 이런 방식이 불가능
let user = {
  name: "John",
  age: 30
};

let key = "name";
console.log( user.key ) // undefined

계산된 프로퍼티

  • 객체를 만들 때 객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는 경우, 이를 계산된 프로퍼티라고 부름.
let fruit = "apple";

let bag = {
  [fruit]: 5, // 변수 fruit에서 프로퍼티 이름을 동적으로 받아 옵니다.
};

console.log(bag.apple); // fruit에 "apple"이 할당되었다면, 5가 출력됩니다.
  • 위 예시에서 [fruit]는 프로퍼티 이름을 변수 fruit에서 가져오겠다는 것을 의미
  • 사용자가 fruit에 apple을 입력했다면 bag엔 {apple:5}가 할당
let fruit = "apple";
let bag = {};

// 변수 fruit을 사용해 프로퍼티 이름을 만들었습니다.
bag[fruit] = 5;

let fruit = "apple";
let bag = {
  [fruit + "Computers"]: 5, // bag.appleComputers = 5
};

console.log(bag.appleComputers); // 5
  • 대괄호 표기법은 프로퍼티 이름과 값의 제약을 없애주기 때문에 점 표기법보다 훨씬 강력 그런데 작성하기 번거롭다는 단점이 존재

  • 이런 이유로 프로퍼티 이름이 확정된 상황이고, 단순한 이름이라면 처음엔 점 표기법을 사용하다가 뭔가 복잡한 상황이 발생했을 때 대괄호 표기법으로 바꾸는 경우가 많습니다.


단축 프로퍼티

  • 실무에선 프로퍼티 값을 기존 변수에서 받아와 사용하는 경우가 종종 있습니다.
function makeUser(name, age) {
  return {
    name: name,
    age: age,
    // ...등등
  };
}

let user = makeUser("John", 30);
console.log(user.name); // John
  • 위 예시의 프로퍼티들은 이름과 값이 변수의 이름과 동일, 이렇게 변수를 사용해 프로퍼티를 만드는 경우는 아주 흔한대, 프로퍼티 값 단축 구문을 사용하면 코드를 짧게 줄일 수 있음.

  • 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
}

console.log(obj.for + obj.let + obj.return // 6
  • 이와 같이 프로퍼티 이름엔 특별한 제약이 없습니다. 어떤 문자형, 심볼형 값도 프로퍼티 키가 될 수 있죠(식별자로 쓰이는 심볼형에 대해선 뒤에서 다룰 예정입니다).

  • 문자형이나 심볼형에 속하지 않은 값은 문자열로 자동 형 변환됩니다.

  • 예시를 살펴봅시다. 키에 숫자 0을 넣으면 문자열 "0"으로 자동변환됩니다.

let obj = {
  0: "test", // "0": "test"와 동일합니다.
};

// 숫자 0은 문자열 "0"으로 변환되기 때문에 두 얼럿 창은 같은 프로퍼티에 접근합니다,
console.log(obj["0"]); // test
console.log(obj[0]); // test (동일한 프로퍼티)
  • 이와 같이 객체 프로퍼티 키에 쓸 수 있는 문자열엔 제약이 없지만, 역사적인 이유 때문에 특별 대우를 받는 이름이 하나 있다. 바로 proto입니다.
let obj = {};
obj.__proto__ = 5; // 숫자를 할당합니다.
alert(obj.__proto__); // [object Object] - 숫자를 할당했지만 값은 객체가 되었습니다. 의도한대로 동작하지 않네요.
  • 원시값 5를 할당했는데 무시된것을 확인
  • proto의 본질은 프로토타입 상속에서, 이 문제를 어떻게 해결할 수 있을지에 대해선 프로토타입 메서드와 proto가 없는 객체에서 자세히 다룰 예정

'in'연사낮로 프로퍼티 존재 여부 확인하기

  • 자바스크립트 객체의 중요한 특징 중 하나는 다른 언어와는 달리, 존재하지 않는 프로퍼티에 접근하려 해도 에러가 발생하지 않고 undefined를 반환

  • 이런 특징을 응용하면 프로퍼티 존재 여부를 쉽게 확인

let user = {};

console.log( user.noSuchProperty === undefined ); // true는 '프로퍼티가 존재하지 않음'을 의미합니다.
  • 이렇게 undefined와 비교하는 것 이외에도 연산자 in을 사용하면 프로퍼티 존재 여부를 확인할 수 있습니다.

  • 문법은 다음과 같습니다.

"key" in object
  • 예시
let user = { name: "John", age: 30 };

console.log("age" in user); // user.age가 존재하므로 true가 출력됩니다.
console.log("blabla" in user); // user.blabla는 존재하지 않기 때문에 false가 출력됩니다.
  • in 왼쪽엔 반드시 프로퍼티 이름이 와야 합니다. 프로퍼티 이름은 보통 따옴표로 감싼 문자열입니다.

  • 따음표를 생략하면 아래 예시와 같이 엉뚱한 변수가 조사 대상

let user = { age: 30 };

let key = "age";
 console.log( key in user ); // true, 변수 key에 저장된 값("age")을 사용해 프로퍼티 존재 여부를 확인합니다.

  • 그런데 이쯤 되면 "undefined랑 비교해도 충분한데 왜 in 연산자가 있는 거지?"라는 의문이 들 수 있습니다.

  • 대부분의 경우, 일치 연산자를 사용해서 프로퍼티 존재 여부를 알아내는 방법("=== undefined")은 꽤 잘 동작합니다. 그런데 가끔은 이 방법이 실패할 때도 있습니다. 이럴 때 in을 사용하면 프로퍼티 존재 여부를 제대로 판별할 수 있습니다.

let obj = {
  test: undefined
};

console.log( obj.test ); // 값이 `undefined`이므로, 얼럿 창엔 undefined가 출력됩니다. 그런데 프로퍼티 test는 존재합니다.

console.log( "test" in obj ); // `in`을 사용하면 프로퍼티 유무를 제대로 확인할 수 있습니다(true가 출력됨).
  • obj.test는 실제 존재하는 프로퍼티입니다. 따라서 in 연산자는 정상적으로 true를 반환
  • undefined는 변수는 정의되어 있으나 값이 할당되지 않는 경우에 쓰기 때문에 프로퍼티 값이 undefined인 경우는 흔치 않습니다. 값을 '알 수 없거나' 값이 '비어 있다는'것을 나타낼 때는 주로 null을 사용

'for...in' 반복문

  • for...in 반복문을 사용하면 객체의 모든 키를 순회할 수 있음.

  • for..in은 앞서 학습했던 for(;;) 반복문과는 완전히 다릅니다.

for(key in object){
	//각 프로퍼티 키(key)를 이용하여 본문(body)를 실행
}
  • 아래 예시를 실행하면 객체 user의 모든 프로퍼티가 출력
let user = {
  name: "John",
  age: 30,
  isAdmin: true
};

for (let key in user) {
  // 키
  console.log( key );  // name, age, isAdmin
  // 키에 해당하는 값
  console.log( user[key] ); // John, 30, true
}
  • for..in 반복문에서도 for(;;)문처럼 반복 변수(looping variable)를 선언(let key)했다는 점에 주목해 주시기 바랍니다.

  • 반복 변수명은 자유롭게 정할 수 있습니다. 'for (let prop in obj)'같이 key 말고 다른 변수명을 사용해도 괜찮습니다.


객체 정렬 방식

  • 객체와 객체 프로퍼티를 다루다 보면 "프로퍼티엔 순서가 있을까"라는 의문이 생기기 마련 반복문은 프로퍼티를 추가한 순서대로 실행될지, 그리고 이 순서는 항상 동일할지 궁금해지죠.

  • 답은 간단하다. 객체는 '특별한 방식으로 정렬'됩니다. 정수 프로퍼티는 자동으로 정렬되고, 그외의 프로퍼티는 객체에 추가한 순서 그대로 정렬

let codes = {
  "49": "독일",
  "41": "스위스",
  "44": "영국",
  // ..,
  "1": "미국"
};

for (let code in codes) {
  console.log(code); // 1, 41, 44, 49
}
  • 현재 개발 중인 애플리케이션의 주 사용자가 독일인이라고 가정 나라 번호를 선택하는 화면에서 49가 맨 앞에 오도록 하는 게 좋음

  • 그런데 코드를 실행해 보면 예상과는 전혀 다른 결과가 출력

    • 미국(1)이 첫 번째로 출력
    • 그 뒤로 스위스(41), 영국(44), 독일(49)이 차례대로 출력
  • 이유는 나라 번호(키)가 정수이어서 1, 41, 44, 49 순으로 프로퍼티가 자동 정렬되었기 때문입니다.


  • 정수 프로퍼티? 그게 뭔가요?

    • 정수 프로퍼티라는 용어는 변형 없이 정수에서 왔다 갔다 할 수 있는 문자열을 의미
    • 문자열 "49"는 정수로 변환하거나 변환한 정수를 다시 문자열로 바꿔도 변형이 없기 때문에
      정수 프로퍼티입니다.
// 함수 Math.trunc는 소수점 아래를 버리고 숫자의 정수부만 반환합니다.
 console.log(String(Math.trunc(Number("49"))) ); // '49'가 출력됩니다. 기존에 입력한 값과 같으므로 정수 프로퍼티입니다.
 console.log( String(Math.trunc(Number("+49"))) ); // '49'가 출력됩니다. 기존에 입력한 값(+49)과 다르므로 정수 프로퍼티가 아닙니다.
 console.log( String(Math.trunc(Number("1.2"))) ); // '1'이 출력됩니다. 기존에 입력한 값(1.2)과 다르므로 정수 프로퍼티가 아닙니다.

  • 한편 키가 정수가 아닌 경우엔 작성된 순서대로 프로퍼티가 나열
let user = {
  name: "John",
  surname: "Smith"
};
user.age = 25; // 프로퍼티를 하나 추가합니다.

// 정수 프로퍼티가 아닌 프로퍼티는 추가된 순서대로 나열됩니다.
for (let prop in user) {
  console.log( prop ); // name, surname, age
}
  • 위 예시에서 49(독일 나라 번호)를 가장 위에 출력되도록 하려면 나라 번호가 정수로 취급되지 않도록 속임수를 쓰면 됩니다. 각 나라 번호 앞에 "+"를 붙여봅시다.
let codes = {
  "+49": "독일",
  "+41": "스위스",
  "+44": "영국",
  // ..,
  "+1": "미국"
};

for (let code in codes) {
  console.log( +code ); // 49, 41, 44, 1
}

위 내용은 javascript.info 사이트에서 공부한 내용 정리
자세한 내용은 아래 링크를 참고하세요
https://ko.javascript.info/object

profile
개발 옆차기

0개의 댓글