[DAY12] 객체.객체["객ㅊㅔ"]

Jhey·2024년 10월 29일
0

JavsScript

목록 보기
7/18

0. 객체

  • 키와 값으로 구성된 속성의 집합
  • 중괄호로 선언
  • 참조 자료형
// 키와 값으로 구성된 속성의 집합
const userObj = { 
  name: "chul su",
  age: 20,
}; 

userObj.age = 50;
const copyUserObj = userObj;

// 동적으로 추가
const obj = {};
obj.name = "영희";
// 동적으로 삭제
delete obj.name;

console.log(obj.age); // undefined, age 속성이 없지만 접근하는 건 문제 안 됨
// 단순히 값이 할당되지 않은 것임

// 객체 생성
const obj2 = new Object();
obj2.name = "철수";

/*
  데이터를 정의하는 데 있어서 간편하게 
  데이터를 정의할 수 있는 방법을 리터럴 표기법 (literal)
*/

// 객체 리터럴
const obj = {}; // 이렇게 쓸 수 있음, 효율적

// 배열 리터럴
const arr = [];

// 문자 리터럴
const name = "철수";

// 불리언 리터럴
const user = false;

// 숫자 리터럴
const num = 10;

// null 리터럴
const is = null;

// symbol 리터럴
const key = Symbol("a");

// 객체 속성에 접근하는 방법
for (let key in obj) {
  console.log(obj[key]); // obj.key 하면 안 됨
}

const obj = {
  name: "철수",
  likes: ["사과", "바나나", "오렌지", { hate: ["당근"] }],
  address: {
    zipcode: 13100
  }
};

console.log(obj.likes[1]);
console.log(obj.address.zipcode);
console.log(obj["address"]["zipcode"]);

// 내장 메서드
// 특정 키 존재 유무를 확인할 수 있음
console.log(obj.hasOwnProperty('name'));
console.log(obj.name);

// 함수 호출
const userObj = {
  getName: function(name, age) {
    console.log(name, age);
  },
};
userObj.getName("영희", 20);

// 자기 자신을 호출 - this
const userObj = {
  name: "철수",
  getName: function() {
    console.log(this.name);
  },
};
userObj.getName();

1. this

  • 예약되어 있는 키워드
  • 함수를 호출한 객체를 가리킴
  • 함수를 누가 호출했는지를 봐라
function getName() {
  console.log(this);
}
window.getName(); 
// window 생략 가능해서 지금까지 getName()이라고 사용한 것임

// 단축 문법
const obj = {
  getName // 값과 식별자의 값이 같다면 한 번만 적어도 됨
};

const obj = {
  getName() {}, // 함수는 key-값 형태가 아닌 이렇게 함수만 적을 수 있음
};

1.1 화살표 함수에서 this

const person = {
  name: "Alice",
  hobbies: ["Reading", "Coding", "Gardening"],
  showHobbies: function () {
    this.hobbies.forEach((hobby) => {
      console.log(this.name + " likes " + hobby);
    });
  },
};

person.showHobbies(); // this가 showHobbies 함수의 this(즉, person)와 동일하게 참조됨
  1. showHobbies 메서드에서 thisperson 객체를 가리킴.
  2. forEach 내부의 화살표 함수 (hobby) => { ... }는 새로운 this를 가지지 않고, showHobbies가 참조하는 this를 그대로 사용함.
  3. 따라서 this.nameAlice로 출력됨.

2번처럼 동작하는 이유
→ 화살표 함수는 만들어질 때 상위 스코프의 this가 고정으로 전달됨.

this가 고정이 되는 이유
→ 일반 함수로 콜백을 전달할 때마다 this가 의도치 않게 바뀌는 상황이 잦았기 때문에, ES6에서는 화살표 함수가 생성될 때 this어디에 바인딩(=객체에 연결)되는지 명확하게 하려고 고안됨.

1.2 일반 함수에서 this

const person = {
  name: "Alice",
  hobbies: ["Reading", "Coding", "Gardening"],
  showHobbies: function () {
    this.hobbies.forEach(function (hobby) {
      console.log(this.name + " likes " + hobby);
    });
  },
};

person.showHobbies(); // "undefined likes Reading"
  1. forEach 내부의 function (hobby) { ... }this를 새로 바인딩(=객체에 연결)하기 때문에, thisperson 객체가 아닌 전역 객체를 가리킴.
  2. this.nameundefined임.

일반 함수는 호출할 때마다 새로운 this가 바인딩되기 때문임.

