홍카나의 공부방

[Javascript] 객체(object) 기본 이해하기 본문

Programming Language/Javascript

[Javascript] 객체(object) 기본 이해하기

홍문관카페나무 2024. 10. 7. 16:50

 

객체

 

자바스크립트에서 객체는 문자열, 숫자 등의 원시형(primitive type)타입과 다르게 여러 종류의 데이터를 담을 수 있다. 객체는 중괄호{}를 통해서 만들 수 있다.

let name = {
  lastName : "hong",
  firstName : "cana",
  isAdmin : true,
};

 

중괄호 안에는 키:밸류 쌍으로 구성된 프로퍼티(property)를 여러개 넣을 수 있다. key에는 문자형, value에는 모든 자료형이 허용된다. 중괄호 { ... }를 이용해 객체를 선언하는 것을 객체 리터럴(object literal)이라고 부른다. 또한 객체 안에 들어간 마지막 프로퍼티는 쉼표(,)로 끝날 수 있음을 유의하자.

 

그리고 객체 선언에 상수(const)를 사용할 수 있는데, 상수를 사용해도 객체 내용 자체는 수정이 가능하다. const 명령어는 변수의 객체 참조 값이 바뀌는 것을 막는 것이지, 객체 내용을 변경하는 것은 막지 않는다. 쉽게 얘기하면 변수가 가리키고 있는 주소 값의 변경을 막는 것인데, 프로퍼티를 추가한다고 해서 객체 변수의 주소 값이 변경되지 않기 때문이다.

const obj = {
  age: 25,
};

obj.age = 30; // ok.

 

한 객체에서 일반 프로퍼티와 단축 프로퍼티를 함께 사용할 수도 있다. 그리고 키에 숫자를 넣으면 자동으로 문자열로 변환된다. 키에는 문자형 타입만 허용되기 때문이다.

let user = {
  name,    // name: name과 같다.
  age: 30,
};

const obj = {
  0: "test"
};

console.log(obj[0]); // 0이 자동으로 문자열로 변환되고, test가 출력된다..
console.log(obj["0"]); // test가 출력된다.

 

다른 언어와 달리, 존재하지 않는 프로퍼티에 접근하려 하면 오류가 발생하지 않고 undefined를 반환한다는 특징이 있다. 그리고 파이썬의 딕셔너리처럼 `in` 연산자를 사용하면 프로퍼티 존재 여부를 확인할 수 있다.

 

파이썬에서 딕셔너리 순회에 for k,v in dic.items(): 와 같은 방식을 사용했다면, 자바스크립트 객체 순회는 for ... in 문법을 사용한다.

for (key in object) {
  console.log(key); // key1, key2, ...
  console.log(object[key]); // value1, value2, ...
}

 

 

키가 정수로 취급될 경우 자동으로 정렬되지만, 그렇지 않은 경우 키가 자동으로 정렬되지 않음을 유의한다. 그리고 프로퍼티 삭제는 delete를 이용한다.

 

delete obj.name;

 

 

 

 


 

참조에 의한 객체 복사

 

객체는 참조에 의해 할당되고 복사된다. 즉, 변수에 객체 자체가 아닌 메모리 상의 주소인 '참조'가 저장된다. 따라서 객체가 할당된 변수를 복사하거나, 함수의 인자로 넘길 땐 객체의 값이 아닌 객체의 참조가 복사된다.(call by reference를 떠올리자.)

 

그래서 객체의 완벽한 복제본을 만드려면 깊은 복사(deep copy)를 해야 한다. Object.assign() 함수를 이용하면 객체 내부에서 또다른 객체에 대한 참조가 없을 시 충분히 깊은 복사를 구현할 수 있지만, 그렇지 않을 경우 자바스크립트 라이브러리 lodash의 메서드인 _.cloneDeep(obj)를 사용해야 한다.

 

const user = {
  name: "hong",
  age: 30,
};

const clone = Object.assign({}, user);

assign을 이용해도 다른 객체로 취급함을 확인 가능

 

let objects = [{ 'a': 1 }, { 'b': 2 }];

let deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]); // false

 

 

 


 

가비지 컬렉터(GC)

 

자바스크립트 엔진 내에서는 GC가 꾸준히 작동한다. 모든 객체를 모니터링할 수 있고, 도달할 수 없는 객체는 삭제한다. 도달 가능한 값의 예시로는 쉽게 생각하면 전역 변수, 현재 함수의 지역 변수인 루트(root)와 그 루트가 참조할 수 있는 값이 도달 가능한 값이 된다.

 

mark-and-sweep 이라는 가비지 컬렉션 기본 알고리즘에 대해서도 알아두자. 이는 이 글에서 설명하는 것보다 모던 자바스크립트 튜토리얼 문서에 있는 설명을 한 번 살펴보는게 나을 것이다. 쉽게 요약하면 root로 부터 시작하여 도달 가능한 객체들을 전부 기억(mark)한 다음에, 기억할 수 없는 객체는 메모리에서 삭제하는 것이다.

 

 

그리고 자바스크립트 엔진은 실행에 영향을 미치지 않으면서 가비지 컬렉션을 더 빠르게 수행하는 다양한 최적화 기법을 사용하는데, 자바스크립트에 익숙해진 다음에 엔진에 대해서 따로 학습하는 것을 추천한다.

 


 

메서드

 

자바스크립트에서 객체는 실제 존재하는 개체(entity)를 표현하고자 할 때 생성하는데, 개체의 특정한 행동을 표현하는 메소드를 만들 수도 있다. 아래와 같이 객체 프로퍼티에 할당된 함수를 메서드(method)라고 부른다.

const user = {
  name: "hong",
  age: 30,
};

user.saySiu = function() {
  console.log("SIUUUUUUUUU");
};

user.saySiu(); // SIUUUUUUUUU!!!!

 

객체 리터럴 내부에서 선언도 가능하다. this 키워드를 사용하며 객체 내부의 프로퍼티에 접근할 수도 있는데, 우선 자바스크립트에서 this는 컴파일 타임이 아닌 런타임 시점에서 결정된다는 것만 알아두고 넘어가자.

const user = {
  name : "hong",
  age : 30,
  saySiu() {
    console.log("SIUUUUUUUUUU!!");
  },
};
let user = {
  firstName: "hong",
  saySiu() {
    let siu = () => { alert(this.firstName); }
    siu();
  }
};

user.saySiu();

 


 

New

 

객체 리터럴을 사용하면 객체를 쉽게 만들 수 있지만, 유사한 객체를 여러 개 만들어야할 필요가 생길때 new 연산자를 사용하면 좋다.

function User(name) {
  // this = {};
  
  this.name = name;
  this.isAdmin = true;
  
  // return this;
}

let user = new User("hongcana");
console.log(user.name); // hongcana

 

위 코드를 보면 User가 클래스고, user로 User 클래스의 인스턴스를 만드는 것과 비슷해보인다.

반응형