드디어 나름 기획했던 javascript 기초 시리즈의 마지막 객체편이다.

1편부터 함께 build-up하신 분이 있다면 우선 진심으로 감사드리고🙇‍♂️ 또 너무너무 고생하셨다는👍👍 말씀을 꼭 드리고 싶다.



> 객체의 구조와 생성하는 방법

객체는 {} 안에 keyvalue가 한쌍으로 이루어진
property(속성)라는 것이 담긴 형태로 구성되어 있다.

객체는 두가지 방법에 의해 생성할 수 있다.

객체의 선언은 주로 리터럴(literal) 문법을 쓰고
생성자(constructor) 문법은 추가적인 기능이 필요한 경우에 사용한다.

우선 리터럴(literal) 문법과 함께 구조를 알아보며 객체를 완성시켜보자.


▶︎ {}

✔️ 객체는 {}(중괄호) 안에 key:value가 담긴 형태로 구성된다.

✔️ 객체 또한 다른 자료형들과 마찬가지로 변수에 할당하여 사용한다.

let 객체담은변수 = { key:value };

✔️ 객체 안에 내용이 많으면 코드를 구분하여 가독성을 높여주자.

let 객체담은변수 = { 
  key:value,
  key2:value,
  key3:value
};

▶︎ key

✔️ key는 자신의 짝인 value를 가리키고 있는 이름과 같은 것이다.

✔️ 데이터를 변수에 할당할때 넣는 변수이름을 짓는것과 유사하다.

✔️ key는 변수처럼 몇몇 규칙 내에서 마음대로 이름을 지어줄 수 있다.

// "객체담은변수"에 객체를 할당
let 객체담은변수 = {
  // key이름은 변수이름짓기처럼 자유롭다
  key이름은내맘대로: "value"
};

💡 property key는 변수이름과 다르게 예약어(let, for 등)가 사용 가능하다.
숫자도 가능하며 문자형이 아닌 경우 자동으로 문자형으로 변환된다.

let 자유로운객체 = {
  let: "'s go",
  918: "구여미 생일"
};
console.log(자유로운객체.let); // 's go
console.log(자유로운객체[918]); // 구여미 생일
console.log(자유로운객체["918"]); // 구여미 생일

❗️0918처럼 key가 0부터 시작하고 뒤에 정수가 쓰이는 경우에는 문자열로 자동변환 되지 않는다.(또한 0.918은 되고 09.18은 안된다.)


▶︎ value

✔️ key의 다음으로 :(콜론, 식별자)을 넣고 그 다음에 value를 넣는다.

✔️ value객체이름.key 혹은 객체이름["key"]를 통해 불러올 수 있다.

let 객체담은변수 = {
  // "key이름은내맘대로" key의 value로 "할수있다!🙆‍♀️"를 넣었다.
  key이름은내맘대로: "할수있다!🙆‍♀️"
};

console.log(객체담은변수.key이름은내맘대로); // 할수있다!🙆‍♀️

▶︎ property

✔️ key:value 한 쌍을 가리켜 property라고 부른다.

  // property
  key이름은내맘대로: "할수있다!🙆‍♀️"

✔️ property와 property는 ,로 구분해줘야 한다.

let 객체담은변수 = {
  key이름은내맘대로: "할수있다!🙆‍♀️",
  객체뒤에는: "콤마를!!",
  마지막property에는: "콤마 안써도 됩니당!"
} 

이제부터는 관련 자료를 찾아보다가 "어떤 것의 property의 key" 혹은
"property의 value"라고 말한다면 지금 언급하고 있는 것이 객체라는 것을
자동으로 인지할 수 있다.



▶︎ 객체 생성자(constructor) 문법

생성자 문법은 객체를 처음 배운다면 이해하기 어렵기 때문에
객체가 이렇게 생성될수도 있구나 하는 정도만 알고 다음으로 넘어가자.

✔️ 변수에 new Object()를 할당하여 변수명을 통해 객체를 생성할 수 있다.

let 객체소환술사 = new Object();

// 빈 객체를 소환했다.
console.log(객체소환술사); // {}

