1 the four invocation forms
GOAL
Burn in the rule that `this` has nothing to do with WHERE a function was written — it is chosen anew at every CALL SITE. One function, four ways to call it, four different `this`.
CONCEPT
1. plain call fn() → undefined (strict mode) 2. method call obj.fn() → obj (receiver left of dot) 3. explicit fn.call(x) → x (also .apply / .bind) 4. constructor new Fn() → a brand-new object, whose hidden [[Prototype]] is wired to Fn.prototype (module 1!).
HINT
Look at each quiz line, work out what the CALL SITE dictates, then type the exact string/boolean that call hands back.
MIRRORS
A game engine you don't own runs YOUR callbacks with a `this` it picks for you: an onHit hook runs with this = the player that was struck, an input-mapping callback with this = the input handle, a level hook with this = the game — every one is form 3 (.call) underneath.
Run
node 01-four-invocation-forms.cjsSource
'use strict';
// ---------------------------------------------------------------------
// PROTO-DOJO · Module 2 / Exercise 1 — the four invocation forms
//
// GOAL: Burn in the rule that `this` has nothing to do with WHERE a
// function was written — it is chosen anew at every CALL SITE.
// One function, four ways to call it, four different `this`.
// CONCEPT: 1. plain call fn() → undefined (strict
// mode) 2. method call obj.fn() → obj (receiver
// left of dot) 3. explicit fn.call(x) → x (also
// .apply / .bind) 4. constructor new Fn() → a
// brand-new object, whose hidden [[Prototype]] is wired to
// Fn.prototype (module 1!).
// HINT: Look at each quiz line, work out what the CALL SITE
// dictates, then type the exact string/boolean that call hands
// back.
// MIRRORS: A game engine you don't own runs YOUR callbacks with a
// `this` it picks for you: an onHit hook runs with this = the
// player that was struck, an input-mapping callback with this
// = the input handle, a level hook with this = the game —
// every one is form 3 (.call) underneath.
//
// Run: node 01-four-invocation-forms.cjs
// ---------------------------------------------------------------------
const assert = require('node:assert');
function reportOwner() {
if (this === undefined) return 'no-owner';
return 'owner:' + this.id;
}
const knightScreen = { id: 'screen-knight', reportOwner: reportOwner };
function InputHandle(id) {
this.id = id;
}
InputHandle.prototype.reportOwner = reportOwner;
// -- TODO 1: replace every '???' with the exact string / boolean produced ---
const quiz = {
// FORM 1 — plain call: reportOwner()
// ('use strict' at the top of this file means NO fallback to the global object)
plainCall: '???',
// FORM 2 — method call: knightScreen.reportOwner()
// the receiver left of the dot becomes `this`
methodCall: '???',
// FORM 3 — explicit: reportOwner.call({ id: 'screen-rogue' })
explicitCall: '???',
// FORM 4 — constructor: new InputHandle('gamepad-1').reportOwner()
// `new` builds a fresh object, wires its hidden link to InputHandle.prototype,
// runs the constructor with `this` = that fresh object… and then the
// .reportOwner() part is an ordinary FORM 2 call on the result.
constructorCall: '???',
// and the wiring `new` performed, true or false:
// Object.getPrototypeOf(new InputHandle('x')) === InputHandle.prototype
newLinksPrototype: '???',
};
// -- checks -----------------------------------------------------------
assert.strictEqual(quiz.plainCall, reportOwner(),
'FORM 1: strict-mode plain call → this is undefined, no global fallback');
assert.strictEqual(quiz.methodCall, knightScreen.reportOwner(),
'FORM 2: the receiver left of the dot becomes this');
assert.strictEqual(quiz.explicitCall, reportOwner.call({ id: 'screen-rogue' }),
'FORM 3: .call aims this explicitly — the engine-invokes-your-hook form');
assert.strictEqual(quiz.constructorCall, new InputHandle('gamepad-1').reportOwner(),
'FORM 4: this = the freshly created object, then a method call on it');
assert.strictEqual(
quiz.newLinksPrototype,
Object.getPrototypeOf(new InputHandle('x')) === InputHandle.prototype,
'`new` wires the hidden link to Fn.prototype — module 1 says hello'
);
console.log('PASS — 01-four-invocation-forms: the call site decides, every time');