[Section 01] JavaScript 기초


< 10. 객체 >

1. 객체의 기본 개념

1.1. 프로퍼티의 집합

  • 키와 값으로 구성된 속성의 집합
  • 일반적인 객체 : 중괄호 { } 로 선언
const userObj = { }; // 중괄호만 써서 정의 가능, 빈 객체
const userObj = {
  name: "chul su",
  age: 20,
};                   // name 과 age는 키, chul su와 20은 값

1.2. 참조 타입

  • 여러 변수에서 같은 객체를 공유할 수 있다
  • 참조 자료형에는 객체, 배열, 함수가 있다
const userObj = {
  name: "chul su",   // 참조 자료형
  age: 20,
};
const copyUserOjb = userObj;
console.log(userObj); // { name: 'chul su', age: 20 }
console.log(copyUserOjb); // { name: 'chul su', age: 20 }

userObj.age = 50; // 뒤에 오늘 age는 50으로 재할당됨
console.log(userObj); // { name: 'chul su', age: 50 }
console.log(copyUserOjb); // { name: 'chul su', age: 50 }

1.3. 동적으로 프로퍼티 추가 / 삭제

1.3.1. 동적 추가

  • 객체의 속성에 접근해서 값을 할당
const userObj = {}; // 빈 객체
userObj.name = "영희"; // 새로운 속성과 값 추가
console.log(userObj); // { name: '영희' } 출력
console.log(userObj.age); // undefined 출력
// 동적으로 속성과 값을 할당하는 것이 가능하므로 age속성이 없지만 접근 가능
// age is no defined가 시스템 오류가 아니라 할당값을 못 찾는다고 출력 undefined

1.3.2. 동적 삭제

  • delete 키워드를 사용해서 특정 속성 삭제
const userObj = {
    name: "chul su",
    age: 20,
  };
console.log(userObj); // { name: 'chul su', age: 20 } 출력

delete userObj.name; // name 키 삭제
console.log(userObj); // { age: 20 } 출력
  • 예시
    const userObj = {
      name: "영희",
      age: 20,
    };
    delete userObj.name;  // name 속성 삭제 됨
    console.log(userObj); // { age: 20 } 출력
    
    delete userObj.age;  // age 속성 삭제 됨
    console.log(userObj); // {} 출력

1.3.3. new 키워드를 사용한 동적 추가

const userObj2 = new Object();
const userObj2 = {};               // 둘 다 빈 객체 만드는 법
  • 예시
    const userObj2 = new Object(); // 빈 객체 생성
    userObj2.name = "철수";
    console.log(userObj2); // { name: '철수' }
    
    userObj2.age = 30;
    console.log(userObj2); // { name: '철수', age: 30 }

1.4. 키는 문자열 또는 심볼 타입만 가능

  • 프로퍼티의 키는 기본적으로 문자열이거나 심볼이어야 하며, 이는 객체의 프로퍼티 접근 및 조작 시 중요한 규칙

2. 객체 생성과 프로퍼티

2.1. 객체 생성 방법

2.1.1. 객체 리터럴

< 리터럴(literal) 표기법 >

  • 중괄호 사용
  • 데이터를 정의하는 데 있어서 간편하게 데이터를 정의할 수 있는 방법
  • 기본 자료형참조 자료형을 선언했던 방법 모두가 리터럴 표기법
// 함수 리터럴
const sum = () => {};
// 객체 리터럴
const userObj = {};
// 배열 리터럴
const userArr = [];
// 원래는 아래처럼 해야 했음
const userArr = new Array(1, 2, 3, 4, 5);
console.log(userArr);
// 문자 리터럴
const userName = "철수";
// 불리언 리터럴
const isUser = true;
// 숫자 리터럴
const num = 10;
// null 리터럴
const isUser = null;
// symbol 리터럴
const uniqueKey = Symbol("a");

2.1.2. Object 생성자 함수

  • new 키워드 사용
  • 사용하지 않음
const obj2 = new Object();

2.1.3. 생성자 함수

  • new 키워드 사용
  • class가 있기 때문에 많이 사용하지 않음
  • 그러나 기억은 해둬야 한다.
function Person(name) {
    this.name = name;
}
const obj3 = new Person('John');

