Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions this-binding/03_lyw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* ❓ 문제: this 바인딩 + 클로저 + 비동기 흐름까지 종합 예측하기 (중급)
*
* 출력 결과를 각 줄마다 예측하세요.
* 요구사항:
* 1) console.log가 총 5번 실행되는데, 순서와 값을 각각 예측할 것
* 2) 왜 그런 결과가 나오는지 this 바인딩 / 클로저 / 마이크로태스크(Promise) 관점에서 설명
* 3) 특히 setTimeout 내부 this, 화살표 함수 this, bind된 함수 this, call로 변경된 this 등 차이를 반드시 언급할 것
*/

var name = "Global";

Comment on lines +11 to +12

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

this/name 결과가 런타임(브라우저/Node, module/strict)에 따라 달라져 예제가 비결정적입니다.

  • fn1()는 ES module/strict에선 this === undefinedthis.x 접근 시 예외가 날 수 있습니다.
  • var name = "Global"은 Node에서 globalThis.name을 보장하지 않고, setTimeout 콜백의 this도 브라우저/Node에서 다릅니다.
    학습용이면 “브라우저의 classic script(비-module) 기준” 같은 전제를 상단에 명시하거나, globalThis를 사용해 전역 값을 분리해서 보여주는 쪽이 안전합니다.
-var name = "Global";
+globalThis.name = "Global";
-    setTimeout(function () {
-      console.log("4:", this.name); // setTimeout은 this를 바이딩하지 않음 = Global
-    }, 0);
+    setTimeout(function () {
+      // 런타임별로 this가 달라질 수 있어 globalThis도 함께 보여주는 편이 안전
+      console.log("4:", this && this.name, "(globalThis:", globalThis.name + ")");
+    }, 0);

Also applies to: 21-41

🤖 Prompt for AI Agents
In this-binding/03_lyw.js around lines 11-12 (and similar cases at 21-41), the
example relies on environment-dependent behavior of `this` and `var name` which
makes the output non-deterministic across strict/module/Node/browser contexts;
either (A) explicitly state at the top that the examples assume "browser classic
script (non-module) environment" so readers know the precondition, or (B) make
the code deterministic by replacing global `var name = "Global"` with
`globalThis.name = "Global"` (or reference `globalThis` for the global value)
and change functions that rely on implicit `this` to use explicit receivers
(pass the object or use `.call/.bind`) or read from `globalThis` so behavior is
consistent across environments; apply the same change to the similar examples in
lines 21-41.

const obj = {
name: "OBJ",
x: 10,

getX() {
return this.x;
},

run() {
// 1) 클로저가 원본 this를 유지하지 않는 경우
const fn1 = this.getX;
console.log("1:", fn1()); // 일반함수 this는 window객체 참조 = undefined

// 2) call로 this를 즉시 변경
console.log("2:", fn1.call(obj)); // call로 obj를 불러와서 this.x 는 obj의 x = 10

// 3) bind로 this 영구 고정
const fn2 = this.getX.bind(this);
console.log("3:", fn2()); // getX에 this를 고정으로 obj 바인딩 = 10

// 4) setTimeout 전통 함수 → this 자동 바인딩 없음
setTimeout(function () {
console.log("4:", this.name); // setTimeout은 this를 바이딩하지 않음 = Global
}, 0);

// 5) Promise + 화살표 함수 → 상위 this를 캡처

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

녀석아
프로미스는 마이크로태스큐
셋타임아웃은 태스크큐

그래서 마이크로 > 테스크 이렇게 실행된다

Promise.resolve().then(() => {
console.log("5:", this.name); // 비동기함수는 this를 바이딩하지 않지만 화살표함수는 this를 부모의 this를 가져옴 = OBJ
});
Comment on lines +33 to +41

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

기대 출력 순서가 틀립니다(마이크로태스크가 타이머보다 먼저 실행).
Promise.then(microtask)은 현재 콜스택 종료 직후 setTimeout(..., 0)(macrotask)보다 먼저 실행되므로, 실제 순서는 1,2,3,5,4가 됩니다. 주석의 “4 다음 5”는 수정 필요합니다.

-// 4: Global
-// 5: OBJ
+// 5: OBJ
+// 4: Global

Also applies to: 46-51

},
};

obj.run();
// 실행결과
// 1: undefined
// 2: 10
// 3: 10
// 4: Global
// 5: OBJ