Chapter 3

객체와 함수 기초

  • 3.1 객체란?
  • 3.2 객체 리터럴과 프로퍼티
  • 3.3 ES6 객체 리터럴 확장
  • 3.4 원시 값 vs 객체
  • 3.5 참조에 의한 전달과 얕은/깊은 복사
  • 3.6 함수란?
  • 3.7 함수 정의와 호이스팅
  • 3.8 매개변수와 반환값
  • 3.9 다양한 함수의 형태

JS에서 원시 값을 제외한 나머지는 전부 객체이고, 함수는 그 객체 중에서도 특별한 일급 객체야. 이 둘을 제대로 잡아야 JS의 나머지가 풀리지.

객체프로퍼티(property)의 집합이야. 프로퍼티는 키(key)와 값(value)의 쌍으로 구성되고, 값이 함수이면 그걸 **메서드(method)**라고 불러.

var person = {
  name: 'Lee',       // 프로퍼티
  sayHello: function () {  // 메서드
    console.log(`Hi! My name is ${this.name}`);
  }
};

JS는 다양한 방법으로 객체를 만들 수 있지만, 가장 일반적인 건 객체 리터럴 {}이야. 클래스를 정의하고 new로 인스턴스를 만들 필요 없이, 중괄호만으로 바로 객체를 생성할 수 있지. 프로퍼티 접근은 마침표 표기법(person.name)과 대괄호 표기법(person['name']) 두 가지가 있는데, 대괄호 안에는 반드시 문자열을 넣어야 해. 존재하지 않는 프로퍼티에 접근하면 에러가 아니라 **undefined**를 반환한다는 점도 기억해두자.

ES6에서 추가된 확장 기능도 알아두면 좋아. 프로퍼티 축약 표현은 변수 이름과 프로퍼티 키가 같으면 생략할 수 있고, 계산된 프로퍼티 이름으로 동적인 키를 쓸 수 있고, 메서드 축약 표현으로 function 키워드를 생략할 수 있지.

const x = 1, y = 2;
const obj = { x, y };  // { x: 1, y: 2 }
const person = {
  name: 'Lee',
  sayHi() { console.log('Hi!'); }  // 메서드 축약
};

원시 값과 객체의 차이가 JS의 많은 동작을 설명해. 원시 값은 불변(immutable) + 값 복사이고, 객체는 가변(mutable) + 참조 복사야. 원시 값에 새 값을 재할당하면 기존 메모리의 값을 수정하는 게 아니라 새로운 메모리 공간에 새 값을 저장하고 변수가 그쪽을 가리키게 돼. 문자열도 원시 값이라 개별 문자를 변경할 수 없어.

var str = 'Hello';
str[0] = 'h';  // 에러는 안 나지만, 반영도 안 됨
console.log(str);  // 'Hello'

반면 객체를 변수에 할당하면, 변수에는 **참조 값(메모리 주소)**이 저장돼. 객체를 다른 변수에 할당하면 참조가 복사되기 때문에, 한쪽을 수정하면 다른 쪽에도 영향이 가. 이게 JS에서 가장 흔한 버그 원인 중 하나야.

var person = { name: 'Lee' };
var copy = person;  // 참조 복사
copy.name = 'Kim';
console.log(person.name);  // 'Kim' — 같은 객체를 가리키니까!

Object.assign이나 스프레드 연산자(...)는 1단계까지만 복사하는 얕은 복사야. 중첩 객체까지 완전히 분리하려면 깊은 복사(structuredClone() 등)가 필요하지.

함수는 단순한 코드 묶음이 아니라 값처럼 취급되는 일급 객체야. 정의 방식은 함수 선언문, 함수 표현식, Function 생성자, 화살표 함수 네 가지가 있어.

function add(x, y) { return x + y; }           // 함수 선언문
var add = function (x, y) { return x + y; };   // 함수 표현식
var add = (x, y) => x + y;                      // 화살표 함수 (ES6)

함수 선언문 vs 함수 표현식의 가장 큰 차이는 호이스팅이야. 함수 선언문은 선언 전에 호출할 수 있지만(함수 호이스팅), 함수 표현식은 변수 호이스팅이 적용되어 선언 전에 호출하면 에러가 나거든. 저자는 함수 표현식 사용을 권장해.

JS 함수는 매개변수와 인수의 개수가 달라도 에러가 안 나. 부족한 매개변수는 undefined, 초과된 인수는 arguments 객체에 저장되지. 매개변수 기본값(ES6)으로 undefined 문제를 해결할 수 있어. 원시 값은 값이 복사되므로 함수 내부에서 변경해도 원본에 영향이 없지만, 객체는 참조가 전달되므로 함수 내부에서 변경하면 원본이 바뀌어. 객체를 변경해야 하면 깊은 복사로 새 객체를 만들어서 변경하는 게 안전하지.

다양한 함수 형태도 알아둬야 해. **즉시 실행 함수(IIFE)**는 정의와 동시에 실행되고, 재귀 함수는 자기 자신을 호출하며, 중첩 함수는 함수 안에 정의된 함수로 외부 함수의 변수를 참조할 수 있어(클로저의 기반). 콜백 함수는 다른 함수에 인수로 전달되는 함수이고, 고차 함수는 콜백을 받는 함수야. 순수 함수는 부수 효과가 없고 같은 입력에 항상 같은 출력을 반환하는 함수지.


정리

3장 읽고 기억할 거 세 가지:

  1. 원시 값은 불변 + 값 복사, 객체는 가변 + 참조 복사야. 두 변수가 같은 객체를 공유하는 건 가장 흔한 버그 원인이지.
  2. JS에서 함수는 일급 객체야. 변수에 할당하고, 인수로 전달하고, 반환값으로 쓸 수 있고, 이게 콜백과 고차 함수 패턴의 기반이야.
  3. 함수 표현식을 기본으로 쓰고, 부수 효과를 최소화하는 순수 함수를 지향하자.