✔️ 생성자 문법으로 빵틀처럼 재사용 할 수 있는 객체 생성 코드를 만들 수 있다.

function 몬스터(name, hp, ability) {
  this.name = name,
  this.hp = hp,
  this.ability = ability
}

// new 몬스터()를 생성자 함수라고 한다.
// 객체를 생성함과 동시에 함수에 argument를 전달한다.
let 소환술사 = new 몬스터("비둘기", 1, "정수리에 물똥");

let 악당소환술사 = new 몬스터("병아리", 0.3, "귀여미");

// 생성자 함수를 거쳐 key는 같지만 value는 다른 property를 가진 객체를 돌려줬다.
console.log(소환술사); // 몬스터 { name: '비둘기', hp: 1, ability: '정수리에 똥' }
  
console.log(악당소환술사); // 몬스터 { name: '병아리', hp: 0.3, ability: '귀여미' }

💡 객체 생성자 문법은 유사한 객체를 만들어야 할 때 사용된다.
재사용할 형태를 정해둔 후 객체를 생성할 때 넣은 입력값에 따라서
지정해둔 일정한 틀 안에서 그때그때 다른 값이 리턴되는 코드를 만들 수 있다.

🤗 지금은 생성자 함수에 대해 알지 못해서 이해하기 어렵겠지만
지금까지 해왔듯 차근히 배워간다면 모두 이해할 수 있는 내용이다.

객체 기본편에서 깊게 다루기에는 맞지 않고 지금 배우는 객체의 기능이
앞으로 어떻게 확장되어가는지, 그리고 어떻게 쓰이는지 예시로 넣어보았다.





> 객체란

객체는 왜 객체형이라는 자료형으로 따로 분류되어있을까?

원시형과는 다른 특성이 있으니 구분지었을 것이다 라고 선을 긋고
원시형과 비교하며 객체만의 새로운 개념들을 받아들여보자.

우선 객체의 형태와 특성을 가볍게 훑어보겠다.

▶︎ 객체는 모든 자료형을 가질 수 있다.

✔️ 말이 웃기지만 객체는 객체형이다. 마치 인간을 인간형이라고 하는 것처럼.

✔️ 중요한건 그렇기 때문에 자신의 자료형만 가질 수 있는 원시형과는 다르다.

// 원시형인 문자형에 undefined를 담았다.
let 나는무엇인가 = "undefined";

// undefined는 문자형이 되어버린다.
console.log(typeof 나는무엇인가); // string

undefined자료형은 문자형을 의미하는 ""안에 들어가면 문자열이 된다.
문자열은 undefined라는 자료형을 담을 수 없는 것이다.


// 객체에 undefined를 담았다.
let 나는무엇인가 = {
  언디파인드type: undefined,
}

// 객체는 undefined 자료형 그대로를 보존한다.
console.log(typeof 나는무엇인가.언디파인드type);  // undefined

하지만 객체에는 데이터 본래의 자료형 그대로 저장된다.


▶︎ 객체는 이름표가 붙은 상자다(key:value)

✔️ 배열에 index가 있다면 객체에는 key라는 이름표가 있다.

✔️ 배열에서 index로 데이터(element)를 불러오듯 객체는 key를 통해 데이터(value)를 불러온다.

let 당신은누구인가 = {
  박효신: "둘도 없는 킹왕짱 가수",
  원빈: "방부제로 샤워하는 배우",
  정우성: "존재가 멋 그 자체인 휴먼"
}

console.log(당신은누구인가.박효신); // 둘도 없는 킹왕짱 가수

박효신(key)이라는 상자(property)에 "둘도 없는 킹왕짱 가수"라는 문자열(value)이 저장되어있다.


▶︎ 객체상자는 변수에게 열쇠를 나눠준다(reference)

🤗 이 부분은 약간어려울 수도 있기 때문에 건너뛰고 다른 내용부터 학습하고
객체에 어느정도 익숙해진 후 돌아와서 다시 읽어봐도 좋다.

✔️ 원시형 데이터를 할당한 원본변수를 새로운변수의 값으로 할당한 경우, 새로운변수는 원시형 데이터를 복사해서 원본변수와 같은 값을 가진다.

