- 키와 값으로 구성된 속성의 집합
- 중괄호로 선언
- 참조 자료형
// 키와 값으로 구성된 속성의 집합
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();
- 예약되어 있는 키워드
- 함수를 호출한 객체를 가리킴
- 함수를 누가 호출했는지를 봐라
function getName() {
console.log(this);
}
window.getName();
// window 생략 가능해서 지금까지 getName()이라고 사용한 것임
// 단축 문법
const obj = {
getName // 값과 식별자의 값이 같다면 한 번만 적어도 됨
};
const obj = {
getName() {}, // 함수는 key-값 형태가 아닌 이렇게 함수만 적을 수 있음
};
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)와 동일하게 참조됨
showHobbies
메서드에서 this
는 person
객체를 가리킴.forEach
내부의 화살표 함수 (hobby) => { ... }
는 새로운 this
를 가지지 않고, showHobbies
가 참조하는 this
를 그대로 사용함.this.name
이 Alice
로 출력됨.❓ 2번처럼 동작하는 이유
→ 화살표 함수는 만들어질 때 상위 스코프의 this
가 고정으로 전달됨.
❓ this
가 고정이 되는 이유
→ 일반 함수로 콜백을 전달할 때마다 this
가 의도치 않게 바뀌는 상황이 잦았기 때문에, ES6에서는 화살표 함수가 생성될 때 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"
forEach
내부의 function (hobby) { ... }
는 this
를 새로 바인딩(=객체에 연결)하기 때문에, this
는 person
객체가 아닌 전역 객체를 가리킴.this.name
은 undefined
임.일반 함수는 호출할 때마다 새로운 this
가 바인딩되기 때문임.
// 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()
/*
얕은 복사 -> 객체, 배열
깊은 복사 -> 기본 자료형
*/
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));
// 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
});
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이 실행된다.
장점: API로 응답받은 데이터가 외부로부터 변경되는 것을 막음.
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로 접근할 수 있다는 엄청난 장점 때문에 연습을 많이 해서 사용해야겠다.