공부 정리/You Don't Know Js

[YDKJ] Objects & Classes - Object Foundations

경적필패. 2023. 9. 3. 21:51
반응형

요약

Chapter 1: Object Foundations

JS의 모든 것은 객체이다.

=> 이 것은 가장 만연하고 잘못된 사실 중 하나임!!!!

이 장에서는 객체로 시작하여, 프로토타입, this, 클래스를 위주로 알아볼 것.

 

Objects As Containers

여러 값을 단일 컨테이너에 모으는 일반적인 방법 중 하나는 객체를 사용하는 것.

ex

myObj = {

}

 

Defining Properties

객체 리터럴 중괄호 안에는 name:value쌍으로 정의함

myObj = {
    favoriteNumber: 42,
    isDeveloper: true,
    firstName: "Kyle"
};

 

위처럼 리터럴 값을 할당할 수도 있고, 표현식을 할당할 수도 있음.

function twenty() { return 20; }

myObj = {
    favoriteNumber: (twenty() + 1) * 2,
};

Looks Like JSON?

지금까지 보여준 객체 리터럴은 JSON과 유사함을 알 수 있음

{
    "favoriteNumber": 42,
    "isDeveloper": true,
    "firstName": "Kyle"
}

JSON과 JS 객체의 가장 큰 차이점은 속성은 이중 따옴표로 묶어야함.

JS객체 리터럴은 따옴표로 묶인 속성이 필요하지 않음 그러나 선택적으로 사용할 수는 있음.

예를들어, 숫자로 시작하거나 공백이 포함된경우 그러함.

 

myObj = {
    favoriteNumber: 42,
    isDeveloper: true,
    firstName: "Kyle",
    "2 nicknames": [ "getify", "ydkjs" ]
};

게다가 일반적으로 JSON구문이 더 엄격함.

=>JS는 주석, 객체 및 배열 표현식에서 후행, 쉼표를 허용함.

Property Names

객체 리터럴 내에서는 거의 항상 문자열 값으로 처리되거나 강제 형변환이 진행됨.

anotherObj = {
    42:       "<-- 이 속성 이름은 정수로 처리됩니다.",
    "41":     "<-- ...그리고 이것도 마찬가지로",

    true:     "<-- 이 속성 이름은 문자열로 처리됩니다.",
    [myObj]:  "<-- ...그리고 이것도 마찬가지로"
};

실제로 key,value를 사용해야될 경우 형변환에 의존하면 버그 발생확률이 높음...

형변환을 사용하지 않은 es6의 Map을 사용할 것을 권고

 

Symbols As Property Names

es6에는 symbol이라는 새로운 원시 값 유형이 추가 됨.

symbol을 통해 만들어진 값은 전역적으로 고유한 값을 가지게 됨.

myPropSymbol = Symbol("선택적, 개발자 친화적 설명");

anotherObj = {
    [myPropSymbol]: "안녕, Symbol!"
};

Concise Properties

객체 리터럴을 정의할 때, 원하는 값을 할당할 기존 스코프 내 식별자와 동일한 이름의 속성 이름을 사용하는 것이 일반 적임.

coolFact = "the first person convicted of speeding was going 8 mph";

anotherObj = {
    coolFact: coolFact
};

이를 축약해서

coolFact = "the first person convicted of speeding was going 8 mph";

anotherObj = {
    coolFact   // <-- 간결한 속성의 축약 표기
};

이렇게 표현하기도 함.

 

Object Spread

객체 리터럴내에서 스프레드 연산자를 이용하여, 객체를 복사할 수 있음.

anotherObj = {
    favoriteNumber: 12,

    ...myObj,   // 객체 전파, 'myObj'를 얕게 복사

    greeting: "Hello!"
}

이러한 작업은 순서대로 수행되기 때문에,

myobj에 favoriteNumber값이 있다면 덮어씌우게 됨.

 

Deep Object Copy

스프레드 복사는 완전한 깊은 객체 복제를 수행하지 않으므로 원시값만을 포함하는 객체를 복제하는데 적합함.

 

깊은 객체 복제를 위해서는

1. 라이브러리 사용

2. JSON.parse(JSON.stringify(..))  사용

3. 최근에 추가된 jjs에 제공되는 api

myObjCopy = structuredClone(myObj);

Accessing Properties

일반적으로는 연산자를 사용하는 것이 좋음

myObj.favoriteNumber;    // 42
myObj.isDeveloper;       // true

그러나 이 방법으로 접근할 수 없는 경우 대괄호를 이용하면됨.

