Skip to content
This page has been auto-translated and may contain errors.View in English

객체

docs.scrimba.com

사용자 한 명을 설명한다고 가정해봅시다: 이름, 이메일, 나이, 로그인 여부. 이들을 네 개의 별도 변수로 분산시킬 수 있지만, 이들은 서로 관련이 있고, 분리해두면 "사용자"를 의미할 때마다 네 가지를 계속 전달해야 합니다. 객체를 사용하면 모든 것을 하나의 값으로 모을 수 있으며, 각 조각은 조회할 수 있는 이름을 가집니다. 취급할 대부분의 데이터(사용자, 제품, 장바구니)는 정확히 이런 형태로 도착합니다.

객체 만들기

**객체**는 중괄호로 작성된 명명된 값의 모음입니다. 내부에는 쉼표로 구분된 key: value 쌍을 나열합니다. 키는 이름이고 값은 그것이 보유한 것입니다:

js
const user = {
  name: "민지",
  age: 27,
};

console.log(user.name); // 민지

값을 다시 읽을 때는 점과 키를 사용합니다: user.name. 이를 점 표기법이라고 하며, 대부분의 경우 이것을 사용하게 됩니다. 왼쪽에 키, 오른쪽에 저장된 값.

값을 읽는 두 번째 방법이 있는데, 문자열로 된 키를 가진 대괄호를 사용합니다:

js
console.log(user["name"]); // 민지

대부분의 경우 점 표기법이 더 깔끔하게 읽혀서 이를 사용하세요. 대괄호는 키가 순수한 단어가 아닐 때(예: 공백이 있을 때) 또는 미리 키를 모를 때 다른 변수에 있을 때 유용합니다.

**객체**는 문자열 키 아래에 관련된 값을 그룹화하며, 중괄호 내에 key: value 쌍으로 작성됩니다. 배열이 위치로 접근하는 순서화된 목록을 보유하는 곳에서, 객체는 이름으로 접근하는 값을 보유합니다:

js
const user = {
  name: "민지",
  age: 27,
  isActive: true,
};

console.log(user.name); // 민지
console.log(user["age"]); // 27

두 가지 방법이 있습니다. 점 표기법(user.name)이 기본값입니다: 더 짧고 명확합니다. 대괄호 표기법(user["age"])이 같은 일을 하지만 문자열로 키를 받으므로, 점 표기법이 할 수 없는 두 가지를 열어줍니다.

대괄호 형식은 키가 유효한 식별자가 아닐 때(예: 공백을 포함하거나 숫자로 시작할 때) 필요하며, 키가 동적일 때(리터럴로 입력하지 않고 변수에 있을 때) 필요합니다:

js
const field = "name";
console.log(user[field]); // 민지, `field`에 보유된 키를 읽음
console.log(user.field); // undefined, "field"라는 리터럴 키를 찾음

그 차이는 사람들을 혼동하게 합니다: user[field]field의 값을 사용하는 반면, user.fieldfield라고 철자된 키를 찾습니다. 존재하지 않는 키를 읽으면 오류 대신 undefined를 반환합니다.

**객체**는 값을 키 아래에 그룹화하기 위한 JavaScript의 핵심 구조입니다. 키는 문자열(또는 지금은 무시할 수 있는 기호)이고 값은 다른 객체나 함수를 포함한 무엇이든 될 수 있습니다. 중괄호에 key: value 쌍으로 작성합니다:

js
const user = {
  name: "민지",
  age: 27,
  isActive: true,
};

console.log(user.name); // 민지
console.log(user["age"]); // 27

점 표기법이 관용적인 기본값입니다. 대괄호 표기법은 계산된 식으로 키와 같은 조회이므로, 정확히 두 가지 경우에 필요합니다: 키가 유효한 식별자가 아닐 때(user["first name"], user["2fa"]), 그리고 키가 동적일 때:

js
const field = "name";
console.log(user[field]); // 민지, 먼저 `field`를 "name"으로 평가함

두 가지 동작을 기억할 가치가 있습니다. 누락된 키를 읽으면 던지지 않고 undefined를 반환하므로, 오타는 크게 실패하지 않고 조용히 실패합니다. 그리고 키는 항상 내부적으로 문자열입니다: user[27]user["27"]은 같은 슬롯에 도달하는데, 숫자가 문자열 키로 강제되기 때문입니다. 그 강제는 객체 키와 배열 인덱스가 비슷해 보이기 시작할 때 혼동의 일반적인 원인입니다.