2.1.4. Object.create()

  • 많이 사용하지 않음
const obj4 = Object.create(Object.prototype);

2.2. 프로퍼티 접근과 조작

2.2.1. 객체의 속성에 접근하는 방법

2.2.1.1. 마침표 연산자 사용

  • 기본적으로 마침표 연산자를 이용해서 접근
const userObj = {
  name: "영희",
  age: 20,
};
console.log(userObj.name); // 영희 출력

2.2.1.2. 대괄호 연산자 사용

  • 마침표로 접근하지 못 할 때 대괄호 연산자 사용
    • key 에 공백에 있을 경우
const userObj = {
  name: "영희",
  age: 20,
};
console.log(userObj["age"]); // 20 출력
// 마침표로 접근하지 못 할 때 대괄호 연산자로 접근

const userObj = {
  "my name": "영희",
  age: 20,
};
// key에 공백이 있을 때
console.log(userObj["my name"]); // 영희 출력
console.log(userObj.my name); // error

2.2.1.3. 마침표 연산자 와 대괄호 연산자 중복 사용

const userObj = {
  name: "영희",
  age: 20,
  likes: ["사과", "바나나", "포도"],
  address: {
    zipCode: 131000,
    addr1: "서울",
    addr2: "101호",
  },
};
console.log(userObj.likes[1]); // 바나나
// 객체 접근을 위한 마침표 연산자와 배열 접근을 위한 대괄호 연산자 사용
console.log(userObj.address.zipCode); // 131000
console.log(userObj.address["zipCode"]);
// 131000 출력, 이렇게도 가능하지만 배열과 구분을 위해 대괄호는 사용 x

2.2.2. 객체의 속성을 수정하는 방법

  • 속성이 있으면 수정, 없으면 추가
  • 동적으로 속성을 추가하는 방법과 동일함
const userObj = {
  name: "영희",
  age: 20,
};
// 동적으로 속성을 추가하는 방법과 같다
userObj.name = "철수";
console.log(userObj); // { name: '철수', age: 20 }

2.2.3. 객체의 속성을 삭제하는 방법

  • delete 객체명.속성명;
const userObj = {
    name: "영희",
    age: 20,
  };
delete userObj.age;  // age 삭제
console.log(userObj); // { name: '영희' } 출력

2.2.4. 객체 속성 유무를 확인하는 방법

2.2.4.1. 반복문 사용

const userObj = {
  name: "철수",
  age: 20,
};
// name이라는 key가 있는지 확인을 해야 한다면?
let isProperty = false;
for (let key in userObj) {
  // userObj 반복
  if (key === "age") isProperty = true;
}
console.log(isProperty); // true

2.2.4.2. 내장 매서드 hasOwnProperty 사용

  • 해당 속성이 있는지 없는지 확인하는 방법
const userObj = {
  name: "철수",
  age: 20,
};
console.log(userObj.hasOwnProperty("age")); // true
console.log(userObj.hasOwnProperty("age2")); // false
if (userObj.hasOwnProperty("name")) {
  // typescript 기능이 내장되어 있는 것
  console.log("name 속성은 있습니다");
}  // name 속성은 있습니다

2.2.5. 매개변수를 사용하는 방법

const userObj = {
  name: "철수",
  age: 20,
  getName: function (name) {
    // 매개변수가 있어도 사용 가능하다.
    console.log(name);
  },
};
userObj.getName("영희"); // 영희

const userObj = {
  name: "철수",
  age: 20,
  getName: function (...args) {
    // 매개변수가 있어도 사용 가능하다.
    console.log(args);
  },
};
userObj.getName("영희", 20); // [ '영희', 20 ]

2.2.6. 계산된 속성 방식으로 접근하는 방법

const key = "name";
const obj = {
  [key]: "철수",
};

console.log(obj.name);

3. 객체 매서드와 this

3.1 일반적인 매서드 정의

const calsulate = {
  add: function () {};
  add() {};      // 두 가지 방법 똑같다
}

3.3. this 키워드 사용하는 방법 (자신에게 접근)

  • 자기 자신에게 접근하는 방법
  • 출력값 테스트를 하려면 코드러너 불가, 웹브라우저 개발자 도구 활용해야 함
  • var let const처럼 사용할 수 있음
  • 대부분 함수 안에서 사용
