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

const a = { foo }; // 렉시컬 스코프에 의해 변수 a가 js 인터프리터에 의해 평가될 때 foo 메서드는 1번 라인의 foo 함수로 결정되어 있다.
const b = {
  foo: () => foo() // b.foo() 메서드를 호출해야 평가 되기에 foo 의 스코프는 아직 결정되지 않았다. 그래서 8번 line에서 foo 함수를 재할당한 뒤 b.foo()를 호출하면 그 떄 foo 메서드가 평가되면서 재할당된 foo 함수를 바라본다.
}

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

a.foo() // foo
b.foo() // new foo

console.log(a)

렉시컬 스코프란?
js code가 인터프리팅될 때 토크나이징, 렉싱 과정이 있는데
토크나이징은 js code를 분석할 수 있게 토큰화 하는 과정이고,
렉싱 과정은 토크나이징 과정에서 생성된 토큰들을 분석하여 의미를 부여한다.
렉싱 과정을 렉스타임이라 하며, 이 렉스타임에서 스코프가 결정된다.
이러한 스코프를 렉시컬 스코프라 하며, js는 렉시컬 스코프를 따른다.
위 코드에서 변수 a가 평가될 때 a 객체의 foo 메서드는 이미 렉스타임에 스코프가 결정됨으로 1번 라인의 foo 함수로 결정됬음으로, 그 아래서 foo 변수를 재할당하더라도 영향이 없다.
그러나 b.foo 메서드는 foo 메서드가 호출되야 익명 함수가 평가되는 레이지 로드에 의해 아직 스코프가 결정되지 않았다. 그래서 foo 함수를 재할당한 뒤 b.foo 메서드를 호출하면 그 때 평가가 이뤄지면서 foo 함수는 재할당된 foo 함수를 참조한다.