js
const product = {
  title: "책상 스탠드",
  price: 40,
  inStock: true,
};

console.log(`${product.title} costs ${product.price}`); // 책상 스탠드 costs 40

객체는 다른 값처럼 값입니다. const에 저장하거나, 배열에 넣거나, 함수에 전달하거나, 반환할 수 있습니다. 키는 그 부분에 이름을 제공하는데, 그것이 전부입니다: product.price는 그것이 무엇인지 말하는데, 변수에 있는 맨 40은 그렇지 않습니다.

Juno객체 만들기 객체는 관련된 값을 이름 아래에 모으고, 중괄호에 key: value 쌍으로 작성됩니다. 점과 키로 값을 읽으세요, user.name처럼. 대괄호 형식은 키에 홀수 문자가 있거나 변수에 있을 때만 사용하세요.
Juno객체 만들기 객체는 배열이 위치로 접근하는 곳에서 이름으로 값에 접근합니다. 점 표기법이 기본값입니다; 대괄호 표기법은 문자열로 키를 받으므로, 순수한 단어가 아닌 키나 변수에 있는 키에 사용하세요. user[field]field에 저장된 키를 읽는 반면 user.field는 리터럴 field 키를 찾고, 누락된 키는 오류 대신 undefined로 반환됨을 기억하세요.
Juno객체 만들기 키는 내부적으로 문자열이므로 user[27]user["27"]은 같은 슬롯을 칩니다, 누락된 키는 던지지 않고 undefined를 반환합니다. 점 표기법이 관용적입니다; 대괄호 표기법은 계산된 키를 가진 같은 조회이며 비-식별자 키와 동적 키가 필요합니다. 오타에서 나오는 그 조용한 undefined는 버그를 숨길 때까지 편리합니다.

객체 변경하기

객체는 만들어진 후 고정되지 않습니다. 새 키를 추가하거나, 기존 키를 변경하거나, 완전히 제거할 수 있습니다. 추가하거나 업데이트하려면 키에 할당합니다:

js
const user = {
  name: "민지",
};

user.age = 30; // 새 키 추가
user.name = "민지 김"; // 기존 키 업데이트

console.log(user); // { name: "민지 김", age: 30 }

키가 이미 존재하면 할당하면 값을 바꾸고, 존재하지 않으면 생성됩니다. 키를 제거하려면 delete를 사용합니다:

js
delete user.age;
console.log(user); // { name: "민지 김" }

여기가 사람들을 놀라게 하는 부분입니다. A const 객체는 여전히 그 속성을 변경할 수 있습니다. constuser 이름이 다른 객체를 가리킬 수 없다는 의미이지만, 그것이 가리키는 객체는 공정한 게임입니다:

js
const cart = { total: 0 };
cart.total = 25; // 괜찮음, 내부 변경
// cart = { total: 25 }; // 이것은 오류일 것임, 이름 재할당

객체는 변경 가능합니다: 생성 후 키를 추가, 업데이트, 제거합니다. 키에 할당하면 새로우면 생성되고 존재하면 덮어씁니다. 키를 제거하는 것은 delete의 일입니다:

js
const user = { name: "민지" };

user.age = 30; // 추가
user.age = 31; // 업데이트
delete user.age; // 제거

console.log(user); // { name: "민지" }

사람들을 잡는 것은 const입니다. const는 이름을 잠그고, 내용을 잠그지 않습니다. 바인딩은 새 객체로 재할당될 수 없지만, 그것이 보유하는 객체는 완전히 편집 가능합니다:

js
const cart = { total: 0, items: 0 };
cart.total = 25; // 허용됨, 객체 변경
cart.items += 1; // 허용됨
// cart = {}; // TypeError, const 바인딩 재할당

이것이 변경하려는 객체에도 const가 합리적인 기본값인 이유입니다. 변수를 다시 가리키고 싶지 않은 경우가 거의 없으며, const는 실수로 그렇게 하지 못하도록 방지하면서 객체 자체를 열어두는 이유입니다.

객체는 변경 가능합니다. 키에 할당하면 upsert(생성 또는 덮어쓰기)하고, delete는 제거합니다:

