[JS] 객체 톺아보기

PinkTopaz·2023년 4월 22일
0

객체

  • 원시형과 다르게 다양한 데이터를 담을 수 있는 자료형
  • key에는 문자형, value에는모든 자료형이 허용된다.

객체를 만드는 방법

객체 생성자

let user = new Object();

객체 리터럴 (주로 사용하는 방법 )

let user = {};

객체 사용 예시


let user = {     
  name: "승경씨",  // 키: "name",  값: "승경씨"
  age: 20,        // 키: "age", 값: 30
  "like fruit" : "yes" // ✅ 복수의 단어는 따옴표로 묶어야 한다. 
};
delete user.age; // ✅ delete 연산자를 사용해서 프로퍼티를 삭제할 수 있다. 

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

const user = {
  name: "승경씨"
};

user.name = "Heather"; 

const는 user의 값을 고정하지만, 내용은 고정하지 않기 때문에
user=.. 이렇게 전체적으로 설정하려고 할 때만 오류를 발생시킨다

대괄호 표기법

코테 문제를 풀면서도 왕왕 볼 수 있는 문법인데, 아주 편리하다.
위 객체 사용 예시에서 선언한 like fruit를 가져올 때

user.like fruit = false;

이와 같이 써주게 되면 에러가 발생한다.
.은 유효한 key인 경우에만 사용 가능한데, 유효한 key에는

  • 공백이 들어갈 수 없고
  • 숫자로 시작하지 않으며
  • $와 _를 제외한 특수 문자가 없어야한다.

key가 유효하지 않을 경우에 사용할 수 있는 방법이 대괄호 표기법이다.

let user = {};

// set
user["like fruit"] = true; // ✅ 대괄호 표기법 안에서 문자열을 쓸 때는 꼭 따옴표로 묶어줘야한다. 

// get
alert(user["likes fruit"]); // true

대괄호 표기법을 사용하면 다으모가 같이 변수를 key로 사용할 수 있다.

let key = "like fruit"
user[key] = true; // ✅ 대괄호 표기법 안에서 문자열을 쓸 때는 꼭 따옴표로 묶어줘야한다. 

변수는 런타임에 평가가 되기 때문에 사용자의 입력값 변경 등에 따라 값이 바뀔 수 있는데, 이 점을 이용해 유연하게 코드를 작성할 수 있다.

let user = {
  name: "Heather",
  age: 20
};

let key = prompt("사용자의 어떤 정보를 얻고 싶으신가요?", "name");

// 변수로 접근
alert( user[key] ); // Heather (프롬프트 창에 "name"을 입력한 경우)

점 표기법을 이용하면 해당 방식은 불가능하다.

let user = {
  name: "Heather",
  age: 23
};

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

계산된 프로퍼티 (computed property)

객체의 key가 대괄호로 둘러싸여 있는 경우, 이를 계산된 프로퍼티라고 부른다

let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");

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

alert( bag.apple ); // ✅ fruit에 "apple"이 할당되었다면 값을 가져온다. 

다음과 같이 구현할 수도 있지만, 계산된 프로퍼티를 사용하는 것이 더 간단해 보인다.

let bag = {};
bag[fruit] = 5;

단축 프로퍼티

function makeUser(name, age) {
  return {
    name: name,
    age: age,
    // ...등등
  };
}

다음과 같이 리턴하는 객체의 key값과 변수명이 같을 때 name : name으로 써주지 않고 다음과 같이 줄여 쓸 수 있다.

function makeUser(name, age, gender) {
  return {
    name, // ✅ name: name 과 같음
    age,  
    gender : gender, // ✅ 일반 프로퍼티와 단축 프로퍼티를 함께 사용할 수도 있다. 
    // ...
  };
}

프로퍼티 이름의 제약 사항

  • 변수와 다르게 for, let, return 같은 예약어를 key 값으로 사용할 수 있으며, 어떠한 문자형, 심볼형 값도 key가 될 수 있다.
  • 문자형이나 심볼형에 속하지 않은 값은 문자열로 자동 형 변환됩니다.
let obj = {
  0: "zero" // ✅ 0이 "0"으로 자동 형변환되어 "0": "zero"와 동일
};

alert( obj["0"] ); // "zero"
alert( obj[0] ); // "zero"

in 연산자로 프로퍼티 존재여부 확인

일치 연산자를 사용해 "name" === undefined로 프로퍼티 존재 여부를 확인할 수도 있지만, 가끔 이 방법이 실패하기도 한다.

let obj = {
  test: undefined
};

//✅ undefined가 할당된 값이므로 undefined가 출력된다. 하지만 test는 존재한다. 혼돈을 줄 수 있다. 
alert( obj.test ); 

이 경우 in 연산자를 사용하면 좋다.

let user = {
  name: "Heather",
  age: 23
};

// ✅ 프로퍼티 명은 따옴표로 감싼다 
alert ("name" in user); // true

for~in 반복문으로 객체의 모든 key 순회하기

let user = {
  name: "Heather",
  age: 24,
};

for (let key in user) {
  // 키
  alert( key );  // name, age
  // 키에 해당하는 값
  alert( user[key] ); // Heather, 24
}

반복변수명 (상기 코드에서는 key)는 자유롭게 정할 수 있다. let num in numList와 같이 쓸 수도 있다.

객체 정렬 방식

