Skip to content

Latest commit

 

History

History
262 lines (164 loc) · 8.87 KB

1주차.md

File metadata and controls

262 lines (164 loc) · 8.87 KB

객체

자바스크립트엔 여덟 가지 자료형이 있습니다. 이 중 일곱 개는 오직 하나의 데이터만 담을 수 있어 원시형(primitive type) 이라 부릅니다.

객체는 중괄호 {...} 를 이용해 만들 수 있습니다. 중괄호 안에는 키: 값 쌍으로 구성된 프로퍼티 를 여러 개 넣을 수 있습니다. 엔 문자형, 엔 자료형이 허용됩니다.

객체는 몇 가지 특수한 기능을 가진 연관 배열입니다.

let user = new Object();
let user = {};

let user = {
  name: "John",
  age: 30,
};

점 표기법을 이용하면 프로퍼티 값을 읽는 것도 가능합니다.

alert(user.name);
alert(user.age);

delete 연산자를 사용하면 프로퍼티를 삭제할 수 있습니다.

delete user.age;

in 연산자로 프로퍼티 존재 여부 확인하기

자바스크립트 객체의 중요한 특징 중 하나는 다른 언어와는 달리, 존재하지 않는 프로퍼티에 접근하려 해도 에러가 발생하지 않고 undefined 를 반환한다는 것입니다.

let user = {};
alert(user.noSuchProperty === undefined); // true는 프로퍼티가 존재하지 않음을 의미합니다.

이렇게 undefined 와 비교하는 것 이외에도 연산자 in 을 사용하면 프로퍼티 존재 여부를 확인할 수 있습니다.

"key" in object;

for...in 반복문

for…in 반복문을 사용하면 객체의 모든 키를 순회할 수 있습니다.


참조에 의한 객체 복사

객체와 원시 타입의 근본적인 차이 중 하나는 객체는 참조에 의해 저장되고 복사된다는 것입니다.

원시값(문자열, 숫자, 불린 값)은 값 그대로 저장 할당되고 복사되는 반면에 말이죠.

변수엔 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어 있는 메모리 주소 인 객체에 대한 참조 값 이 저장됩니다.

객체가 할당된 변수를 복사할 땐 객체의 참조 값이 복사되고 객체는 복사되지 않습니다.

참조에 의한 비교

객체 비교 시 동등 연산자 == 와 일치 연산자 === 는 동일하게 동작합니다.

객체 복사, 병합과 Obejct.assign

자바스크립트는 객체 복제 내장 메서드를 지원하지 않기 때문에 조금 어렵습니다. 사실 객체를 복제해야 할 일 은 거의 없습니다. 참조에 의한 복사로 해결 가능한 일이 대다수이죠.

정말 복제가 필요한 상황이라면 새로운 객체를 만든 다음 기존 객체의 프로퍼티들을 순회해 원시 수준까지 프로퍼티를 복사하면 됩니다.

let user = {
  name: "John",
  age: 30,
};

let clone = {};

for (let key in user) {
  clone[key] = user[key];
}

clone.name = "Pete";

alert(user.name); // 기존 객체에는 여전히 John이 있습니다.

Object.assign 을 사용하는 방법도 있습니다.

Object.assign(dest, [src1, src2, src3 ...]);

중첩 객체 복사

프로퍼티는 다른 객체에 대한 참조값일 수도 있습니다.

let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50,
  },
};

alert(user.size.height);

이 객체를 복사하기 위해서는 user[key] 의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용해야 합니다. 이런 방식을 깊은 복사 라고 합니다.

자바스크립트 라이브러리인 lodash의 메서드인 _.cloneDeep(obj)를 사용하면 쉽게 깊은 복사를 할 수 있습니다.

가비지 컬렉션

원시값, 객체, 함수 등 우리가 만드는 모든 것은 메모리가 차지합니다. 그렇다면 더는 쓸모 없어지게 된 것들은 어떻게 처리될까요? 지금부턴 자바스크립트 엔진이 어떻게 필요 없는 것을 찾아내 삭제하는지 알아보겠습니다.

가비지 컬렉션 기준

도달 가능성(reachability) 이라는 개념을 사용해 메모리 관리를 수행합니다.

태생부터 도달 가능한 것들은 명백한 이유 없이는 삭제되지 않습니다.

  • 현재 함수의 지역 변수와 매개변수
  • 중첩 함수의 체인에 있는 함수에서 사용되는 변수와 매개변수
  • 전역 변수

이런 값들을 루트(root) 라고 합니다.