2. 객체 반복(순회)

// for in

// object.keys()
console.log(Object.keys(userObj)); // ['name', 'age']
const keys = Object.keys(userObj);
for (let value of keys) {
  console.log(userObj[value]);
}

// object.values()

// object.entries()

3. 객체 병합과 복사

/*
  얕은 복사 -> 객체, 배열
  깊은 복사 -> 기본 자료형
*/
const user = {
  name: "철수"
};

const copyUser = user; // 얕은 복사
const copyUserDeep = { ...user }; // 전개 연산자, 깊은 복사
user.name = "영희"; // 깊은 복사하면 영희로 바뀌지 않음
console.log(user);

// 병합
const user = {
  name: "철수",
  age: 20,
};
const developer = {
  skill: "react.js"
};

const person = {
  name: user.name,
  age: user.age,
  skill: developer.skill, // 객체의 병합
};

const mergedPerson = { ...user, ...developer }; // 전개 연산자를 사용하여 객체를 병합
console.log(mergedPerson);

/*
전개 연산자 주의 사항
같은 속성이 있는 경우 뒤에 있는 속성이 덮어버림
*/
const personWithAge = { ...user, ...developer, age: 40 };
// 이럴 땐 age:40이 덮어버림

// 객체 안에 객체가 있을 때 얕은 복사
const user = { 
  name: "철수", 
  age: 20,  
  today: { eat: "meat" },
};

const user2 = { ...user }; // 전개 연산자를 통해 깊은 복사를 한 줄 알았지만 객체가 안에 있기 때문에
user.today.eat = "vegetable"; // 얘는 얕은 복사가 된다.
console.log(user, user2);

// 객체 속 객체까지 깊은 복사를 하고 싶다면
// JSON 문자열로 바꾼 후, 다시 객체로 바꾸기
const user2Deep = JSON.parse(JSON.stringify(user)); 

// 배열 얕은 복사를 깊은 복사로 바꾸기
const numArr = [{ eat: "meal" }];
const copyArrDeep = JSON.parse(JSON.stringify(numArr));

4. 데이터 속성 설명자

// value, writable, enumerable, configurable

const obj = {};
Object.defineProperty(obj, "name", {
  value: "철수",
  writable: true, // 수정 가능 여부
  enumerable: true, // 순회할 때 접근 가능한 속성
  configurable: true // 이 설정을 바꿀 수 있는지 또는 삭제할 수 있는지
});

obj.name = "영희";

// 아래와 같이 다시 속성을 설정할 수 있음
Object.defineProperty(obj, "name", {
  writable: false
});

5. 접근 속성 설명자

const userObj = {
  firstName: "John",
  lastName: "Hash",
  
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  },
  
  set fullName(name) {
    const a = name.split(" ");
    this.firstName = a[0];
    this.lastName = a[1];
  },
};

userObj.fullName = "m"; // set이 실행된다.
console.log(userObj.fullName); // get이 실행된다.

6. 불변성을 유지하는 메서드

장점: API로 응답받은 데이터가 외부로부터 변경되는 것을 막음.

  • Object.seal() - 객체의 속성을 추가하고 삭제하는 것을 막음.
  • Object.preventExtensions() - 속성 추가 불가.
  • Object.freeze() - 변경 아예 불가, 위의 두 개를 합한 것임.


번외. 객체 안에 객체 안에 ..

const library = {
    홍길동전: { // key : 홍길동전 value: 객체
        author: "허균",
        year: 1600,
        genres: ["소설", "고전"],
        available: true,
    },
    삼국지: {
        author: "나관중",
        year: 14,
        genres: ["소설", "고전"],
        available: false,
    },
    "자바스크립트 완벽 가이드": {
        author: "David Flanagan",
        year: 2020,
        genres: ["기술", "프로그래밍"],
        available: true,
    },
};

function addBook(library, title, author, year, genres) {
    library[title] = { //원래 객체 부르는것과 동일하게 객체[key]로 부른다.
        author: author,
        year: year,
        genres: genres,
        available: true, 
    };
}

➡️ 객체 안에 객체가 있는 형식 또 한 똑같이 key - value 형태로 생각하면 된다.


배운점

객체는 뭔가 어려워서 사용을 피하고 배열만 사용했는데 key로 접근할 수 있다는 엄청난 장점 때문에 연습을 많이 해서 사용해야겠다.

profile
천천히 가더라도 즐겁게 ☁

0개의 댓글

관련 채용 정보