myObj["2 nicknames"];    // [ "getify", "ydkjs" ]
anotherObj[42];          // "<-- 이 속성 이름은..."
anotherObj["41"];        // "<-- 이 속성 이름은..."

Object Entries

myObj = {
    favoriteNumber: 42,
    isDeveloper: true,
    firstName: "Kyle"
};

Object.entries(myObj);
// [ ["favoriteNumber",42], ["isDeveloper",true], ["firstName","Kyle"] ]

entries를 이용해 객체의 key,value값을 가져올 수 있음.

 

Destructuring

myObj = {
    favoriteNumber: 42,
    isDeveloper: true,
    firstName: "Kyle"
};

const { favoriteNumber = 12 } = myObj;
const {
    isDeveloper: isDev,
    firstName: firstName,
    lastName: lname = "--missing--"
} = myObj;

favoriteNumber;   // 42
isDev;            // true
firstName;        // "Kyle"
lname;            // "--missing--"

이 코드처럼 비구조화를 사용할 수 있음.

위 예시에서 보면 객체의 isDeveloper 값을 찾아서 isDev에 넣어줌.

그러나!!!

항상 이 구조를 사용할 필요는 없음 때로는

isDev = myObj.isDeveloper만 사용해도 충분함.

 

Conditional Property Access

최근 es2020에서는 옵셔널체이닝이라는 기능이 추가되엇음.

?. 연산자로,

myObj?.favoriteNumber

이렇게 사용가능.

?. 왼쪽의 값이 null이나 undefined면 나머지속성은 생략되고 undefined가 리턴됨.

이를 이용하여 안전하게 접근을 할 수 있게 되었음.

 

 

Accessing Properties On Non-Objects

fave = 42;

fave;              // 42
fave.toString();   // "42"

fave는 원시값인데 어떻게 toString()이라는 속성에 접근할 수 있을까?

 

간략하게 말하자면, js는 객체가 아닌 값에 속성접근을 하면 일시적으로 객체로 감싸서 객체에 대한 속성 접근을 수행함.

이를 boxing이라고 부름.

 

 

Deleting Properties

anotherObj = {
    counter: 123
};

anotherObj.counter;   // 123

delete anotherObj.counter;

anotherObj.counter;   // undefined

일반적으로 생각하는 것과 달리, delete는 메모리 해제를 하지않고 객체에서 속성을 제거하는 것뿐.

따라서 후속 스윕에 제거될 것임.

delete는 undefined나 null을 할당하는것과는 다름!!

 

Determining Container Contents

객체가 어떤 값을 가지고 있는지 확인하려면 다음과 같이 할 수 있음.

myObj = {
    favoriteNumber: 42,
    coolFact: "the first person convicted of speeding was going 8 mph",
    beardLength: undefined,
    nicknames: [ "getify", "ydkjs" ]
};

"favoriteNumber" in myObj;            // true

myObj.hasOwnProperty("coolFact");     // true
myObj.hasOwnProperty("beardLength");  // true

myObj.nicknames = undefined;
myObj.hasOwnProperty("nicknames");    // true

delete myObj.nicknames;
myObj.hasOwnProperty("nicknames");    // false

in연산자는 객체의 체인까지 확인하지만,

hasOwnProperty는 대상객체만 확인함.

es2020에서는 hasOwn이라는 함수를 사용함.

Object.hasOwn(myObj, "favoriteNumber");

hasOwnProperty와 동일한 작업을 수행하지만, 객체 값 외부에서 객체의 [[prototype]]을 통해 호출하는 대신 정적 도우미로 호출하여 더 안전함.

 

Containers Are Collections Of Properties

객체의 가장 일반적인 사용법은 여러 값을 담는 컨테이너임.

우리는 속성 컨테이너 객체를 다음과 같은 방법으로 생성하고 관리함

  • 속성(이름이 지정된 위치)을 정의. 이는 객체를 생성할 때나 나중에 수행할 수 있음.
  • 값을 할당함. 이 역시 객체를 생성할 때나 나중에 수행할 수 있음
  • 나중에 위치 이름(속성 이름)을 사용하여 값을 접근
  • delete를 사용하여 속성을 삭제함.
  • in, hasOwnProperty(..) / hasOwn(..), Object.entries(..) / Object.keys(..) 등을 사용하여 컨테이너 내용을 결정함.

 

느낀 점

객체에 대해 가볍게 알아볼 수 있는 내용들이었음.

entries, react에서 먼저 접했던 구조분해, json과 유사한 점을 배울 수 있었다.

또한 오랜만에 boxing에 대해서도 가볍게 복습할 수 있었다.

반응형