const userObj = {
  name: "철수",
  age: 20,
  getName: function () {
    console.log(this.name);
  },
};
userObj.getName(); // 철수
  • 함수 선언문에서는 함수를 호출한 객체를 가리킨다.
const userObj = {
  name: "철수",
  getName: function () {
    console.log(userObj.name); // 철수
    console.log(this.name); // 철수
  },
};
userObj.getName();
// this는 함수를 누가 호출했는지가 중요함

const getName(){
    console.log(this)
};
const userObj = {
  name: "철수",
//   getName: getName, // 객체 이름과 값이 같으면 getName 하나만 사용 가능
  getName: function getName() { // getName()으로 줄일 수 있음
    console.log(this);
  },
};
userObj.getName();
  • 화살표 함수에서는 그 함수가 선언된 스코프(어휘적 스코프)를 가리킨다.
  • 헷갈리므로 화살표 함수에서는 this를 사용하지 않는 것이 좋다
const userObj = {
    name: "철수",
    getName: () => { 
      console.log(this);
    },
  };
userObj.getName();

const userObj = {
    name: "철수",
    getName: function (prefix) {
      return this.name + prefix;
    },
  };
  const greet = userObj.getName(", 안녕!");
  console.log(greet);

4. 객체 순회와 조작

4.1. 객체를 반복할 수 있는(순회) 방법

4.1.1. for ... in 문 사용

 const userObj = {
    name: "철수",
    age:20,
  }

  for (let key in userObj){
    console.log(key, userObj[key]);
  }
  // name 철수
  // age 20

4.1.2. Object.keys 매서드 사용 (키 출력)

 const userObj = {
    name: "철수",
    age:20,
  }
  console.log(Object.keys(userObj)); 
  // [ 'name', 'age' ]

  const userObj = {
    name: "철수",
    age:20,
  }
  const keysArr = Object.keys(userObj);
  for (let value of keysArr){
    console.log(userObj[value]);
  } 
  // 철수 
  // 20

  const userObj = {
    name: "철수",
    age:20,
  }
  Object.keys(userObj).forEach((key) => {
    console.log(`${key}: ${userObj[key]}`)
  });
  // name: 철수
  // age: 20

4.1.3. Object.values 매서드 사용 (값 출력)

  • 값만 배열로 반환
 const userObj = {
    name: "철수",
    age:20,
  }
  for (let value of Object.values(userObj)) {
    console.log(value);
  };
// 철수
// 20

4.1.4. Object.entries 매서드 사용

  • key와 value을 배열로 반환
const userObj = {
    name: "철수",
    age:20,
  }
Object.entries(userObj).forEach(([key, value]) => { 
    // forEach로 key와 value를 분해 후 사용 
    console.log(`${key}: ${value}`);
});
// name: 철수
// age: 20
console.log(Object.entries(userObj));
// [ [ 'name', '철수' ], [ 'age', 20 ] ]

4.2. 객체 복사와 병합

  • 배열과 객체는 참조 자료형
  • 깊은 복사에서 얕은 복사는 불가능, 얕은 복사에서 깊은 복사는 가능

4.2.1. 객체 복사

4.2.1.1. 얕은 복사

  • 객체와 배열과 같은 참조 자료형에서 많이 사용되는 복사
  • 참조 관계가 유지되면서 복사되는 것
const user = {
    name: "철수",
}
const copyUser = user;
user.name = "영희";
console.log(user); // { name: '영희' }
console.log(copyUser) // { name: '영희' }
// 같이 변경됨, user에는 값의 주소값이 들어가는 것
// copyUser도 주소값을 받는 것이므로 둘 다 변경이 됨

4.2.1.2. 깊은 복사

  • 기본 자료형에 해당하는 자료들이 사용
const user = {
    name: "철수",
}
const copyUser = user;
let a = 10;
let b = a;  // b를 a로 복사하고
a = 20;     // a를 20으로 수정했지만, b 값이 변하지 않음
console.log(a,b);  // 20 10

4.2.1.3. ... 전개 연산자 사용

  • 객체의 속성을 그대로 풀어 놓을 때
  • {...user} 전개연산자 사용
    ( 완벽한 깊은 복사는 아님, 참조자료형이 중첩되지 않았을 때 )