js
const user = { name: "민지", age: 30 };

user.role = "admin"; // 추가
delete user.age; // 제거

console.log(user); // { name: "민지", role: "admin" }

const 구분은 내부화할 것인데, 왜냐하면 const가 보호하는 것에 관한 것이기 때문입니다. const는 바인딩을 동결하고, 절대 값을 동결하지 않습니다. 이름은 재할당될 수 없으며, 그것이 참조하는 객체는 열려있습니다:

js
const cart = { total: 0 };
cart.total = 25; // 괜찮음, 참조된 객체 변경
// cart = { total: 25 }; // TypeError: 상수 변수에 할당

객체 자체를 실제로 잠그고 싶다면, Object.freeze(obj)는 키를 추가, 변경 또는 제거하지 못하도록 방지하지만, 이것은 얕은 동결이며(중첩된 객체는 변경 가능하게 유지됨) 비-엄격 코드에서 오류 대신 조용히 아무것도 하지 않습니다. 실제로는 거의 필요하지 않습니다. 유지할 가치 있는 습관은 기본적으로 const입니다: 바인딩이 안정적임을 나타내고 실제로 발생하는 실수인 우발적인 재할당을 차단하면서 정상적인 변경을 사용 가능하게 둡니다.

Juno객체 변경하기 키에 할당하여 추가하거나 업데이트하고, delete를 사용하여 제거합니다. 놀라움은 const입니다: user가 다른 객체를 가리키지 못하게 하지만, 그것이 보유하는 객체 내부를 여전히 변경할 수 있습니다. const가 모든 것을 잠글 것으로 기대하지 않는 데 시간이 걸렸습니다.
Juno객체 변경하기 할당은 키를 추가하거나 덮어쓰고, delete는 제거합니다. const는 이름을 잠그고, 내용을 잠그지 않으므로, const 객체는 완전히 편집 가능하게 유지되면서 변수 자체는 다시 가리킬 수 없습니다. 그것이 정확히 변경하려는 객체에도 const가 좋은 기본값인 이유입니다.
Juno객체 변경하기 할당은 키를 upsert하고, delete는 제거하며, const는 값이 아닌 바인딩을 보호하므로, 참조된 객체는 변경 가능한 상태로 유지됩니다. 객체를 반드시 잠궈야 하면, Object.freeze는 얕게 잠그고 엄격하지 않은 모드에서 오류 대신 조용히 실패합니다. 이를 드물게 사용하세요; const는 기본적으로 이미 실제로 나타나는 재할당 실수를 막습니다.

메서드와 this

객체의 값은 함수일 수 있습니다. 그럴 때 이를 **메서드**라고 합니다: 객체가 저장하는 사실이 아니라 할 수 있는 것입니다. 같은 점과 괄호로 호출합니다:

js
const user = {
  name: "민지",
  greet() {
    return `Hi, I am ${this.name}`;
  },
};

console.log(user.greet()); // Hi, I am 민지

내부의 새로운 단어는 this입니다. user.greet()을 호출할 때, this는 "이 메서드가 호출된 객체"를 의미하며, 여기서는 user입니다. 따라서 this.name은 같은 객체에서 name 키를 읽습니다. 이것이 메서드가 전달하지 않고 자신의 객체의 값에 접근하는 방식입니다.

함수가 객체의 값으로 저장될 때, 이를 **메서드**라고 합니다. 메서드는 객체가 그 데이터와 함께 행동을 전달하게 하고, this를 통해 그 데이터에 접근합니다:

js
const cart = {
  items: ["lamp", "desk"],
  total: 65,
  summary() {
    return `${this.items.length} items, ${this.total} total`;
  },
};

console.log(cart.summary()); // 2 items, 65 total

거의 모든 것을 다룰 this의 규칙: this는 호출 시간에 점의 왼쪽에 있는 객체입니다. cart.summary()를 호출하면 thiscart이므로, this.itemsthis.total은 같은 객체에서 읽습니다.

"호출 시간에"라는 문구는 중요합니다. this는 메서드를 쓸 때 고정되지 않으며, 메서드가 호출되는 방식으로 결정됩니다. cart.summary()로 호출하면 thiscart입니다; 함수를 빼내서 혼자 호출하면 this는 더 이상 cart를 가리키지 않습니다. 그 모서리는 나중에 만날 것이지만, 점으로 호출된 메서드의 경우 this는 정확히 당신이 원하는 대로 작동합니다.