✔️ 그렇다면 그 새로운변수에 다시 할당된 값을 수정하면 어떻게 될까?

// 원시형을 할당한 원본변수
let 사람이되고싶은_곰 = "곰";

// 새로운 변수에 "사람이되고싶은_곰" 변수를 할당했다.
let 마늘을열심히먹은_곰 = 사람이되고싶은_곰;

// 둘은 같은 값을 갖는다.
console.log(사람이되고싶은_곰); // 곰
console.log(마늘을열심히먹은_곰); // 곰

// "사람이되고싶은_곰" 변수를 할당한 새로운변수에 할당된 값을 수정해보자.
마늘을열심히먹은_곰 = "웅녀";

// 사람이되고싶은_곰 변수는 값이 바뀌지 않았다!
console.log(사람이되고싶은_곰); // 곰
console.log(마늘을열심히먹은_곰); // 웅녀

새로운변수에 같은 원시형 데이터를 할당했을 경우, 기존변수에 할당된 원시형 데이터는 변함이 없고 서로 다른 값을 가지게 된다.
❗️복사된 원시형 데이터는 원본 원시형 데이터와 상관 없는 새로운 데이터다.
❗️원시형 데이터는 변경 불가능한 값(immutable value)이기 때문에 값을 수정할 수 없다.


✔️ 반면 객체를 할당한 변수는 완전히 다르게 동작한다.

// 객체를 할당한 원본변수
let 사람이되고싶은_호랑이 = { 
  호랑이: "마늘은 싫어"
}

// 새로운 변수에 "사람이되고싶은_호랑이" 변수를 할당했다.
let 마늘을안먹은_호랑이 = 사람이되고싶은_호랑이;

// 둘은 같은 값을 갖는다.
console.log(사람이되고싶은_호랑이); // 마늘은 싫어
console.log(마늘을안먹은_호랑이); // 마늘은 싫어

// "사람이되고싶은_호랑이" 변수를 할당한 변수에 새로운 값을 할당해보자.
마늘을안먹은_호랑이.호랑이 = "아몰라! 마늘안먹어 나 사람안할래!!";

// "사람이되고싶은_호랑이" 변수도 값이 바껴버렸다!
console.log(사람이되고싶은_호랑이); // 아몰라! 마늘안먹어 나 사람안할래!!
console.log(마늘을안먹은_호랑이); // 아몰라! 마늘안먹어 나 사람안할래!!

💡 객체와 참조(reference)
새로운변수에 할당된 객체의 내용을 수정했더니 원본변수의 객체 내용까지 변경되어 버렸다.

❗️어떤 변수에 할당된 객체는 그 변수 자체에 귀속되는 것이 아니라 자신을 할당한 변수에게 객체 자신을 열수있는 열쇠를 준다고 생각해보자.
그래서 객체를 담고있는 원본변수를 새로운변수에 할당하는 것은 원본변수가 객체에게 받은 열쇠만 복사해간다고 기억하자.

❗️하지만 새로운 변수에 원시값을 할당하면 둘의 관계는 끊기고 원본변수의 객체의 값은 변하지 않는다.

🤗 정확히는 객체는 별도의 메모리에 저장되고 객체를 할당한 변수에는 그 객체에 대한 참조값(메모리 주소)이 저장되어 있는 것이다.
원시형 데이터는 자신이 할당된 변수에 값이 저장된다.


✔️ 객체는 동일한 데이터라는 기준이 원시형과는 다르다.

✔️ 원시형은 데이터의 값이 같으면 JavaScrip는 동일한 데이터라고 판단하지만 객체는 참조값(메모리 주소)이 같아야 동일한 데이터라고 판단한다.

// 동일한 값을 가진 원시형
let 문자열1 = "나는 고구마";
let 문자열2 = "나는 고구마";
console.log(문자열1 === 문자열2); // true

// 동일한 값을 가진 객체 
let 객체1 = { 나는: "고구마" };
let 객체2 = { 나는: "고구마" };
console.log(객체1 === 객체2); // false