// ex 1)
const user = {
    name: "철수",
}
const copyUser = {...user}; 
// {name: "철수"} 를 풀어 놓은 것과 똑같다
user.name ="영희";
console.log(user, copyUser) // { name: '영희' } { name: '철수' }

※ 완전 깊은 복사를 만드는 방법
// JSON.stringify( ) : 객체를 json 문자열로 바꿔버림
// JSON.parse( ) : json 문자열을 객체로 바꿈
// JSON.parse(JSON.stringify(user)) 이런식으로 만들면
// 아예 풀어서 새로 정의를 하는 것과 같으므로 깊은 복사 가능함

// ex 2)
const numArr = [10, 20];
const copyNumArr = numArr;
numArr[0] = 30;
console.log(numArr, copyNumArr) 
// [ 30, 20 ] [ 30, 20 ]
// 얕은 복사가 돼서 같이 바뀌어 버림

const numArr = [10, 20];
const copyNumArr = [...numArr];
numArr[0] = 30;
console.log(numArr, copyNumArr) 
// [ 30, 20 ] [ 10, 20 ]
// 전개 연산자를 이용해서 깊은 복사 가능

4.2.2. 객체 병합

4.2.2.1. ... 전개 연산자 사용

// ex 1)
const user = {
    name: "철수",
    age: 20,
}
const developer = {
    skill: "react.js"
};
const person = {...user, ...developer};
console.log(person) // { name: '철수', age: 20, skill: 'react.js' }
  • 전개하려고 하는 동일한 속성이 있을 때는 뒤에 오는게 덮어버리기 때문에 주의
// ex 2)
const user = {
    name: "철수",
    age: 20,
}
const developer = {
    skill: "react.js",
    age: 50,  // 뒤에 오는 50이 30을 덮게 됨
};
const person = {...user, ...developer};
console.log(person)  // { name: '철수', age: 50, skill: 'react.js' }

// ex 3)
const user = {
    name: "철수",
    age: 20,
}
const developer = {
    skill: "react.js",
    age: 50,
};
const person = {...user, ...developer, age: 40};  // 40이 덮게 됨
console.log(person)  // { name: '철수', age: 40, skill: 'react.js' }

5. 객체의 고급 기능

5.1. 객체 속성 설명자 defineProperty

  • 일반적으로 많이 사용되는 개념은 아님 (고급 개념)
  • 객체 속성을 설명하는 것
  • value, writable, enumerable, configurable
  • 실무에서 활용도 낮음
const userObj = {};
userObj.name = "철수";  // 동적 추가
console.log(userObj);

const userObj = {};
Object.defineProperty(); 
// 타입스크립트로 매서드 정의가 되어 있는 것
// 세 개의 매개변수를 갖는다 (마우스 커서 올려 보면 나옴)
console.log(userObj);

const userObj = {
    age: 20,
    gender: "male",
};
Object.defineProperty(userObj, "name", {
    value: "철수", // 속성의 값 셋팅할 때 사용, 개발자 도구에서 확인 가능
    writable: true, 
    // 수정 가능 여부
    // true면 동적 수정 가능, false면 불가능
    // boolean(true / false)이나 undefined(안 넣거나)만 넣을 수 있음
    enumerable:false,
    // 순회할 때 접근 가능한 속성인지 지정
    // false면 특정 속성 key가 드러나지 않음(숨김)
    // boolean(true / false)이나 undefined(안 넣거나)만 넣을 수 있음
    configurable: false,
    // 이 설정을 바꿀 수 있는지 또는 삭제할 수 있는지 지정
    // false면 수정 삭제 불가
    // true로 해야 나중에 다른 속성들도 재설정 가능
    // boolean(true / false)이나 undefined(안 넣거나)만 넣을 수 있음
});
console.log(userObj);

5.2. 접근자 프로퍼티 get, set

  • 속성에 접근할 때 사용
  • 많이 사용하진 않음
  • get을 사용하면 매개변수를 이용할 수 없다
  • key처럼 사용할 것인지 함수처럼 사용할 것인지 차이(?)
const userObj = {
    firstName: "john",
    lastName: "hash",
}
console.log(`${userObj.firstName} ${userObj.lastName}`)