객체에 저장된 함수는 **메서드**이며, this를 통해 객체의 자신의 상태에 접근합니다. 실제로 중요한 바인딩 규칙: this는 함수가 정의된 위치가 아니라 호출되는 방식으로 설정됩니다. 일반적인 메서드 호출의 경우, this는 점의 왼쪽 객체입니다:

js
const cart = {
  total: 65,
  discount: 0.1,
  finalPrice() {
    return this.total * (1 - this.discount);
  },
};

console.log(cart.finalPrice()); // 58.5

바인딩이 동적이므로, 메서드를 분리하면 깨집니다: const fn = cart.finalPrice; fn();cart 컨텍스트를 잃고 this는 더 이상 원하는 위치를 가리키지 않습니다.

실제적인 함정은 메서드로서의 화살표 함수입니다. 화살표는 자신의 this를 얻지 못하고, 정의된 주변 범위에서 this를 캡처합니다. 따라서 메서드로 사용된 화살표는 외부 this(최상위 레벨에서, 객체가 아님)를 읽지 않고 그것이 있는 객체의 this를 읽습니다:

js
const user = {
  name: "민지",
  greet: () => `Hi, I am ${this.name}`, // 잘못됨: `this`는 `user`가 아님
  greetOk() {
    return `Hi, I am ${this.name}`; // 맞음: 메서드 축약
  },
};

실행할 규칙: 함수가 this를 객체를 의미하게 해야 할 때 메서드 축약(greet() {})을 사용하고, 실제로 주변 this(거의 다른 곳)를 원하는 콜백을 위해 화살표를 예약합니다.

Juno메서드와 this 객체에 저장된 함수는 메서드이고, user.greet()처럼 점과 괄호로 호출됩니다. 내부에서 this는 메서드가 호출된 객체를 의미하므로, this.name은 그 객체의 자신의 name을 읽습니다. 이것이 메서드가 자신의 객체의 값에 어떻게 접근하는지입니다.
Juno메서드와 this 메서드는 객체에 있는 함수이며, this는 호출할 때 점의 왼쪽에 있는 객체입니다. 따라서 cart.summary()thiscart로 만듭니다. 함정은 this가 메서드를 쓸 때가 아니라 호출할 때 결정되므로, 메서드를 객체에서 빼내는 순간 중요해집니다.
Juno메서드와 thisthis는 함수가 있는 곳이 아니라 호출되는 방식으로 바인드되므로, 메서드를 분리하면 객체를 잃습니다. this를 객체를 의미하게 해야 할 때 메서드 축약을 사용하고, 주변 this(화살표가 내부 것을 캡처하므로 거의 다른 곳)를 원하는 콜백을 위해 화살표를 유지하세요. 그 화살표-메서드 혼합은 클래식이고 조용히 실패합니다.

객체와 배열 함께

대부분의 실제 데이터는 객체의 목록입니다: 많은 사용자, 많은 제품, 각 객체 하나의 같은 키를 가진 레코드. 객체를 배열에 넣습니다:

js
const products = [
  { title: "책상 스탠드", price: 40 },
  { title: "공책", price: 6 },
  { title: "펜", price: 3 },
];

console.log(products[0].title); // 책상 스탠드

위치로 하나의 객체에 도달하고(products[0]), 그 다음 점으로 그 필드 중 하나(.title)에 도달합니다. 연결되면, products[0].title은 첫 번째 제품의 제목을 읽습니다.

모든 객체에서 필드를 읽으려면 배열을 반복합니다:

js
for (const product of products) {
  console.log(product.title);
}
// 책상 스탠드
// 공책
// 펜

루프의 각 차례에, product는 목록의 하나의 객체이고, product.title은 그 제목을 읽습니다. 이 형태, 반복하는 객체의 배열은 당신이 할 대부분의 데이터 작업입니다.

객체의 배열은 대부분의 실제 데이터의 형태입니다: 각 객체는 레코드이며, 각각 같은 키를 공유합니다. 배열 액세스와 점 액세스를 결합하여 모든 단일 필드에 도달합니다:

js
const products = [
  { title: "책상 스탠드", price: 40 },
  { title: "공책", price: 6 },
  { title: "펜", price: 3 },
];

