JavaScript Language Model

"JavaScript 코드의 변수, 값, 함수, this, 객체, 모듈은 어떤 규칙으로 동작하고, ES6+ 문법은 각각 어떤 문제를 풀려고 생겼는가?" 이 page는 그 질문에 답한다. ECMAScript는 JavaScript 언어의 표준 사양이고, JavaScript는 브라우저나 Node.js 같은 실행 환경에서 동작하는 실제 언어다.[1] Frontend Wiki에서 이 page는 맨 아래 층에 놓인다고 볼 수 있다. SPA and CSR이 "browser JavaScript runtime"이라고, Vue.js가 "JavaScript state"라고만 부르던 층의 규칙을 여기서 설명한다. 오래 걸리는 작업의 흐름은 JavaScript Asynchronous Execution이, DOM과 script 실행 시점은 Browser DOM and Script Loading이 맡는다.

언어와 실행 환경의 경계

언어 특성

ES6가 풀려던 문제

ES6 이전의 불편[9:1] ES6+에서 쓰는 문법[10:1] 이 Wiki에서 다루는 곳
var만 있어 스코프 관리가 어렵다. let, const 스코프와 변수 선언
표준 모듈 시스템이 없어 파일 간 의존성을 관리하기 어렵다. module (import/export) 모듈
객체 지향 문법이 prototype 기반이라 처음 배우기 어렵다. class 객체 모델: prototype과 class
비동기 코드를 작성하면 콜백 중첩이 심해진다. Promise [[Wiki/frontend/concepts/javascript-asynchronous-execution
객체와 배열을 다루는 문법이 장황하다. destructuring, spread, arrow function 객체·배열 문법, 함수 호출과 this

스코프와 변수 선언

var count = 99;

for (var count = 0; count < 5; count++) {
  console.log(count);
}

console.log(count); // 5
const user = {
  name: "hong",
};

user.name = "kim"; // 가능

user = {
  name: "lee",
}; // TypeError
선언 스코프 선언 전 접근 재할당
var 함수 스코프, 블록이 범위를 제한하지 못한다.[14:1] undefined가 나온다.[17:1] 가능하다(위 루프 예제에서 count가 바뀐다).[14:2]
let 블록 스코프다.[15:1] TDZ에서 ReferenceError가 난다.[18:2] 가능하다.[19]
const 원문은 따로 적지 않는다. TDZ에서 ReferenceError가 난다.[18:3] 불가능하다. 다만 객체 내부 프로퍼티 변경은 막지 않는다.[16:1]

값과 참조

const original = {
  name: "hong",
  address: {
    city: "seoul",
  },
};

const copied = {
  ...original,
};

copied.address.city = "busan";

console.log(original.address.city); // busan

값 평가: truthy와 falsy, ||, ??, ?.

const age = 0;

console.log(age || "값누락"); // "값누락"
console.log(age ?? "값누락"); // 0
a의 값 조건 평가 a || "기본값" a ?? "기본값"
0 falsy "기본값" 0
"" falsy "기본값" ""
false falsy "기본값" false
null falsy "기본값" "기본값"
undefined falsy "기본값" "기본값"

함수는 값이다

const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map((number) => number * 2);
const evens = numbers.filter((number) => number % 2 === 0);
const sum = numbers.reduce((total, number) => total + number, 0);

함수형 프로그래밍과 클로저

function fizzclosure() {
    const fizz = (index) => (index % 3 === 0) ? "fizz" : "";
    const buzz = (index) => (index % 5 === 0) ? "buzz" : "";
    Array(100).fill().map((x, i) => i + 1).forEach(index => {
        let result = fizz(index) + buzz(index);
        console.log(result.length == 0 ? `${index}` : result);
    });
}

함수 호출과 this

const person = {
  name: "Alice",

  sayHello: function () {
    setTimeout(() => {
      console.log(this.name);
    }, 100);
  },
};

person.sayHello(); // Alice
구분 일반 함수 화살표 함수
this를 정하는 기준 호출 방식[42:2] 선언된 위치의 상위 스코프 this[46:1]
setTimeout 같은 콜백 안에서 바깥 객체의 this를 잃을 수 있다.[44:1] 바깥 함수의 this를 그대로 쓴다.[46:2]
객체 메서드로 쓸 때 호출한 객체를 this로 받는다.[42:3] 호출한 객체를 받지 못한다.[48:1]

객체·배열 문법

객체 모델: prototype과 class

const parent = {
  sayHello() {
    console.log("hello");
  },
};

const child = Object.create(parent);

child.sayHello(); // hello

모듈

// 내보내기
export const PI = 3.14;
export default function greet() {}

// 가져오기
import greet, { PI } from './module.js';

Proxy와 Reflect

const state = new Proxy(
  {
    count: 0,
  },
  {
    set(target, prop, value, receiver) {
      const result = Reflect.set(target, prop, value, receiver);

      console.log(`${prop} 값이 ${value}로 변경되었습니다.`);
      return result;
    },
  }
);

state.count = 1;

흔한 실패 모드

실수 결과 원인
||로 기본값을 준다. 유효한 0, "", false가 기본값으로 덮인다.[24:1] ||는 falsy 전체를 대체한다.
선언 전에 변수를 쓴다. var는 undefined로 버그를 숨기고, let·const는 ReferenceError를 낸다.[17:2][18:4] 호이스팅 뒤 초기화 방식이 다르다.
const 객체를 불변으로 여긴다. 내부 프로퍼티가 바뀐다.[16:2] const는 재할당만 막는다.
메서드를 떼어 호출하거나 일반 함수를 콜백으로 넘긴다. this가 원래 객체를 가리키지 않을 수 있다.[42:4][44:2] 일반 함수의 this는 호출 방식으로 정해진다.
화살표 함수를 객체 메서드로 쓴다. 호출한 객체를 this로 받지 못한다.[48:2] 화살표 함수는 자기 this를 만들지 않는다.
Spread 복사본의 중첩 객체를 바꾼다. 원본의 중첩 객체도 바뀐다.[21:1] Spread는 얕은 복사다.
class를 prototype과 별개인 모델로 여긴다. prototype chain으로 동작하는 코드를 이해하지 못한다.[56:1][57:2] class는 prototype 위의 문법적 설탕이다.

관련

테스트 질문

출처


  1. ECMAScript.md (Study) 36-40줄 — "ECMAScript는 JavaScript 언어의 표준 사양이다.", "JavaScript는 브라우저나 Node.js 같은 실행 환경에서 동작하는 실제 언어이고, ECMAScript는 그 언어가 어떤 문법과 동작 규칙을 가져야 하는지 정의하는 표준이다.", "즉, ECMAScript는 JavaScript의 핵심 문법과 동작 방식을 정의한다." ↩︎ ↩︎

  2. ECMAScript.md (Computing) 14줄 — "ECMA에서 표준 관리" ↩︎

  3. ECMAScript.md (Study) 42줄 — "브라우저의 DOM API, window, document, fetch 같은 기능은 JavaScript 실행 환경이 제공하는 API이며, ECMAScript 자체의 핵심 문법과는 구분된다." ↩︎

  4. JavaScript.md 22줄 — "웹 클라이언트 뿐 아니라 node.js를 이용해 backend 부분도 제작" ↩︎

  5. JavaScript.md 9줄 — "동적 타이핑, 객체 지향, 함수 프로그래밍 등 활용도 높은 스크립트 언어" ↩︎

  6. JavaScript.md 13-15줄 — "abstraction: 객체나 함수를 통한 추상화 제공", "inheritance & polymorphism: class기반 상속이 아닌 prototype 개념 활용", "encapsulation: closure 활용" ↩︎ ↩︎

  7. JavaScript.md 19-20줄 — "호스트 실행 환경에 종속적", "일반적으로 독립적인 실행파일을 만들지 않음" ↩︎

  8. 출처 공백 — 실행 방식을 다룬 줄은 JavaScript.md 17-18줄과 ECMAScript.md (Computing) 15줄뿐이고, 두 노트의 설명은 서로 맞지 않는다. 같은 노트 묶음의 hub가 링크한 V8 노트는 Raw에 없다. 엔진 실행 방식은 공식 자료가 들어올 때까지 보류한다. ↩︎

  9. ECMAScript.md (Study) 46-54줄 — "ES6는 JavaScript 문법에 큰 변화를 가져온 버전이다.", "var만 존재해서 스코프 관리가 어렵다.", "모듈 시스템이 표준으로 존재하지 않아 파일 간 의존성을 관리하기 어렵다.", "객체 지향 문법이 prototype 기반이라 처음 배우기 어렵다.", "비동기 코드를 작성하면 콜백 중첩이 심해진다.", "객체와 배열을 다루는 문법이 장황하다." ↩︎ ↩︎

  10. ECMAScript.md (Study) 56줄 — "ES6 이후에는 let, const, arrow function, class, module, destructuring, spread, Promise 같은 문법이 추가되어 JavaScript를 더 안전하고 구조적으로 작성할 수 있게 되었다." ↩︎ ↩︎

  11. ECMAScript.md (Computing) 16줄 — "2015년 ES6부터 객체지향 프로그래밍 언어로 진화". 이 page는 연도만 옮겼다. "객체지향 언어로 진화"라는 부분은 같은 노트 10줄과 함께, class 기반이 아닌 prototype 상속(JavaScript.md 14줄)과 class가 prototype 위의 문법적 설탕이라는 설명(ECMAScript.md (Study) 796-798줄)에 맞지 않아 옮기지 않았다. ↩︎

  12. ECMAScript.md (Study) 64-66줄 — "스코프는 변수가 유효한 범위이다.", "JavaScript에서 변수를 찾을 때는 현재 스코프에서 먼저 찾고, 없으면 바깥 스코프로 올라가며 찾는다. 이 구조를 스코프 체인이라고 한다." ↩︎

  13. ECMAScript.md (Study) 68-73줄 — "변수가 어디까지 살아 있는지 예측하기 어렵다.", "같은 이름의 변수가 서로 영향을 줄 수 있다.", "전역 변수가 의도치 않게 변경될 수 있다.", "클로저와 모듈을 이해하기 어렵다." ↩︎

  14. ECMAScript.md (Study) 77-91줄 — "var는 블록 스코프를 따르지 않고 함수 스코프를 따른다.", "즉, if, for의 중괄호 {}는 var의 스코프를 제한하지 못한다.", "기존 count와 같은 스코프의 변수로 취급되기 때문에 루프가 끝난 후 count 값이 5로 바뀐다." 코드 81-89줄을 그대로 옮겼다. ↩︎ ↩︎ ↩︎

  15. ECMAScript.md (Study) 97-120줄 — "let은 블록 스코프를 따른다.", 코드 105줄 "console.log(message); // ReferenceError", "반복문에서 사용하는 임시 변수가 외부 스코프로 새어 나가지 않으므로 안전하다." ↩︎ ↩︎

  16. ECMAScript.md (Study) 131-151줄 — "참조가 가리키는 객체의 내부 값은 변경할 수 있다.", "const는 재할당을 막는다.", "객체 내부의 프로퍼티 변경까지 막지는 않는다.", "객체 자체를 불변으로 만들고 싶다면 별도의 불변 처리 방식이 필요하다." 코드 135-145줄을 그대로 옮겼다. ↩︎ ↩︎ ↩︎

  17. ECMAScript.md (Study) 155-174줄 — "호이스팅은 선언이 코드 실행 전에 먼저 처리되는 JavaScript의 동작 방식이다.", "var는 선언과 초기화가 함께 처리된다.", "그래서 선언 전에 접근해도 에러가 아니라 undefined가 나온다." ↩︎ ↩︎ ↩︎

  18. ECMAScript.md (Study) 178-189줄 — "let과 const도 호이스팅된다. 하지만 선언 전에 접근할 수 없다.", "변수가 선언되기 전까지의 구간을 TDZ, 즉 일시적 사각지대라고 한다.", "TDZ는 실수를 조기에 발견하게 해준다.", "var는 선언 전에 접근해도 undefined를 반환하기 때문에 버그를 숨길 수 있다. 반면 let과 const는 초기화 전에 접근하면 에러를 발생시켜 잘못된 사용을 막는다." ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  19. ECMAScript.md (Computing) 28-31줄 — 코드 주석 "재할당 가능"(let), "재할당 불가"(const) ↩︎

  20. ECMAScript.md (Computing) 20-23줄 — 원시타입 "값 자체를 저장", 참조타입(객체, 배열) "같은 공간에서 값을 참조 → 변경 시 같은 값으로 출력". 같은 표의 원시 타입 이름 목록(string, integer, boolean)은 JavaScript 타입 이름과 맞는지 원문으로 확인할 수 없어 옮기지 않았다. ↩︎

  21. ECMAScript.md (Study) 589-610줄 — "Spread는 얕은 복사를 수행한다.", "얕은 복사는 가장 바깥 레벨만 새로 만들고, 내부의 중첩 객체는 같은 참조를 공유한다.", "copied는 새 객체지만, address는 원본과 같은 객체를 가리킨다." 코드 593-608줄을 그대로 옮겼다. ↩︎ ↩︎

  22. ECMAScript.md (Study) 612-618줄 — "중첩 객체까지 독립적으로 복사하려면 깊은 복사가 필요하다.", "단, structuredClone()도 함수나 DOM 노드처럼 복사할 수 없는 값이 있다." ↩︎

  23. ECMAScript.md (Study) 199-213줄 — falsy 값 목록(false, 0, -0, "", null, undefined, NaN), "그 외 대부분의 값은 truthy로 평가된다.", "중요한 점은 0, "", false도 실제로는 의미 있는 값일 수 있다는 것이다." ↩︎

  24. ECMAScript.md (Study) 217-236줄 — "||는 단순히 true 또는 false를 반환하는 연산자가 아니다.", "왼쪽 값이 truthy면 왼쪽 값을 그대로 반환하고, 왼쪽 값이 falsy면 오른쪽 값을 반환한다.", "0은 나이 값으로는 유효하지만, JavaScript의 조건 평가에서는 falsy이므로 오른쪽 값이 선택된다." ↩︎ ↩︎

  25. ECMAScript.md (Study) 240-263줄 — "??는 nullish 값만 기본값으로 대체한다.", "??는 0, false, ""를 유효한 값으로 보존한다.", "실무에서는 0, false, ""가 의미 있는 입력값인 경우가 많으므로 기본값 처리에는 ??가 더 안전한 경우가 많다." 코드 249-254줄을 그대로 옮겼다. ↩︎

  26. ECMAScript.md (Study) 279-302줄 — "Optional Chaining을 사용하면 중간 값이 null 또는 undefined일 때 에러를 발생시키지 않고 undefined를 반환한다.", "이 문법은 API 응답처럼 구조가 항상 보장되지 않는 데이터를 다룰 때 유용하다.", "Optional Chaining은 에러를 숨기는 도구가 아니라, 값이 없을 수 있는 구조를 명시적으로 다루는 도구로 이해하는 것이 좋다." ↩︎

  27. ECMAScript.md (Study) 317-323줄 — "템플릿 리터럴을 사용하면 문자열 안에 표현식을 직접 넣을 수 있다.", "또한 여러 줄 문자열을 자연스럽게 작성할 수 있다." ECMAScript.md (Computing) 38-42줄에 같은 문법의 예시가 있다. ↩︎

  28. 출처 공백 — ECMAScript.md (Study)는 ??, ?., structuredClone() 등의 도입 버전을 적지 않는다. TypeScript와 JavaScript의 관계도 이 batch의 page 근거에 없다. ↩︎

  29. ECMAScript.md (Study) 338-354줄 — "JavaScript에서 함수는 값이다.", "함수를 변수에 담을 수 있고, 다른 함수의 인자로 전달할 수 있으며, 함수의 반환값으로 사용할 수도 있다.", "이 특성 때문에 콜백 함수, 고차 함수, 비동기 처리 같은 패턴이 가능하다." ↩︎

  30. 함수형 프로그래밍.md 17-22줄 — "일급 시민 (First-class Citizen)", "변수에 할당", "함수의 인자로 전달", "함수의 반환값으로 사용" ↩︎

  31. ECMAScript.md (Study) 358-377줄 — "기본 매개변수는 인자가 전달되지 않았을 때 사용할 기본값을 정한다.", "기본 매개변수를 사용하면 함수 내부에서 다음과 같은 방어 코드를 줄일 수 있다." ECMAScript.md (Computing) 56-61줄에 같은 문법의 예시가 있다. ↩︎

  32. ECMAScript.md (Study) 381-393줄 — "Rest Parameter는 여러 인자를 배열로 모은다.", "Rest Parameter는 인자의 개수가 정해지지 않은 함수를 만들 때 사용한다.", "주의할 점은 Rest Parameter는 항상 마지막 매개변수여야 한다." ↩︎

  33. ECMAScript.md (Study) 693-700줄 — "map: 각 요소를 변환해 새 배열을 만든다.", "filter: 조건을 만족하는 요소만 모아 새 배열을 만든다.", "reduce: 배열을 하나의 값으로 누적한다.", "forEach: 각 요소에 대해 작업을 수행하지만 반환값을 모으지는 않는다.", "배열 메서드는 원본 데이터를 직접 변경하지 않는 방식의 코드를 작성할 때 유용하다." 코드 685-691줄을 그대로 옮겼다. ↩︎ ↩︎

  34. 함수형 프로그래밍.md 54, 64, 74줄 — "각 요소를 변환하여 새로운 배열 생성. 원본 불변.", "조건을 만족하는 요소들만 모아 새로운 배열 생성.", "배열 요소를 순회하며 하나의 결과값 생성." ↩︎

  35. 함수형 프로그래밍.md 88줄 — "reduce는 map과 filter 모두 구현 가능 — 가장 범용적인 고차함수." 바로 위 81-85줄의 "map을 reduce로 구현" 예제는 숫자 배열(77줄)에 value.length를 써서 의도대로 동작하지 않으므로 옮기지 않았다. ↩︎

  36. ECMAScript.md (Study) 585줄 — "Spread는 원본을 직접 수정하지 않고 새 배열이나 객체를 만들 때 자주 사용된다." ↩︎

  37. 함수형 프로그래밍.md 11줄 — "함수를 일급 시민으로 취급하고, 부수 효과를 피하며, 불변 데이터를 다루는 프로그래밍 패러다임." ↩︎

  38. 함수형 프로그래밍.md 26-28줄 — "동일한 입력 → 항상 동일한 출력", "외부 상태를 변경하지 않음 (Side Effect 없음)", "참조 투명성 보장" ↩︎

  39. 함수형 프로그래밍.md 32, 34줄 — "값이 한 번 할당되면 변경되지 않음", "예측 가능한 코드 작성 가능". 사이의 33줄 "람다 계산법의 근간"은 근거가 없는 단정이라 옮기지 않았다. ↩︎

  40. 함수형 프로그래밍.md 40줄 — "선언된 범위(스코프)의 변수를 캡처해서 저장". 38-39줄의 "람다 계산식의 구현체", "이름 없는 함수로 리터럴하게 작성 가능"은 익명 함수와 클로저를 섞은 설명이라 옮기지 않았다. ↩︎

  41. 함수형 프로그래밍.md 104-112줄 — "2. 클로저 활용 — 각 판단 로직을 함수로 분리" 코드를 그대로 옮겼다. ↩︎

  42. ECMAScript.md (Study) 403-425줄 — "JavaScript의 일반 함수에서 this는 함수가 선언된 위치가 아니라 호출 방식에 따라 결정된다.", "위 코드에서 sayHello는 user.sayHello() 형태로 호출되었기 때문에 this는 user가 된다.", "하지만 메서드를 변수에 따로 담아 호출하면 this 연결이 끊길 수 있다." ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  43. DOM.md (JavaScript) 13-14줄 — "현재 실행 문맥(context) - 현재 함수를 호출한 객체", "자바와 달리 함수가 선언될 때가 아니라 함수가 호출될 때 동적으로 결정" ↩︎

  44. ECMAScript.md (Study) 429-449줄 — "콜백 함수로 일반 함수를 전달하면, 원래 객체의 this를 잃어버릴 수 있다.", "브라우저 일반 script에서는 window를 가리킬 수 있고, Node.js에서는 Timeout 객체를 가리킬 수 있다. strict mode나 module 환경에서는 다르게 동작할 수 있다.", "핵심은 콜백 내부 일반 함수의 this가 바깥 객체와 자동으로 연결되지 않는다는 것이다." ↩︎ ↩︎ ↩︎

  45. DOM.md (JavaScript) 17-19줄 — "기본 바인딩", "일반적인 방식으로 그 함수를 호출한 객체", "non-strict에서 호출 객체 생략 시 window" ↩︎

  46. ECMAScript.md (Study) 453-471줄 — "화살표 함수는 자기만의 this를 만들지 않는다.", "대신 자신이 선언된 위치의 상위 스코프에 있는 this를 그대로 사용한다. 이를 lexical this라고 한다.", "화살표 함수는 자신의 this를 만들지 않으므로, 바깥 함수인 sayHello의 this를 사용한다." 코드 457-468줄을 그대로 옮겼다. ↩︎ ↩︎ ↩︎

  47. DOM.md (JavaScript) 32-33줄 — "arrow함수는 자신만의 this를 가지지 않음", "자신이 선언된 상위 scope의 this를 그대로 물려받음(lexical this)" ↩︎

  48. ECMAScript.md (Study) 475-493줄 — "화살표 함수는 콜백에서는 유용하지만, 객체 메서드 자체로 사용할 때는 주의해야 한다.", "화살표 함수는 자기만의 this를 만들지 않기 때문에 person을 this로 받지 않는다.", "ES Module이나 strict mode 환경에서는 this가 undefined라 에러가 날 수 있다.", "따라서 객체 메서드에는 일반 함수 문법을 사용하는 것이 안전하다." ↩︎ ↩︎ ↩︎

  49. 출처 공백 — DOM.md (JavaScript) 21-25줄에 "묵시적 바인딩", "명시적 바인딩", "new 바인딩" 제목만 있고 본문이 없다. call, apply, bind는 이 batch의 어느 Raw에도 없다. 명시적 바인딩을 다룬 source가 들어오면 이 절을 보강한다. ↩︎

  50. ECMAScript.md (Study) 501-534줄 — "객체를 만들 때 변수명과 프로퍼티명이 같으면 단축해서 쓸 수 있다.", "메서드도 짧게 작성할 수 있다.", "객체 단축 문법은 코드의 반복을 줄이고 객체 구조를 더 명확하게 보여준다." ↩︎

  51. ECMAScript.md (Study) 538-561줄 — "객체의 key를 변수나 표현식으로 만들 수 있다.", "[] 안의 표현식이 평가된 결과가 프로퍼티 이름이 된다.", "API 응답 가공, 동적 폼 데이터, 설정 객체를 만들 때 유용하다." ↩︎

  52. ECMAScript.md (Study) 622-677줄 — "구조 분해 할당은 배열이나 객체에서 필요한 값을 꺼내 변수로 선언하는 문법이다.", "변수 이름을 바꾸고 싶으면 별칭을 사용할 수 있다.", "Rest 문법과 함께 사용할 수도 있다.", "중첩 객체에서도 사용할 수 있다.", "다만 중첩이 너무 깊으면 가독성이 떨어질 수 있으므로 적절히 나누어 쓰는 것이 좋다." ECMAScript.md (Computing) 44-48줄에 배열·객체 destructuring 예시가 있다. ↩︎

  53. ECMAScript.md (Study) 704-725줄 — "Set은 중복 없는 값의 집합이다.", "Map은 key-value 데이터를 저장한다.", "일반 객체와 달리 Map은 key로 문자열뿐 아니라 객체, 함수 등 다양한 값을 사용할 수 있다." ↩︎

  54. ECMAScript.md (Study) 733-751줄 — "JavaScript는 prototype 기반 객체 지향 언어다.", "객체는 자신이 직접 가진 프로퍼티를 먼저 찾고, 없으면 자신의 prototype에서 찾는다. prototype에도 없으면 그 위의 prototype으로 계속 올라간다.", "이 연결 구조를 prototype chain이라고 한다." 코드 739-749줄을 그대로 옮겼다. ↩︎

  55. ECMAScript.md (Study) 773-775줄 — "sayHello를 생성자 내부에 만들면 인스턴스마다 함수가 새로 생성된다. 반면 prototype에 메서드를 등록하면 모든 인스턴스가 같은 메서드를 공유한다.", "이 방식은 메모리 효율적이다." ↩︎

  56. ECMAScript.md (Study) 779, 796-798줄 — "ES6의 class는 prototype 기반 객체 모델을 더 익숙하고 읽기 쉬운 문법으로 감싼 것이다.", "class는 새로운 객체 모델을 만든 것이 아니라, 기존 prototype 구조를 더 명확한 문법으로 표현한 것이다.", "즉, class는 prototype의 대체가 아니라 prototype을 사용하는 문법적 설탕이라고 볼 수 있다." ↩︎ ↩︎

  57. ECMAScript.md (Study) 1421-1423줄 — "class 문법으로 작성한 메서드도 내부적으로는 prototype에 등록된다.", "따라서 JavaScript의 객체 모델을 제대로 이해하려면 class만 외우는 것보다 prototype chain을 함께 이해해야 한다." 이 문장은 노트의 질문 절(1333줄 [!ai] AI 답변 callout 아래)에 있다. ↩︎ ↩︎ ↩︎

  58. ECMAScript.md (Study) 802-884줄 — "constructor는 인스턴스가 생성될 때 실행되는 초기화 메서드다.", "static 메서드는 인스턴스가 아니라 클래스 자체에 속한 메서드다.", "#을 사용하면 클래스 내부에서만 접근 가능한 private field를 만들 수 있다.", "extends를 사용하면 기존 클래스를 상속할 수 있다.", "자식 클래스에서 부모 클래스의 메서드를 같은 이름으로 다시 정의하면 오버라이딩이 된다." ECMAScript.md (Computing) 63-73줄에 class 예시가 있다. ↩︎

  59. ECMAScript.md (Study) 894-899줄 — "캡슐화: private field와 관련", "상속: extends, super, method overriding과 관련", "SOLID는 설계 원칙이므로 별도 OOP 또는 객체지향 설계 문서로 분리하는 것이 좋다." ↩︎

  60. 출처 공백 — 이 노트 묶음의 JavaScript hub 노트(Raw/legacy/knowledge/04 - Knowledge/Computing/JavaScript/_JavaScript.md 20줄)가 링크한 "프로토타입 패턴" 노트는 Raw에 없다. 부스트캠프 학습정리 원본은 이번 batch에서 읽지 않았다. ↩︎

  61. ECMAScript.md (Study) 909-916줄 — "모듈이 없다면 여러 파일이 같은 전역 스코프를 공유하게 된다.", "서로 다른 파일의 변수명이 충돌할 수 있다.", "파일 로딩 순서에 따라 코드가 깨질 수 있다.", "어떤 파일이 어떤 기능에 의존하는지 파악하기 어렵다.", "모듈 시스템은 각 파일에 독립적인 스코프를 제공하고, export와 import를 통해 명시적으로 의존성을 연결한다." ↩︎

  62. ECMAScript.md (Study) 920-960줄 — "Named Export는 여러 값을 이름을 붙여 내보내는 방식이다.", "이름을 바꾸고 싶으면 alias를 사용할 수 있다.", "Default Export는 한 파일에서 대표 값을 하나 내보내는 방식이다.", "가져올 때는 원하는 이름으로 받을 수 있다." 코드는 ECMAScript.md (Computing) 91-98줄을 그대로 옮겼다. ↩︎

  63. ECMAScript.md (Study) 964-974줄 — "ESM의 import는 정적 import다.", "정적 import는 코드 실행 전에 모듈 의존성을 먼저 분석할 수 있다는 뜻이다.", "사용하지 않는 코드를 제거하는 tree shaking 최적화에 유리하다.", "import 선언은 모듈 평가 전에 처리된다. 그래서 개념적으로는 호이스팅된다고 설명할 수 있다." ↩︎

  64. ECMAScript.md (Study) 998-1019줄 — "CommonJS는 Node.js에서 많이 사용되던 모듈 시스템이다.", "CommonJS는 런타임에 require()로 모듈을 불러온다.", "ESM은 코드 실행 전에 import/export 구조를 정적으로 분석한다.", "ESM은 브라우저 표준 모듈 시스템으로도 사용된다." ↩︎

  65. ECMAScript.md (Study) 980줄 — "브라우저에서 ESM을 사용하려면 script 태그에 type="module"을 지정한다." ↩︎

  66. ECMAScript.md (Study) 1183-1214줄 — "Proxy는 객체의 기본 동작을 가로채는 객체다.", "객체의 속성을 읽거나, 값을 변경하거나, 속성을 삭제하는 동작 사이에 중간 로직을 넣을 수 있다.", "Proxy에서 특정 동작을 가로채는 메서드를 trap이라고 한다.", "get: 속성 조회를 가로챈다.", "set: 속성 할당을 가로챈다.", "has: in 연산자를 가로챈다.", "deleteProperty: 속성 삭제를 가로챈다." ↩︎

  67. ECMAScript.md (Study) 1229-1249줄 — "Reflect는 객체의 기본 동작을 함수 형태로 제공하는 내장 객체다.", "Proxy trap 안에서 원래 동작을 그대로 수행하고 싶을 때 사용한다.", "Proxy는 가로채는 역할이고, Reflect는 기본 동작을 안전하게 위임하는 역할로 이해할 수 있다." ↩︎

  68. ECMAScript.md (Study) 1253, 1279, 1301줄 — "Proxy를 사용하면 객체에 값을 넣을 때 검증할 수 있다.", "Proxy를 사용하면 특정 속성 접근을 제한할 수도 있다.", "이처럼 Proxy는 객체의 사용 규칙을 객체 바깥에서 감싸는 방식으로 정의할 수 있다." ↩︎

  69. ECMAScript.md (Study) 1305-1327줄 — "Proxy는 값이 변경되는 순간을 감지할 수 있다.", "이 원리를 이용하면 데이터가 바뀔 때 화면을 다시 그리는 반응형 시스템의 기초를 만들 수 있다.", "Vue 3의 반응형 시스템도 Proxy 기반 아이디어와 연결된다." 코드 1307-1323줄을 그대로 옮겼다. ↩︎