[JavaScript스터디] 객체

G-NOTE·2022년 8월 6일
0

항해99

목록 보기
24/36

객체

객체란, 다양한 타입의 값(원시값 or 다른 객체)을 하나의 단위로 구성한 복합적인 자료구조
객체를 변수에 할당하면 변수에는 '참조 값'이 저장된다.
객체는 0개 이상의 프로퍼티로 구성된 집합으로, 프로퍼티는 key-value의 조합으로 구성되어 있다.

빈 객체를 만드는 방법

let user = new Object(); // '객체 생성자' 문법
let user = {};  // '객체 리터럴' 문법

객체 리터럴의 { } 안에는 'key(식별자)-value'의 쌍으로 구성된 property가 들어간다.

let user = {     // 객체
  name: "John",  // 키: "name",  값: "John"
  age: 30        // 키: "age", 값: 30
};

객체는 변할 수 있다.

const 키워드로 선언된 객체는 그 객체 자체는 변경하지 못하지만, 객체의 '참조값'을 가리키고 있으므로 객체의 프로퍼티는 수정할 수 있다.

객체의 대괄호 표기법

.은 공백이 없고, 숫자로 시작하지 않으며 $_가 없는 유효한 변수 식별자에만 사용할 수 있다.
키가 유효한 변수 식별자가 아닌 경우, 점 표기법 대신 어떤 문자열이든 동작 가능한 대괄호 표기법을 사용하여 객체를 표현할 수 있다.

let user = {};

// set
user["likes birds"] = true;

// get
alert(user["likes birds"]); // true

// delete
delete user["likes birds"];

또한, key는 런타임에 평가되기 때문에 사용자 입력값 변경 등 평가가 끝난 이후의 결과를 프로퍼티 키로 사용할 수 있다. 점 표기법은 실시간으로 변하는 key를 찾는 데 사용할 수 없다.

단축 프로퍼티

key, value의 이름이 동일한 경우 변수명만 써도 프로퍼티를 설정할 수 있다.

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

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

자바스크립트 객체는 다른 언어와 달리 존재하지 않는 프로퍼티에 접근하려 해도 에러가 발생하지 않고 undefined를 반환하는데, 연산자 in을 사용해서 프로퍼티의 존재 여부도 확인할 수 있다.

let user = {};

alert( user.noSuchProperty === undefined ); // true는 '프로퍼티가 존재하지 않음'을 의미
let user = { name: "John", age: 30 };

alert( "age" in user ); // user.age가 존재하므로 true 출력
alert( "blabla" in user ); // user.blabla는 존재하지 않기 때문에 false 출력

참조에 의한 객체 복사

원시값과 달리 객체는 참조에 의해(by reference) 저장되고 복사된다.
원시값은 그 값 자체가 메모리 주소에 할당되어 저장되고 복사된다.
그러나 객체는 객체가 저장된 메모리 주소에 객체에 대한 '참조 값'이 저장된다. 객체 내부의 값이 저장되는 것이 아니다.

따라서 객체를 복사할 때 객체의 '참조 값'이 복사될 뿐, 객체가 복사되는 것은 아니다.

참조에 의한 비교

let a = {};
let b = a; // 참조에 의한 복사

alert( a == b ); // true, 두 변수는 같은 객체를 참조하고 있다.
alert( a === b ); // true
let a = {};
let b = {}; // 똑같이 생겼으나 서로 다른 메모리 주소를 참조하고 있는 독립된 두 객체

alert( a == b ); // false

중첩된 객체의 복사

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

alert( user.sizes.height ); // 182

위같은 경우 clone.sizes = user.sizes으로 객체를 복사할 수 없다. user.sizes가 객체이기 때문에 참조 값이 복사된다.

얕은 복사와 깊은 복사

얕은 복사 (shallow copy)

const obj1 = { a: 1, b: 2};
const obj2 = obj1;
console.log( obj1 === obj2 ); // true
  • 얕은 복사 : 객체를 직접 대입하는 경우 참조에 의한 할당이 이루어지므로 둘은 같은 데이터 주소를 참조하고 있다.

깊은 복사 (deep copy)

const obj1 = { a:1, b:2 };
const obj2 = { ...obj };
obj2.a = 100;
console.log( obj1 === obj2 ) // false
console.log( obj1.a ) // 1
  • 스프레드 연산자로 obj1의 내부 프로퍼티를 복사하여 obj2의 빈 객체에 할당하였다.
  • obj1과 obj2가 가리키는 메모리 주소는 다르다. (단 1단계까지만)