console.log(products[1].price); // 6

배열이므로, 배열 메서드는 그것에서 작동하며, 여기가 그들의 가치를 얻는 곳입니다. map으로 각 객체에서 하나의 필드를 가져오고, filter로 일치하는 레코드를 유지하고, reduce로 그들을 하나의 값으로 롤업합니다:

js
const titles = products.map((product) => product.title);
console.log(titles); // ["책상 스탠드", "공책", "펜"]

const total = products.reduce((sum, product) => sum + product.price, 0);
console.log(total); // 49

콜백은 반복당 하나의 객체를 받으며, 키로 그 필드를 읽습니다. 이것이 클릭되면, "각 레코드에 대해 이 필드를 가져오십시오"와 "모든 레코드에서 이 필드를 합계하십시오"는 원 라이너가 됩니다.

객체의 배열은 구조화된 데이터의 표준 형태이며, 배열 메서드는 그것으로 작동하는 방법입니다. 각 콜백은 하나의 레코드를 받으며; 키로 그 필드를 읽고 변환, 필터링 또는 집계합니다:

js
const orders = [
  { id: 1, total: 40, paid: true },
  { id: 2, total: 6, paid: false },
  { id: 3, total: 3, paid: true },
];

const paidTotal = orders
  .filter((order) => order.paid)
  .reduce((sum, order) => sum + order.total, 0);

console.log(paidTotal); // 43

연결이 위에서 아래로 파이프라인으로 읽혀집니다: 지불된 주문을 유지한 다음 그들의 합계를 합하십시오. 이것은 각 단계가 객체의 배열을 받고 다른 배열을 반환하기 때문에(또는, reduce의 경우, 단일 값) 깔끔하게 구성됩니다.

데이터가 성장함에 따라 기억할 한 가지: 이러한 객체는 참조로 보유되며, 아래의 고급 섹션이 정확하게 만듭니다. map 또는 forEach 콜백 내 객체를 변경하면 배열의 원본 레코드를 변경하며, 복사본을 변경하지 않으며, 이는 때때로 당신이 원하는 것이고 종종 놀라움입니다. 원본에 닿지 않고 변환하려는 경우, 주어진 객체를 편집하는 대신 새 객체를 빌드하십시오.

Juno객체와 배열 함께 대부분의 실제 데이터는 객체의 배열입니다: 각 항목이 같은 키를 가진 하나의 레코드인 목록. 하나에 products[0]로 도달하고, 그 다음 products[0].title로 필드에 도달합니다. 배열을 반복하여 모든 레코드에 닿으면, 당신이 할 대부분의 데이터 작업 뒤의 패턴이 있습니다.
Juno객체와 배열 함께 객체의 배열은 대부분의 실제 데이터가 도착하는 형태이며, 배열 메서드는 그것을 위해 만들어졌습니다. map은 각 레코드에서 필드를 가져오고, filter는 일치하는 것들을 유지하고, reduce는 그들을 합계하며, 콜백은 각 차례에 하나의 객체를 받습니다. "각 레코드에 대해 이 필드를 가져오십시오"는 루프를 멈추고 원 라이너가 됩니다.
Juno객체와 배열 함께 배열 메서드는 레코드 위의 파이프라인으로 연결됩니다: 필터로 축소한 다음 값으로 축소하고, 각 단계는 키로 필드를 읽습니다. 데이터가 성장함에 따라 이러한 객체는 참조로 보유되므로, map 또는 forEach 콜백 내 하나를 변경하면 배열의 원본을 제자리에 편집합니다. 원본에 닿지 않고 변환하려면, 주어진 객체를 편집하는 대신 새 객체를 빌드하십시오.

객체가 다음에 어디로 가는지

객체와 배열은 지속적으로 도달할 두 구조이며, 취급할 대부분의 데이터는 두 가지의 일종의 중첩입니다: 배열 필드를 가진 객체, 객체의 배열, 그리고 둘 다의 조합. 배열 메서드와 쌍을 이루면, 필요한 형태로 거의 모든 데이터를 형성할 수 있습니다.

다음 단계는 페이지에 객체를 사용하는 것입니다. DOM에 도달하면, 읽고 변경하는 요소는 또한 객체이며, 설정하는 키와 호출하는 메서드를 가지므로, 여기의 모든 것은 직접적으로 수행됩니다.