const userObj = {
    firstName: "john",
    lastName: "hash",
    get fullName() {
        return `${userObj.firstName} ${userObj.lastName}`;
    },  // 값으로 조합 가능
    set fullName(name) {
        const splitNames = name.split(" "); 
        // split(" ")는 구분자 이용 자르기
        // split("")는 한 글자씩 자르기
        console.log(splitNames);
        this.firstName = splitNames[0];
        this.lastName = splitNames[1];
    }, // 대체 가능
}
userObj.fullName = "mariana jone";
console.log(userObj.fullName)

6. 객체 불변성과 최적화

6.1. Object.seal()

  • 객체의 속성을 추가하거나 삭제하는 것을 막을 때 사용
const userObj = Object.seal({
    name: "철수",
});
userObj.age = 20; // 추가 안 됨
delete userObj.name;  // 삭제 안 됨
console.log(userObj)  // { name: '철수' } 출력

6.2. Object.preventExtensions()

  • 객체의 속성을 추가하는 것을 막을 때 사용
const userObj = Object.preventExtensions({
    name: "철수",
});
userObj.age = 20;  // 추가 안 됨
userObj.name = "영희"  // 수정은 가능
console.log(userObj)  // { name: '영희' } 출력

6.3. Object.freeze()

  • 객체 변경을 막을 때 사용
  • 실무에서 많이 사용
const userObj = Object.freeze({
    name: "철수",
});
userObj.age = 20;  // 추가 안 됨
userObj.name = "영희"  // 수정 불가
console.log(userObj)  // { name: '철수' } 출력

7. 매서드 체이닝

  • 객체의 매서드를 연결해서 사용할 수 있음
const calculate = {
    value: 0,
    add: function(n1) {
        this.value += n1;
        return this;  
        // 이 함수를 내보내고, 이 함수는 calculate의 객체
        // this를 내보내야만 매서드 체이닝이 가능
    },
    subtract: function(n1) {
        this.value -= n1;
        return this;  
        // 이 함수를 내보내고, 이 함수는 calculate의 객체
        // this를 내보내야만 매서드 체이닝이 가능
    },
    getResult: function () {
        return this.value;
        // 마지막엔 이 함수의 값을 내보내기
    },
}
const result = calculate.add(10).subtract(5).getResult();
console.log(result)

< 하루 정리 >

오늘도 정보의 바다에서 익사를 할 뻔한 아주 위험한 날이었다...
설명 이해하느라 필기하느라 정신이 없어서 쉬는 시간도 없이 계속 앉아서 보고 또 보고 ㅠㅠ
문제는 여전히 못 풀고, 팀 미팅 발표 주제 선정도 못 해서 조급하고 ...
현타가 아주 씨게 왔다.

앞으로도 이럴텐데 마인드 컨트롤이 필요하다... 
어차피 수업 시간에 주시는 시간 내에는 문제를 못 푼다고 마음 편하게 생각하고 
있어야 할텐데 .. 
그 놈의 자존심.. 승부욕.. 
어떻게든 풀어보고 싶어서 애를 쓰지만 쉽진 않다.

수업 시간에도 어려웠던 클로저와 렉시컬 스코프를 팀 미팅 주제로 선정하고
자료를 계속 찾아봤지만,
다들 고수님들 뿐이신지 내가 아는 개념을 훨씬 뛰어 넘는 개념들로 설명을 해주신다 ㅠㅠ
느낌은 알겠는데 정확하게는 모르겠는 그런 느낌??
그래도 어찌저찌 자료는 만들었지만 다른 분들이 준비하셨던 거에 비하면 
참 초라해지는 결과물이다.

일단 복잡해진 머리를 정리하기 위해서 해야 될 것들을 적어보자!
  1. RBF 때 공유할 코딩 테스트 5문제 풀기
  2. 함수 연습문제 +, 연습문제 ++ 풀어서 답안 제출하기
  3. 오늘 강사님이 올려주신 적금 문제 풀어보기
  4. 구매한 교재 수업 중 배운 내용까지 읽어 보기

오늘 조금 더 공부해야 하는데 체력이 다 떨어졌다.. 자꾸 쉬고 싶다
profile
첫 시작!

0개의 댓글