// 동일한 참조값을 가진 객체
let 객체3 = { 나는: "고구마" };
let 객체4 = 객체3;
console.log(객체3 === 객체4); // true




> 객체는 왜 필요할까

객체는 여러가지 모든 자료형의 데이터를 모아놓을 수 있는 상자와 같은 존재다.

그런데 어디서 많이 들어본 특징이다.

맞다. 배열 역시 데이터를 모아놓을 수 있고 가져와 쓸 수 있는데..
그렇다면 객체는 왜 만들어졌고 존재하는지 궁금해질 수 밖에 없다.

▶︎ 객체의 이름표 key는 내마음대로

✔️ 배열의 index는 0, 1, 2...와 같은 숫자가 내 의지와 상관 없이 element에 지정된다.

✔️ 하지만 객체는 내가 원하는대로 value에 key를 붙여줄 수 있다.

let 컴퓨터꺼 = ["memory", "cpu", "ssd"];

console.log(컴퓨터꺼[0]); // memory


let 내꺼 = {
  맛난: "아이스크림",
  예쁜: "여자친구",
  자꾸감기는: "눈"
};

console.log(내꺼.맛난); // 아이스크림

💡 연결하려는 value에 따라 연상하기 쉬운 이름으로 지어줄 수 있기 때문에
데이터를 사용할 때 기억하기도 편리하고 각각의 데이터가 의도하는 것
무엇인지 알려주기도, 파악하기도 쉽다!


▶︎ 객체의 key는 너무 특별해서

✔️ 배열의 index는 element의 추가, 삭제에 따라 컴퓨터 마음대로 변화된다.

✔️ 따라서 내가 너무 똑똑해서 index와 연결되는 element들을 외웠다 해도
element 추가/삭제가 빈번히 발생한다면.. 점점 미쳐가며 의도치 않은
element를 가져올 확률이 높아진다.

🤗 실재로 index를 기억해서 element를 다룬다는 것이 아니라
index로 특정 데이터를 지목하여 사용하는 것이 지속적으로는 거의
불가능하고 의미없다는 말이다.


✔️ 반면 객체의 key는 임의로 누가 조작하거나 삭제하지 않는 이상 변하지 않으며
(value를 임의로 변경하지 않는 이상) 항상 동일한 value를 지목하고 있다.

// 배열
let 컴퓨터꺼 = ["memory", "cpu", "ssd"];

console.log(컴퓨터꺼[0]); // memory
// "memory"가 삭제되었다.
컴퓨터꺼.shift(컴퓨터꺼[0]);
// 똑같은 index를 불러왔지만 삭제된 "memory" 대신 "cpu"를 꺼내왔다.
console.log(컴퓨터꺼[0]); // cpu


// 객체
let 내꺼 = {
  맛난: "아이스크림",
  예쁜: "여자친구",
  자꾸감기는: "눈"
};

console.log(내꺼.맛난); // 아이스크림
// "맛난"이 삭제되었다.
delete 내꺼.맛난;
// "맛난"이라는 것은 없다고 말해준다. 
console.log(내꺼.맛난); // undefined

💡 반복문과 배열에서 알아봤듯 배열은 배열만의 장점들이 있다.
배열은 배열 전체의 길이를 간단하게 파악할 수 있고 전체 element들에 대한
특정 연산을 쉽고 빠르게 수행할 수도 있는 특수성이 있다.
객체보다 후진게 아닌 목적이 다른 도구라고 생각하자.

🤗 개인적으로 배열은 데이터 묶음 전체에 대한 처리와 관련하여 활용도가 높고 변화되는 데이터에 대한 대응 또한 유연한 것이 특징이고, 객체는 관련된 데이터/연산을 목적에 따라 묶어음으로써 규모적 관리의 용의성이 높고 그 안에서 개별적으로 이름을 붙여줄 수 있어서 각각의 데이터/연산 단위로도 관리하고 사용하기 편리하다고 정리하고 있다.


▶︎ 배열이랑 같은 주머니인데 좀 다르다

✔️ 배열도 분명 모든 자료형을 담을 수 있고 함수도 마찬가지다.

let 배열이 = [function 여긴어디인가(a, b) { return a+b }, "이야 나 함수도 담는다야"]

