객체 리터럴 선언과 렉시컬 스코프

Ethan Yu·2023년 8월 17일
0

Script

목록 보기
1/1

javascript

렉시컬 스코프와 관련하여 결과가 직관적이지 않은 코드를 마주쳐 기록 및 분석하였습니다.

let foo = () => console.log('foo');

// 단축 속성을 이용한 객체 리터럴 선언
const a = { foo }; 
// 함수로 초기화된 속성을 가진 객체 리터럴 선언
const b = {
	foo: () => foo();
};
// 메서드를 이용한 객체 리터럴 선언
const c = {
	bar() {
     	foo(); 
    }
}

a.foo(); // foo
b.foo(); // foo
c.foo(); // foo

foo = () => console.log('new foo');

a.foo(); // foo
b.foo(); // new foo
c.bar(); // new foo

1. 단축 속성을 이용한 객체 리터럴 선언

  • 값이 함수인 속성을 가지고 있으나 해당 값이 이미 평가(렉싱)되었으므로, foo 함수의 재선언에도 불구하고 객체 리터럴의 평가 시점에 이미 객체의 속성인 foo는 결정되었습니다.

2. 함수로 초기화된 속성을 가진 객체 리터럴 선언

  • 값이 함수인 속성을 가지고 있으나, 해당 값은 화살표 함수로 선언한 새로운 익명함수입니다.
  • 객체 리터럴의 평가 시점에는 해당 익명 함수로 감싸진 내부의 foo 함수는 평가되지 않습니다.
  • 즉,foo 함수의 렉시컬 스코프가 결정되지 않았습니다.
  • 해당 속성이 호출될 경우(b.foo())에야 렉시컬 스코프가 결정되기 때문에(lazy-load) foo 속성은 재할당된 foo 함수를 참조할 수 있습니다. (속성이 호출되어야 익명함수의 평가를 시작할 수 있기 때문입니다)

3. 메서드를 이용한 객체 리터럴 선언

  • ES2015+ 부터는 객체 리터럴 안쪽에서도 메서드를 선언할 수 있게 되었습니다.
  • 메서드도 (2) 케이스와 동일하게 lazy-load됩니다.
  • (2) 케이스와의 동작 차이는 메서드 / 함수의 구분에 근거하여 결정됩니다.

cf. 메서드와 함수의 구분

  • 메서드는 prototype도 없고 생성자로도 사용하지 못한다.
  • 메서드는 자신을 바인딩하고 있는 객체와 양방향으로 연결(이를 위해 [[HomeObject]] 슬롯을 이용)되기 때문에 super 키워드를 지원한다. 이때 super 키워드는 자신을 바인딩하고 있는 객체의 prototype을 가리킨다.
    - 이론적으로 [[HomeObject]] 슬롯은 메서드가 super을 사용하는지 여부와 관계없이 존재하긴 하나, 실제적으로 super을 사용하지 않았으면 엔진이 이 링크([[HomeObject]]를 통한 메서드와 바인딩 객체의 연결)를 최적화할 가능성이 있다고 한다. (웹 개발자를 위한 자바스크립트의 모든 것, 2022)
profile
🧐 사용자와 개발자를 모두 배려하고 싶은 개발자. 백엔드부터 임베디드까지 다양하게 개발하다가 지금은 🎨 프런트엔드에 자리잡았어요.

1개의 댓글

comment-user-thumbnail
2023년 8월 17일

유익한 자료 감사합니다.

답글 달기