객체의 프로퍼티는 항상 객체에 추가한 순서 그대로 정렬이 될까?
아니다.
그 외 프로퍼티는 객체에 추가한 순서대로 정렬되지만, 정수 프로퍼티는 자동으로 정렬이 된다.

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

for (let code in codes) {
  alert(code); // ✅ 1, 41, 44, 49
}

for (let code in codes) {
  alert(+code); // ✅ key가 정수 프로퍼티가 아니도록 숫자로 바꿔준다. 
}

📍 정수 프로퍼티란

정수 프로퍼티라는 용어는 변형 없이 정수에서 왔다 갔다 할 수 있는 문자열을 의미한다.
"49"는 정수로 변환해도, 변환한 정수를 다시 문자열로 바꿔도 변형이 없이 49이지만,
"+49"는 정수로 변환하면 49로 원래 값과는 달라지기에 정수 프로퍼티가 아니다.


참조에 의한 객체 복사

원시값은 '값 그대로' 저장/할당/복사되지만, 객체형은 참조에 의해 저장되고 복사된다.

let message = "Hello!";
let phrase = message;

이렇게 문자열을 변수에 저장한 경우에는

다음과 같이 독립된 변수에 각각 Hello!가 저장된다.

하지만 객체의 경우에는 객체 자체는 메모리 어딘가에 저장이 되고, 변수에는 객체를 참조할 수 있는 값이 저장된다.

let user = { name: "John" };
let admin = user; // 참조값을 복사함

따라서 다음과 같은 코드로 객체를 조작하고 접근할 수 있다.

let user = { name: 'Heather' };

let admin = user; //✅ admin, user는 같은 주소를 가리킨다.
admin.name = 'Eunice'; 

참조에 의한 비교

객체 비교 시 =====는 동일하게 동작한다.
두 객체가 동일한 객체 (즉, 두 변수가 하나의 객체를 가리키는 경우) 참을 반환한다.

let a = {};
let b = a; // ✅ 참조에 의한 복사

alert( a == b ); // true, 두 변수는 같은 객체를 참조합니다.
alert( a === b ); // true

하지만 다음과 같은 경우에는 두 객체가 같아보이지만 각각 주소가 다른 객체이기 때문에 비교시 false를 반환한다.

let a = {};
let b = {}; // 독립된 두 객체

alert( a == b ); // false

객체 복사, 병합과 Object.assign

참조에 의한 복사를 이용해 객체가 할당된 변수를 복사하면, 동일한 객체에 대해 참조하는 값이 하나 더 만들어질 뿐이다.
만약 기존에 있던 객체와 동일하지만, 독립적인 객체를 만들고 싶다면 어떻게 해야할까?

let clone = {}; // 새로운 빈 객체

// 빈 객체에 user 프로퍼티 전부를 복사해 넣습니다.
for (let key in user) {
  clone[key] = user[key];
}

다음과 같이 객체를 순회하며 원시 수준까지 프로퍼티를 복사할 수도 있고

let user = { name: "John" };

let permissions1 = { canView: true };
let permissions2 = { canEdit: true };

// permissions1과 permissions2의 프로퍼티를 user로 복사합니다.
Object.assign(user, permissions1, permissions2);

// ✅ now user = { name: "John", canView: true, canEdit: true }

Object.assign을 이용할 수도 있다.

Object.assign(dest, [src1, src2, src3...]) 에서 첫번째 인자에는 목표로 하는 객체가 들어가고, src1, src2, src3에는 복사하고자하는 객체가 들어간다.

만약 목표 객체(dest)에 동일한 이름을 가진 프로퍼티가 있다면 기존 값에 새로운 값이 덮어 씌워진다.

let user = { name: "John" };

Object.assign(user, { name: "Pete" });
alert(user.name); // user = { name: "Pete" }

메서드와 this

객체 리터럴 안에서 메서드를 선언할 때 다음과 같은 두 방법을 사용할 수 있다.

user = {
  sayHi: function() {
    alert("Hello");
  }
};

// ✅ 단축 구문
user = {
  sayHi() { // "sayHi: function()"과 동일
    alert("Hello");
  }
};

this

메서드 내부에서 this 키워드를 사용하면 객체에 접근할 수 있다.

let user = {
  name: "John",
  age: 30,

  sayHi() {
    // ✅ 'this'는 '현재 객체'를 나타냅니다.
    alert(this.name); // ✅ alert(user.name);와 동일
  }

};

alert(user.name)는 외부 변수이기 때문에 만약 객체 외부에서 user = null 과 같은 재할당이 일어난다면 에러가 발생할 것이다.
따라서 이 경우에는 this를 사용하는 게 더 좋겠다.

자유로운 this

자바스크립트에서 this의 값은 런타임에 결정된다.
어려운 개념이 아니라 단순히 메서드가 어디서 정의되었는지에 상관없이 this는 ‘점 앞의’ 객체가 무엇인가에 따라 ‘자유롭게’ 결정된다는 의미이다.

let user = { name: "John" };
let admin = { name: "Admin" };

function sayHi() {
  alert( this.name );
}

// ✅ 별개의 객체에서 동일한 함수를 사용함
user.f = sayHi;
admin.f = sayHi;

// ✅ 'this'는 '점(.) 앞의' 객체를 참조하기 때문에 this 값이 각각 달라진다 
user.f(); // John  (this == user)
admin.f(); // Admin  (this == admin)
profile
🌱Connecting the dots🌱

0개의 댓글