console.log(배열이[0]); // [function: 여긴어디인가]

✔️ 심지어 연산도 된다.

// 변수이름 짓다가 하루가 다 가서.. 이해 부탁드리겠습니다.
let 배열이네집 = [function 여긴어디인가(a, b) { return a+b }, "이야 나 함수도 담는다야"];

console.log(배열이네집[0](9, 18)); // 27

🤗 배열에 함수를 넣어서 사용할 일은 없으니 참고만 하고 넘어가도록 하자.


✔️ but 앞서 확인했듯 배열의 index는 불안정하고 기억하기 어려우며 또한
우리가 아는 배열의 사용법과는 추구하는 결이 다르다는 것이 직감적으로 느껴진다.

indexOf() method를 이용해 index를 찾을 수 있겠지만 번거롭다.


✔️ 반면에 객체는 함수를 담기에 참 좋은 주머니다. 언제든 key로 함수를 부를 수 있다.

let 김객체네집 = {
  여긴또어딘가: function(a, b) { return a+b }
};

console.log(김객체네집.여긴또어딘가(9, 18)); // 27

💡 이렇게 객체 안에 있는 함수를 method(메소드)라고 부른다.


✔️ 단축구문까지 만들어진걸 보면 그만큼 method는 자주 사용된다는걸 눈치챌수있다.

let 김객체네집 = {
  여긴또어딘가(a, b) { return a+b }
};

console.log(김객체네집.여긴또어딘가(9, 18)); // 27

객체에 함수를 넣음으로써 기능을 가진 객체가 되었으며 이제는 단순히 데이터만 담아 모아놓는 주머니가 아니게 되었다.
이러한 특성들을 바탕으로 객체는 다양한 일을 할 수 있게 된다.(=배워야할게많다)
JavaScript는 다 계획이 있었다.🤤





> 객체 접근하기

객체의 property에 접근하는 방법에는 두가지가 있다.

왜 굳이 두가지 방법으로 나누어놨는지 이유를 알아보도록 하자!

▶︎ dot notation(점 표기법)

✔️ property의 value는 객체이름.key와 같은 형태로 객체에서 가져오려는 key 앞에 .(dot)을 넣어서 불러올 수 있다.

let 미국양꼬치 = {
  야_몇$있냐: "1센트에 한대다 솔직히 말해라"
};

console.log(미국양꼬치.야_몇$있냐); // 1센트에 한대다 솔직히 말해라

✔️ 하지만 key에 띄어쓰기가 있거나 숫자로 시작하거나 특수문자($, _ 제외)가 있는 경우 dot notation을 쓸 수 없다.

let 미국양꼬치 = {
  "야 몇$있냐": "1센트에 한대다 솔직히 말해라"
};

console.log(미국양꼬치.야 몇$있냐); // SyntaxError: missing ) after argument list

❗️key에 띄어쓰기나 특수문자가 있는 경우 ""로 감싸 문자열로 만들어야 한다.


▶︎ brackt notation(대괄호 표기법)

✔️ property 호출시 key를 [](bracket notation)에 넣으면 key가 어떤 형태의 문자열이라도 읽을수 있다.

let 미국양꼬치 = {
  "야 몇$있냐": "1센트에 한대다 솔직히 말해라",
  "🕺 이눔시끼!!": "어디가!!"
};

// 특수문자나 띄어쓰기가 있어도 읽어온다.
console.log(미국양꼬치["야 몇$있냐"]); // 1센트에 한대다 솔직히 말해라
console.log(미국양꼬치["🕺 이눔시끼!!"]); // 어디가!!

❗️[] 안에 key는 꼭 따옴표로 묶어줘야 동작한다.
따옴표는 '', "", `` 중에 아무거나 사용해도 된다.


✔️ property의 key를 변수에 할당할 수도 있으며 경우도 [""]로 가져올 수 있다.

let 미국양꼬치 = {
  "야 몇$있냐": "1센트에 한대다 솔직히 말해라",
  "🕺 이눔시끼!!": "어디가!!"
};

// 변수에 key를 할당
let 나쁜사람 = "야 몇$있냐";