const obj1 = { a:1, b:2 };
const obj2 = Object.assign({}, obj1);
obj2.a = 100;
console.log( obj1 === obj2 ) // false
console.log( obj1.a ) // 1
  • Object.assign() 메서드는 열거할 수 있는 하나 이상의 출처 객체로부터 대상 객체로 속성을 복사할 때 사용하며, 대상 객체를 리턴한다.
  • Object.assign() 메소드를 통해 첫 번째 인자로 빈 { } 객체를, 두 번째 매개변수에 obj1라는 변수에 obj2를 할당했다.
  • obj1과 obj2가 가리키는 메모리 주소는 다르다. (단 1단계까지만)

가비지 컬렉션

자바스크립트의 메모리 관리는 개발자가 아닌 자바스크립트 엔진이 자동으로 수행한다.
가비지 컬렉터는 자바스크립트 엔진 내부에서 끊임없이 동작하며 모든 객체를 모니터링하여(=메모리 공간 주기적으로 검사) 어떠한 식별자도 참조하지 않는 메모리 공간을 비운다.

가비지 컬렉션의 기준

가비지 컬렉션 대상의 기준은 '도달 가능한가' 여부이다.
어디서든 접근하거나 사용할 수 있는 값은 '도달 가능한(reachable) 값'으로 분류되어 메모리에서 삭제되지 않는다.

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

루트에서 참조되는 값이나 스코프 체이닝으로 루트에서 참조될 수 있는 값은 도달 가능한 값이 된다.

mark and sweep algorithm

가비지 컬렉션의 실행 기반이 되는 알고리즘

  • Mark Phase : 가비지 컬렉터의 루트로부터 시작해 이 루프가 참조하는 모든 오브젝트들 마크(기억)
  • Sweep Phase : 마크가 끝나면 가비지 컬렉터는 메모리 전체를 돌면서 마크되지 않은 메모리를 해제한다.

메서드와 this

메서드는 객체에 제한되어 있는 함수를 의미한다. (프로퍼티 값이 함수일 경우, 일반 함수와 구분하기 위해 메서드라 한다.)

객체 지향 프로그래밍

절차 지향적 관점에서 벗어나 독립적인 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임
객체를 먼저 정의하고, 객체간 협력으로 프로그램을 구현한다.

메서드 단축 구문

user = {
  sayHi: function() {
    alert("Hello");
  }
};

// 단축 구문
user = {
  sayHi() { 
    alert("Hello");
  }
};

this

다른 언어와 달리 자바스크립트의 this에 바인딩된 값은 런타임(함수 호출 방식에 따라)에 결정된다.

  • 내부함수는 일반 함수, 메소드, 콜백함수 어디서 선언되었든 관게없이 this는 전역 객체를 바인딩한다.
  • 함수가 객체의 프로퍼티 값이면 메서드로서 호출되고, 이때 메서드 내부의 this는 해당 메서드를 호출한 객체에 바인딩된다.
  • 화살표 함수는 고유한 this를 가지지 않는다. 따라서 화살표 함수에서 this를 참조하면, 화살표 함수가 아닌 평범한 외부 함수에서 this 값을 가져온다.

new 연산자와 생성자 함수

옵셔널 체이닝 '?.'

옵셔널 체이닝 ?.은 좌항의 피연산자가 null 또는 undefined일 경우 undefined를 반환하고 그렇지 않으면 우항의 프로퍼티 참조를 이어간다.

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

자바스크립트로 존재하지 않는 요소에 접근하여 정보를 가져오려고 할 경우 문제가 발생하는데, 이를 해결하기 위해 && 연산자를 사용했다.
그러나 이렇게 &&로 연결하면 코드가 길어지고 가독성이 떨어진다는 단점이 있었다.

&& 방식

let user = {}; // 주소 정보가 없는 사용자

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

옵셔널 체이닝

let user = {}; // 주소 정보가 없는 사용자

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

옵셔널 체이닝을 남발하면 안되는 이유

옵셔널 체이닝은 존재하지 않아도 괜찮은 대상에만 사용해야 한다.
필수로 들어가야하는 대상에 값이 할당되지 않았으면 바로 알 수 있어야 하는데 옵셔널 체이닝은 이를 무시하고 다음 연산을 진행해야 하기 때문이다.

옵셔널 체이닝의 활용

obj?.prop – obj가 존재하면 obj.prop을 반환하고, 그렇지 않으면 undefined를 반환
obj?.[prop] – obj가 존재하면 obj[prop]을 반환하고, 그렇지 않으면 undefined를 반환
obj?.method() – obj가 존재하면 obj.method()를 호출하고, 그렇지 않으면 undefined를 반환

참조

https://ko.javascript.info/object
https://poiemaweb.com/js-this

profile
FE Developer

0개의 댓글