루트가 참조하는 값이나 체이닝으로 루트에서 참조할 수 있는 값은 도달 가능한 값이 됩니다.

간단한 예시

let user = {
  name: "John",
};
image
user = null;
image

메서드와 this

let user = {
  name: "John",
  age: 30,
  sayHi: function () {
    alert("Hello");
  },
};

객체 프로퍼티에 할당된 함수를 메서드 라고 부릅니다.

위 예시에선 user에 할당된 sayHi가 메서드입니다.

🤔 **객체 지향 프로그래밍** 객체를 사용하여 개체를 표현하는 방식을 객체 지향 프로그래밍(object-oriented programming, OOP)이라 부릅니다.

메서드는 객체에 저장된 정보에 접근할 수 있어야 제 역할을 할 수 있습니다. 모든 메서드가 그런 건 아니지만, 대부분의 메서드가 객체 프로퍼티의 값을 활용합니다.

user.sayHi() 의 내부 코드에서 객체 user 에 저장된 이름을 이용해 인사물을 만드는 경우가 그런 경우에 속합니다.

메서드 내부에서 this 키워드를 사용하면 객체에 접근할 수 있습니다.

자유로운 this

자바스크립트의 this 는 다름 프로그래밍 언어의 this와 동작 방식이 다릅니다. 자바스크립트에선 모든 함수에 this 를 사용할 수 있습니다.

this 값은 런타임에 결정됩니다. 컨텍스트에 따라 달라집니다.

동일한 함수라도 다른 객체에서 호출했다면 this 가 참조하는 값이 달라집니다.


옵셔널 체이닝 ‘?.’

옵셔널 체이닝 ?. 을 사용하면 프로퍼티가 없는 중첩 객체를 에러 없이 안전하게 접근할 수 있습니다.

옵셔널 체이닝이 필요한 이유

사용자가 여러 명 있는데 그 중 몇 명은 주소 정보를 가지고 있지 않다고 가정해봅시다. 이럴 때 user.address.street 를 사용해 주소 정보에 접근하면 에러가 발생할 수 있습니다.

이런 문제를 해결하기 위해 && 연산자를 사용하곤 했습니다.

let user = {};

alert(user && user.address && user.address.street); // undefined

AND를 연결해서 사용하면 코드가 아주 길어진다는 단점이 있습니다.

new 연산자와 생성자 함수

생성자 함수

생성자 함수(constructor function)와 일반 함수에 기술적인 차이는 없습니다. 다만 생성자 함수는 아래 두 관례를 따릅니다.

  1. 함수 이름의 첫 글자는 대문자로 시작합니다.
  2. 반드시 'new' 연산자를 붙여 실행합니다.
function User(name) {
  this.name = name;
  this.isAdmin = false;
}

let user = new User("보라");

alert(user.name); // 보라
alert(user.isAdmin); // false

생성자의 의의는 재사용할 수 있는 객체 생성 코드를 구현하는 것에 있습니다.

모든 함수는 생성자 함수가 될 수 있습니다. new 를 붙여 실행한다면 어떤 함수라도 객체 생성 코드를 구현할 수 있습니다.

생성자와 return 문

return문이 있다면 다음과 같은 일이 벌어집니다.

  • 객체를 return 한다면 this 대신 객체가 반환됩니다.
  • 원시형을 return 한다면 return문이 무시됩니다.

심볼형

Symbol은 원시형 데이터로, 유일무이한 식별자를 만드는 데 사용됩니다. 이름이 같더라더 값이 항상 다릅니다. 이름이 같을 때 값도 같길 원한다면 전역 레지스트리를 사용해야 합니다. Symbol.for(key)는 key 라는 이름을 가진 전역 심볼을 반환합니다.

‘숨김’ 프로퍼티

심볼을 이용하면 숨김(hidden) 프로퍼티를 만들 수 있습니다. 숨김 프로퍼티는 외부 코드에서 접근이 불가능하고 값도 덮어쓸 수 없는 프로퍼티입니다.

let user = {
  name: "John",
};

let id = Symbol("id");

user[id] = 1;

alert(user[id]);

그런데 문자열 "id"를 키로 사용해도 되는데 Symbol("id")을 사용한 이유가 무엇일까요?

user는 서드파티 코드에서 가지고 온 객체이므로 함부로 새로운 프로퍼티를 추가할 수 없습니다. 그런데 심볼은 서드파티 코드에서 접근할 수 없기 때문에, 심볼을 사용하면 서드파티 코드가 모르게 user에 식별자를 부여할 수 있습니다.