// bracket notation -> success
console.log(미국양꼬치[나쁜사람]); // 1센트에 한대다 솔직히 말해라

// dot notation -> fail
console.log(미국양꼬치.나쁜사람); // undefined




> 객체와 배열이 섞인 객체에 접근하기

객체는 앞서 말했다시피 모든 자료형을 property로 가질 수 있다.

따라서 property에 배열과 객체가 섞인 value가 있을 수도 있다.

우리는 이미 열쇠를 쥐고 있는 것이다.

▶︎ 필요한 것

✔️ 객체에 접근하기 위해서는 .key["key"]가 필요하고 배열에 접근하려면 [index]가 필요하다는 것을 우리는 배웠다.

✔️ 접근법만 알면 우리는 복잡해 보이는 객체와 배열이 섞인 value에 쉽게 닿을 수 있다.


▶︎ 복잡한 객체를 만난 우리

✔️ 아래 예문을 통해 우리는 잠시 심마니가 되어 300년산 산삼🥕을 찾아볼 것이다.

let 심마니 = {
  잡초: "안녕 나는 잡초야",
  사과숲: ["뭐야", "나한테", "사과해"],
  숲속: ["가시덤불", ["반짝임", {
    홍삼:["나로 만족할텐가", "🤔", 1, 2, 3, "에잇!!", {
      휘적휘적:["음?!!", {
        무언가빛난다:["흙", "300년산 산삼🥕", "흙"]
      }
    ]}]
  }]]
};

✔️ 객체를 만나면 .객체이름을, 그 객체의 value가 배열이면 [index]로 접근하면 끝.


▶︎ 정답

console.log(심마니.숲속[1][1].홍삼[6].휘적휘적[1].무언가빛난다[1]); 
// 300년산 산삼🥕




> property 확인, 추가, 수정, 삭제하기

▶︎ 확인

✔️ undefined로 확인하기.

  • 객체이름.key === undefined 조합으로 property의 존재를 확인할 수 있다.
let 빈깡통 = {};

console.log(빈깡통.내용물 === undefined) // true


let 새로사온깡통 = { 내용물: "찰랑찰랑" };

console.log(새로사온깡통.내용물 === undefined) // false

✔️ in연산자

  • "key" in 객체이름으로 property 존재 여부를 확인할 수 있다.

  • 찾는 property가 있으면 true 없으면 false를 반환한다.

let 서랍장 = {
  첫번째: "양말",
  두번째: "플링글스"
}

console.log("두번째" in 서랍장); // true

✔️ ❗️그러나 객체이름.key === undefined는 찾는 property가 없어도 true를 반환한다.

✔️ 반면 in연산자는 property가 없으면 false 반환하기 때문에 되도록 정확도가 더 높은 in 연산자를 쓰자.

let 서랍장 = {
  첫번째: "양말",
  두번째: "플링글스",
}

console.log(서랍장.세번째 === undefined); // true

console.log("세번째" in 서랍장); // false

▶︎ 추가

✔️ 객체이름.추가할key = 추가할value로 객체에 property를 추가할 수 있다.

let 서랍장 = {
  첫번째: "양말",
  두번째: "플링글스",
}

// 
서랍장.세번째 = "비상금 50만원";

console.log(서랍장);
/* { '첫번째': '양말',
'두번째': '플링글스',
'세번째': '비상금 50만원' } */

▶︎ 수정

✔️ 수정하고 싶은 property에 대해 객체이름.수정할 property의 key = 새로운 value로 property의 value를 수정할 수 있다.

let 서랍장 = {
  첫번째: "양말",
  두번째: "플링글스",
  세번째: "비상금 50만원"
}

서랍장.두번째 = "반만 남은 플링글스"

console.log(서랍장.두번째);
/* { '첫번째': '양말', 
'두번째': '반만 남은 플링글스', 
'세번째': '비상금 50만원' } */

▶︎ 삭제

✔️ delete 연산자를 객체이름.key 앞에 써주면 property는 삭제된다.

let 서랍장 = {
  첫번째: "양말",
  두번째: "반만 남은 플링글스",
  세번째: "비상금 50만원"
}

delete 서랍장.세번째

console.log(서랍장);
/* { '첫번째': '양말',
'두번째': '반만 남은 플링글스' } */

▶︎ ❗️상수 const와 객체

✔️ const로 선언된 객체는 수정되기 때문에 주의해야 한다.

✔️ 객체 전체를 대상으로 수정하려 할 경우에는 수정되지 않는다.

const 불변의사랑 = {
  나는당신뿐이에요: "수지"
}

// 기존 property를 재할당 할 수 있다.
불변의사랑.나는당신뿐이에요 = "수지, 블랙핑크, 트와이스";

console.log(불변의사랑.나는당신뿐이에요); // 수지, 블랙핑크, 트와이스


// 새로운 property도 추가로 할당 가능하다.
불변의사랑.어제까지는 = "한가인";

console.log(불변의사랑);
/* { 
  '나는당신뿐이에요': '수지, 블랙핑크, 트와이스', 
  '어제까지는': '한가인' 
} */


// 객체 전체는 재할당 할 수 없다!!
불변의사랑 = { 두사랑: "이혜리, 강민경"}; // TypeError: Assignment to constant variable.




> 객체와 반복문

배열과 반복문에서 참고로 다룬 그대로의 내용이다.

약속대로 다시 가져왔으니 그때 이해가 어려웠다면 이제는 좀 더 쉬울거라 믿고
그냥 skip했었다 해도 상관없으니 이제부터 알아보자.

▶︎ for..in 반복문으로 객체 순회하기

✔️ 객체 역시 배열과 마찬가지로 반복문을 쓸 수 있다.

✔️ for..in문으로 객체의 key를 순회할 수 있으며 모든 property를 다룰 수 있다.

✔️ 기본 형태는 for (let key in object) {...}()는 각각

  • let key는 property들의 key를 나타내는 변수로 변수명은 아무렇게나 지어도 상관 없으며 이것을 통해서 property를 불러올 수 있다.
  • in은 for과 마찬가지로 for..in문을 구성하는 기본 뼈대로 그대로 작성한다.
  • object에는 가져올 객체를 담고있는 변수명을 넣고 key를 가리키는 변수명과 함께 object[key]의 형태로 property의 value를 불러올 수 있다.
let 게임평가 = {
  서머너즈워: "즐거웠다",
  라그나로크: "음머~~",
  리니지: "nc주식을 샀어야해"
}

for (let 너의정보는 in 게임평가) {
  console.log(`게임 ${너의정보는}는 내 기억에 ${게임평가[너의정보는]}이다.`); 
}
/* 게임 서머너즈워는 한마디로 "즐거웠다"다.
게임 라그나로크는 한마디로 "음머~~"다.
게임 리니지는 한마디로 "nc주식을 샀어야해"다.*/

❗️객체는 배열처럼 index로 정렬되지 않고 객체만의 방식으로 정렬된다.
정수 프로퍼티(integer property)는 key가 "1"과 가까운 부터 순서대로 정렬되고 나머지는 객체에 추가한 순서대로 출력된다.





> 배열은 왜 객체형일까?

결론부터 말하자면 배열은 객체형의 모든 특성을 가지고 있다.

참조값으로 접근되며 모든 자료형을 수용하고 값을 수정할 수 있다.

▶︎ 참조값

✔️ 객체는 변수에 저장되는 것이 아니라 메모리에 저장되어 참조값으로 접근된다.

✔️ 배열 또한 참조값에 의해 접근되며 값이 같으면 동일한 값이라고 판단하는 원시형과 다르게 값이 같아도 동일한 배열로 보지 않고 다른 배열로 판단된다.

let 배열1 = [ "고구마" ];
let 배열2 = 배열1;
let 배열3 = [ "고구마" ];

console.log(배열1 === 배열2); // true
console.log(배열1 === 배열3); // false



let 원시형1 = "고구마";
let 원시형2 = 원시형1;
let 원시형3 = "고구마";

console.log(원시형1 === 원시형2); // true
console.log(원시형1 === 원시형3); // true

▶︎ 모든 자료형 수용

✔️ 객체형의 특성대로 모든 자료형을 가질 수 있다.

let 객체 = {
  문자형: "고구마", 
  숫자형: 123, 
  불린형: true, 
  undefined: undefined, 
  null: null, 
  배열: ["array"],
  객체: { key: "value" }
};

let 배열 = [ "고구마", 123, true, undefined, null, ["array"], { key: "value" }];


// 모든 내용이 이상 없이 출력된다. 생략하겠다.
console.log(객체); 
console.log(배열); 

▶︎ 수정이 가능한 값

✔️ 객체를 제외한 모든 값은 변경 불가능한 값(immutable value)이다.

✔️ 문자형을 할당한 변수의 문자를 약간 수정하면 그건 변경이 아닌 새로운 문자형이다.

✔️ 하지만 객체는 값을 수정할 수 있고 배열 또한 그렇다.

let 구황작물 = "고구마";
구황작물 = "고구마, 감자";

console.log(구황작물); // 고구마, 감자


let 텃밭 = ["고구마", "감자"];
텃밭.pop();

console.log(텃밭); // ['고구마']

문자열은 "고구마"에서 "고구마, 감자"라는 새로운 문자열로 대체되었지만,
배열은 "감자"라는 값을 제거하고 "고구마"라는 값만 가지게 수정된 것이다.


▶︎ MDN 형님의 결정타!

구글에 js자료형이라고 검색하면 가장 첫번째에 나오는 MDN의 링크를 클릭하면
"배열(Arrays)는 정수키를 가지는 일련의 값들을 표현하기 위한 오브젝트이다." 라고
명시되어있다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Data_structures#arrays





🌈 작은회고 🤔

드디어 끝났다 나의 자바스크립트 기초편이.🥲
처음 기초편을 기획했을 때는 최대한 친절하게 세심한 부연설명과
가장 쉬운 방법으로 설명해보자
하는 목표로 시작했다.
그 결과는 굉장히 고통스러웠다..ㅋㅋ

처음 출연하는 기호가 나오면 괄호를 넣거나 해서 꼭 그 이름을 명시했고
가장 친숙한 단어들로 설명하려 하면서도 문장을 간결하게 표현하려니 죽을 맛이었다.

글이 읽히지 않는 가장 큰 원인이 낯선 어휘가 섞인 긴 문장 때문이라고
생각하기 때문에 전달력을 위해 외면하지 못하고 신경썼던 부분이다.

그렇게 평생 영양제라고는 딱히 챙겨먹어본적 없었던 나는
오메가3와 칼슘&마그네슘 보충제에 몸과 마음을 기대는 지경이 됐다.🤤

그래서 점점 "기초 시리즈만 끝나면 누가 잘 못알아볼것같아도 그냥 편하게 쓰자"하는
마음이 커져갔었는데 막상 마무리가 되다보니 생각이 조금 바꼈다.

우선 설명하려는 계속된 시도 그 자체는 스스로를 이해시키는데도 좋은 영향을 끼쳤다.

기존에 알고 있던 부분이 틀렸다던가 정리되어 새롭게 다가오기도 했고
여러번 곱씹어 생각하다보니 그 내용들이 머릿속에 많이 남아있었다.

그런가보다 하고 넘어갔던 부분들을 말과 코드로 명확히 해야하기 때문에
그 과정에서 막상 하나의 문장도 완성하기 힘들었던 영역들이 있었고
배웠지만 뜬구름같던 지식들이 점점 구체화 되기도 했다.

마치 내가 무엇을 잘 모르고 있는지 확실히 구분해주는 판독기 같았다.

개발자들의 특수한 문화인 코드리뷰도 아마 이런 면에서 하는건가 싶다.

이렇게 돌이켜보니 지난 3주간 치뤘던 기술블로그와의 전투에서
큰 가르침을 얻었기에 이 과정을 어느정도는 계속 가져가보려 한다.

전에 겪어보지 못한 경험이라 더 특별하고 소중하다.

요 기여미 햄스터마냥 새로운 지식들에 계속 도전해보자 🏃

profile
sharing all the world

0개의 댓글