completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Polyfill call, apply & bind

Build myCall, myApply, and myBind while comparing strict this, array-like apply arguments, partial binding, and new-aware constructors.

By the end, you can
  • 01
    Build call and applyCall a function from an object to set this, check the list of values apply gets, and remove the temporary key after every call.
  • 02
    Build bindReturn a wrapper that keeps this, puts saved values first, and knows when it was called with new.
  • 03
    Compare your helpers with the built-insCheck where the helpers give the same result as the built-in methods: strict functions, primitives, name and length, new, arrow functions, and classes.

Build call, apply, and bind yourself

Inside a function, this is the object the function works on. In the call, apply & bind lesson, you used three built-in methods that every function has. Each one lets you choose this:

  • call runs the function now. You pass the extra values one by one.
  • apply runs the function now. You pass the extra values in one list.
  • bind does not run the function. It makes a new function that runs it later.

In this lesson, you write your own copies of all three. Seeing how they work inside makes the rules from The this keyword and Losing this easier to remember.

Plain definition

A polyfill is your own JavaScript code that does the same job as a built-in feature. People write polyfills for old browsers that are missing a feature. Here you write three: myCall, myApply, and myBind. Each one is a normal function on its own. None of them change the built-in methods.

Real-life analogyA borrowed phone for one call

You borrow Ada's phone to make a call. You can dial the numbers one by one. You can pick them from a saved list. Or you can set up speed dial now and make the call later. Every time, it is Ada's phone.

In real life: Use Ada's phone and dial each number
In JavaScript: myCall(fn, receiver, ...args)
In real life: Use Ada's phone and pick numbers from a saved list
In JavaScript: myApply(fn, receiver, argsLike)
In real life: Put Ada's phone on speed dial for later
In JavaScript: myBind(fn, receiver, ...preset)

This lesson uses ideas from these lessons:

Two other lessons also build a built-in yourself: Polyfill array methods and Build a promise from scratch.

myCall: call the function from the object

STEP THROUGH

Here is the main trick. When you call a function from an object, like user.label(), JavaScript sets this to that object. The object that becomes this is called the receiver. So myCall does four things:

  1. It puts the function on the receiver for a moment, under a new key.
  2. It calls the function from the receiver: receiver[key](...args).
  3. It deletes the key again.
  4. It returns what the function returned.

The key is a Symbol. A Symbol is a unique value that you can use as a property key. Press Step to follow the code.

Step through myCall
Step 0 of 7Ready
Your turn: follow the blue line

Step through myCall: put the function on the object under a Symbol key, call it from there, delete the key, and return the result.

Running in
  1. script
Next: line 1
  if (typeof fn !== "function") throw new TypeError("Target must be callable");  const receiver = thisArg == null ? globalThis : Object(thisArg);  const key = Symbol("myCall");  try {    Object.defineProperty(receiver, key, { value: fn, configurable: true });    return receiver[key](...args);  } finally {    delete receiver[key];  }} function label(prefix, punctuation) {  return prefix + this.name + punctuation;}const user = { name: "Ada" };console.log(myCall(label, user, "Hi, ", "!"));
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Line by line:

  • Line 3 picks the receiver. thisArg is the value you asked to use as this. If it is null or undefined, the line uses globalThis, the global object. Otherwise Object(thisArg) makes sure it is an object.
  • Line 4 makes a new Symbol key.
  • Line 6 puts the function on the receiver under that key. Object.defineProperty adds one property; configurable: true lets us delete it later.
  • Line 7 calls the function from the receiver, so this is the receiver.
  • Line 9 deletes the key. It is in a finally block, which runs even if the function throws an error.
How myCall works. The label function is added to the user cart, which holds name "Ada". It is called from the cart, so the result is "Hi, Ada!". Then it is deleted from the cart.labelthe function1. addname: "Ada"labeluser3. then delete the key2. call"Hi, Ada!"the result
myCall puts label into the user object under a secret key and calls it from there. Called from user, it gets user as this; then the key is deleted.
Why a Symbol and not a string

A string key like "__fn" could replace a property the object already has. Every Symbol("myCall") is new and different from every other key. So it can't clash with a real property.

A Symbol key doesn't replace a real propertyPop out in the code editor (opens in a new tab)JavaScript
const user = { name: "Asha", __fn: "keep this value" };
const key = Symbol("temporary function");
user[key] = function () { return this.name; };
console.log(user.__fn, user[key]());
console.log(Reflect.ownKeys(user).includes(key));
delete user[key];
console.log(user.__fn, Object.hasOwn(user, key));
  • Line 1 makes a user that already has a __fn property.
  • Line 3 adds a function under a Symbol key.
  • Line 4 prints keep this value Asha. The old __fn value is still there, and the function read this.name.
  • Line 5 prints true. Reflect.ownKeys lists all of an object's own keys, and the Symbol is one of them for now.
  • Line 6 deletes the key. So line 7 prints keep this value false. Object.hasOwn checks if the object has a key, and it doesn't any more.

The trick has one weak spot. It must add a property to the receiver, and some objects don't allow that.

An object that can't get new propertiesPop out in the code editor (opens in a new tab)JavaScript
function myCall(fn, thisArg) {
  const key = Symbol("temporary function");
  thisArg[key] = fn;
  try { return thisArg[key](); }
  finally { delete thisArg[key]; }
}
const user = Object.preventExtensions({ name: "Asha" });
function greet() { return this.name; }
try { console.log(myCall(greet, user)); }
catch (error) { console.log(error.name); }
console.log(greet.call(user));

It prints TypeError, then Asha. On line 7, Object.preventExtensions stops anyone from adding new properties to user. So the helper can't add its Symbol key, and the call fails with a TypeError. The built-in call on line 11 doesn't add anything to the object, so it still works.

thisArg: null, undefined, and plain values

REAL OUTPUT

thisArg is the first value you pass to call: the value you want as this. What the function really gets depends on one thing: is the function in strict mode? A function is in strict mode when it, or the file around it, starts with "use strict". Code without it is often called sloppy mode.

You also need one more word. A primitive is a plain value that is not an object, like a number or a string. Here are the rules:

  • In a sloppy function, null and undefined become globalThis. A primitive such as 5 is wrapped in an object, here a Number object. This wrapping is called boxing.
  • In a strict function, this is exactly what you passed. undefined stays undefined, null stays null, and 5 stays the number 5.
What this is in strict and sloppy functionsPop out in the code editor (opens in a new tab)JavaScript
function sloppyNull() {  return this === globalThis;}function sloppyUndefined() {  return this === globalThis;}function strictUndefined() {  "use strict";  return this === undefined;}function strictNull() {  "use strict";  return this === null;}function sloppyPrimitive() {  return Object.prototype.toString.call(this);}function strictPrimitive() {  "use strict";  return typeof this;} console.log(sloppyNull.call(null));console.log(sloppyUndefined.call(undefined));console.log(strictUndefined.call(undefined));console.log(strictNull.call(null));console.log(sloppyPrimitive.call(5));console.log(strictPrimitive.call(5));

The six lines print, in order:

  • Lines 23 and 24 print true. In sloppy functions, null and undefined both became globalThis.
  • Lines 25 and 26 print true. In strict functions, undefined and null stayed as they were.
  • Line 27 prints [object Number]. The sloppy function got 5 boxed in a Number object.
  • Line 28 prints number. The strict function got the plain number 5.

myCall copies the sloppy rules. Its line 3 uses globalThis for null and undefined, and Object(thisArg) boxes primitives.

But myCall can't copy the strict rule. To set this, it must call the function from an object, and undefined is not an object. So a strict function gets globalThis instead of undefined.

A strict function asked to run with this set to undefined. Left: native fn.call(undefined) gives this = undefined, which is correct. Right: myCall(fn, undefined) gives this = globalThis, which is wrong.fn.call(undefined)undefinedthiskept undefinedmyCall(fn, undefined)globalThisthisgot globalThis
Both ask a strict function to run with this set to undefined. Native call keeps undefined, but myCall must call from an object, so it uses globalThis.

myApply: myCall with a list of values

VALIDATION

apply works like call. The only difference is how you pass the extra values. call takes them one by one. apply takes them in one list, as its second value. That list can be:

  • null or undefined, which means "no values".
  • An array, like ["Ada", "Grace"].
  • An array-like object: an object with a length and numbered keys, like { 0: "Ada", 1: "Grace", length: 2 }.

Anything else, like the number 7, is not a list. Then apply throws a TypeError before the function runs.

myApply checks the list, then uses myCallPop out in the code editor (opens in a new tab)JavaScript
function myCall(fn, thisArg, ...args) {  const receiver = thisArg == null ? globalThis : Object(thisArg);  const key = Symbol("myCall");  try {    Object.defineProperty(receiver, key, { value: fn, configurable: true });    return receiver[key](...args);  } finally {    delete receiver[key];  }}function myApply(fn, thisArg, argsArray) {  if (argsArray == null) return myCall(fn, thisArg);  if (typeof argsArray !== "object" && typeof argsArray !== "function") {    throw new TypeError("CreateListFromArrayLike called on non-object");  }  return myCall(fn, thisArg, ...Array.from(argsArray));}function list(a, b) {  return this.prefix + a + " & " + b;}const args = { 0: "Ada", 1: "Grace", length: 2 };console.log(myApply(list, { prefix: "Team: " }, args));
  • Line 12 handles null and undefined. It calls myCall with no extra values.
  • Lines 13 to 15 throw a TypeError if the list is not an object or a function.
  • Line 16 uses Array.from to turn the array-like object into a real array. The ... (spread) then passes its items to myCall one by one.
  • Line 22 prints Team: Ada & Grace.

Today, when you just need to pass an array's items one by one, spread is easier to read than apply:

Spread often replaces applyPop out in the code editor (opens in a new tab)JavaScript
const scores = [4, 9, 2];console.log(Math.max.apply(null, scores));console.log(Math.max(...scores));

Both lines print 9.

myBind: save this and the first values

PARTIAL APPLICATION

bind does not run the function. It returns a new function, called a wrapper, that runs the original later. When you call the wrapper:

  • It uses the this you gave to bind.
  • It passes the values you gave to bind first, then the values from the call.

Saving the first values ahead of time is called partial application. The currying lesson covers it in more detail.

What the built-in bind doesPop out in the code editor (opens in a new tab)JavaScript
function multiply(a, b, c) {  return a * b * c;}const nativeDouble = multiply.bind(null, 2);console.log(nativeDouble.name);console.log(nativeDouble.length);console.log(nativeDouble(3, 4)); function showName(punctuation) {  return this.name + punctuation;}const first = showName.bind({ name: "Ada" });const rebound = first.bind({ name: "Grace" });console.log(rebound("!"));

Lines 4 to 7 use the built-in bind:

  • Line 4 saves 2 as the first value. null is the this, which multiply doesn't use.
  • Line 5 prints bound multiply. A bound function's name starts with "bound ".
  • Line 6 prints 2. A function's length is how many parameters it lists. multiply has 3, and one is already filled, so 2 are left.
  • Line 7 prints 24, because 2 * 3 * 4 is 24.
nativeDouble(3, 4). The value 2 saved by bind goes first, then 3 and 4 from the call. multiply gets 2, 3, and 4 and returns 24.nativeDouble(3, 4)234from bindfrom the callmultiplya * b * c24result
bind saved 2. Calling nativeDouble(3, 4) puts 2 first, then 3 and 4, so multiply returns 2 * 3 * 4, which is 24.

Lines 12 to 14 bind a function twice. Line 12 binds Ada. Line 13 tries to bind Grace. Line 14 prints Ada!. The first bound this stays. A second bind can add more values, but it can't change this.

This lesson's myBind also tries to set name and length the same way, with Object.defineProperty. Some older JavaScript engines (the programs that run your code) don't allow that. Then the helper skips it, and the wrapper still works.

Be careful with length. It stops counting at the first parameter with a default value, like punctuation = "!", or at a rest parameter, like ...items. So don't use it to check how a function should be called.

Bound length stops at a default valuePop out in the code editor (opens in a new tab)JavaScript
function greet(name, punctuation = "!") {
  return "Hi, " + name + punctuation;
}
const greetAsha = greet.bind(null, "Asha");
console.log(greetAsha.name);
console.log(greetAsha.length);

Line 5 prints bound greet. Line 6 prints 0. greet.length is 1, because counting stops at punctuation, which has a default. Binding name takes away that one, so 0 are left. It never goes below 0.

bind with new

STEP THROUGH

You can also call a bound function with new. new calls a function as a constructor: it makes a fresh object and runs the function with that object as this. When you use new on a bound function:

  • The bound this is not used. The fresh object is this instead.
  • The saved values still come first.
  • The fresh object is still a Point, so point instanceof Point is true. instanceof checks if an object was made from a constructor's prototype.

Simple bind helpers often get this case wrong.

Real-life analogyA form with one blank filled in

You have a paper form called Point with two blanks. Someone has already written 1 in the first blank. Each time you need a point, you take a fresh copy of the form and fill in the second blank. The copy is still a Point form.

In real life: Each copy is still a Point form
In JavaScript: point instanceof Point is true
In real life: The first blank already says 1
In JavaScript: The saved 1 becomes x
In real life: You take a fresh copy of the form
In JavaScript: new makes a fresh object for this
Step through new BoundPoint(2)
Step 0 of 10Ready
Your turn: follow the blue line

Step through myBind with new: new.target tells the helper to use the fresh object as this.

Running in
  1. script
Next: line 1
  function boundFunction(...later) {    const usingNew = new.target !== undefined;    const args = [...preset, ...later];    if (usingNew) {      return Reflect.construct(fn, args, new.target === boundFunction ? fn : new.target);    }    return fn.apply(thisArg, args);  }  return boundFunction;} function Point(x, y) {  this.x = x;  this.y = y;}Point.prototype.label = function () {  return this.x + "," + this.y;}; const BoundPoint = myBind(Point, { x: 99, y: 99 }, 1);const point = new BoundPoint(2);console.log(point.label());console.log(point instanceof Point);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Press Step to follow new BoundPoint(2). Two tools do the work:

  • new.target is set only when a function is called with new. Line 3 uses it to check.
  • Reflect.construct(fn, args, newTarget) runs fn with new and the values in args. Line 6 uses it, so Point runs as a constructor and the bound object is never used.
new BoundPoint(2). Left: the bound object with x 99 and y 99 is not used. Right: new makes a fresh point object, which gets x 1 from bind and y 2 from the call.new BoundPoint(2)x: 99, y: 99thisArgnot used by newx: 1y: 2pointthe new object
With new, the bound object { x: 99, y: 99 } is skipped. A fresh point gets the saved 1 as x and the 2 from the call as y.

Before new.target existed, bind polyfills used a different trick. They made an empty helper function, Empty, and gave it Point's prototype. Then this instanceof Empty told them if new was used:

The older bind polyfill with an empty helperPop out in the code editor (opens in a new tab)JavaScript
function classicBind(fn, thisArg, ...preset) {  function Empty() {}  function bound(...later) {    const receiver = this instanceof Empty ? this : thisArg;    return fn.apply(receiver, preset.concat(later));  }  if (fn.prototype) {    Empty.prototype = fn.prototype;    bound.prototype = new Empty();    // Keep Empty.prototype intact because bound uses instanceof Empty.  }  return bound;} function Point(x, y) {  this.x = x;  this.y = y;}const BoundPoint = classicBind(Point, { x: 99 }, 1);const point = new BoundPoint(2);console.log(point instanceof Point);
  • Line 2 makes the empty helper function.
  • Line 4 checks: was this call made with new? If so, it uses the fresh object. If not, it uses thisArg.
  • Lines 8 and 9 link the prototypes, so an object made by bound also counts as a Point.
  • Line 20 calls it with new, and line 21 prints true.

Two more cases show why Reflect.construct is the better tool:

A class, and a constructor that returns an objectPop out in the code editor (opens in a new tab)JavaScript
class Member {
  constructor(name) { this.name = name; }
}
function myBind(fn, thisArg, ...preset) {
  function boundFunction(...later) {
    const args = [...preset, ...later];
    if (new.target) {
      return Reflect.construct(fn, args, new.target === boundFunction ? fn : new.target);
    }
    return fn.apply(thisArg, args);
  }
  return boundFunction;
}
const BoundMember = myBind(Member, { name: "ignored" }, "Asha");
const member = new BoundMember();
console.log(member.name, member instanceof Member);

function Profile(name) {
  this.name = name;
  return { name: "Returned" };
}
const BoundProfile = myBind(Profile, null, "Asha");
const profile = new BoundProfile();
console.log(profile.name, profile instanceof Profile);
  • Line 16 prints Asha true. Member is a class, and a class only runs with new. Reflect.construct runs it with new, skips the bound object, and makes a real Member.
  • Line 24 prints Returned false. Profile returns its own object on line 20. With new, a returned object takes the place of the fresh one. So profile is that returned object, not a Profile.

Calling a constructor with apply can't do either of these.

Built-in vs polyfill: what matches

COMPARE

People call the built-in methods native. A polyfill is only useful if you know where it matches the native method and where it doesn't. The table lists each case. The lab below it runs both and shows the real values. The biggest difference is the strict undefined case from earlier.

Read each row as: in this case, does the helper give the same result as the native method, and why?

Does each helper match the native method?
CaseDoes it match?Why
call with an object as thisYes.Calling from the object gives the same this.
null or undefined in a sloppy functionYes.Both use globalThis instead.
null or undefined in a strict functionNo.The built-in passes the exact value. The Symbol trick must call from an object, so it can't.
A primitive, like 5, as thisYes, for sloppy functions.Both box it in an object; the helper uses Object(thisArg). A strict function gets a box from the helper, not the plain value.
apply with a null listYes.Both run the function with no extra values.
apply with a number as the listYes, same error.Both throw a TypeError; the helper checks before Array.from.
bind with saved valuesYes.Saved values go first, then the values from the call.
Binding twiceYes.The first bound this stays; a second bind can only add values.
new with a bound constructorYes, in this helper.Reflect.construct skips the bound object, keeps the prototype, and works with classes.
A constructor that returns an objectYes, in this helper.Like the built-in new, the returned object takes the place of the fresh one.
name and lengthUsually.The built-in sets them; the helper tries with Object.defineProperty, where the engine allows it.
A class with callYes, both fail.A class only runs with new, so both throw.
Compare the built-in methods with the helpers
Cases you can pickPop out in the code editor (opens in a new tab)JavaScript
// All helpers are standalone; no built-in prototype is patched.const cases = [  "normal object receiver",  "strict undefined receiver",  "primitive receiver",  "array-like apply arguments",  "partial bind",  "bind with new",  "name and length",  "class constructor call",];for (const label of cases) {  console.log(label);}
call: an object as thissame
Built-in
Hello, Ada
Helper
Hello, Ada
Verdict
same result
Try it yourself

Calling the function from the object gives the same this as the built-in call.

Both results come from real JavaScript: the built-in method and this lesson's helper. When they differ, the panel says so.
Arrow functions and classes

An arrow function has no this of its own. It uses the this from the code around it. So call, apply, and bind can't change it. A class is the other way around: it only runs with new. Calling a class with call throws a TypeError.

An arrow function and a classPop out in the code editor (opens in a new tab)JavaScript
const arrow = (function makeArrow() {  return () => this.name;}).call({ name: "Ada" });console.log(arrow.call({ name: "Grace" })); class Widget {}try {  Widget.call({});} catch (error) {  console.log(error.name);  console.log(error.message);}
  • Line 4 prints Ada, not Grace. The arrow made on line 2 keeps the this from line 3.
  • Lines 10 and 11 print TypeError and its message, which says the class can't run without new.

Where you’ll use this

SORT IT

You may never ship these helpers. But the same ideas show up in everyday code:

  • Event handlers use bind, or a wrapper function, to keep their object as this.
  • Libraries borrow array methods, like join, and use them on array-like objects.
  • Helper code uses bind to save a value that repeats, like a log prefix, a tax rate, or a language setting.
Which helper does each task need?
  • Use Array.prototype.join on an array-like object right now
  • Run a function with values already stored in { 0: "Ada", length: 1 }
  • Make a function that keeps view as this for a click that happens later
  • Save 0.08 as the first value of priceWithTax(rate, price)
  • Read older code that does Math.max.apply(null, numbers)
  • Support new BoundPoint(2) after saving 1 for x
Try it yourself
0 of 6 correct

Sort each task by the helper it needs.

Choose a category for every card. You can change an answer at any time; Reset clears them all.
Keep a method's object for a later callPop out in the code editor (opens in a new tab)JavaScript
const user = {
  name: "Asha",
  greeting() { return "Hello, " + this.name; },
};
const showGreeting = user.greeting.bind(user);
console.log(showGreeting());

It prints Hello, Asha. Suppose you passed user.greeting on its own to other code. When that code calls it later, it has lost user. Line 5 uses bind to make a function that keeps user as this.

In real apps, use the built-in call, apply, and bind. They handle strict functions, constructors, and the other cases correctly. The helpers in this lesson are for learning. If a very old browser needs a polyfill, use a well-tested polyfill library, not these snippets.

Modern JavaScript often has a clearer way to do the same job:

  • Write Math.max(...numbers) instead of Math.max.apply(null, numbers).
  • A small arrow wrapper, like () => user.greeting(), is often easier to read than bind.
  • Use Object.hasOwn(obj, key) instead of borrowing hasOwnProperty with call, when the browsers you support have it.

Common misconceptions

  • “The Symbol trick is how JavaScript really does it.” No. It shows the idea of calling from an object. The built-in method works inside the engine and adds no property.
  • “Strict and sloppy functions get the same this.” No. Strict functions get exactly what you passed. Sloppy functions swap null and undefined for globalThis, and box primitives.
  • “apply takes any list-like value.” No. Native apply wants an array or an array-like object: something with a length and numbered keys. This lesson's helper checks the value first, then uses Array.from.
  • “bind only sets this.” No. It also saves the first values, and you can use the bound function with new.
  • “Binding twice changes this again.” No. The first bound this stays.
  • “A bound constructor writes into the bound object.” No. new makes a fresh object and skips the bound one.
  • “A Symbol key makes the helper complete.” No. The Symbol stops key clashes. But the helper still fails on objects that can't get new properties, and it can't give a strict function undefined as this.
  • “A function's length shows all its parameters.” No. It stops counting at the first default value or rest parameter.
  • “A class is just a function you can call.” No. A class throws a TypeError unless you use new.

Read each row across: when the tool runs, what you pass it, and how this lesson builds it.

Similar tools that are easy to mix up
ToolWhen does it run?What do you pass?How does this lesson build it?
callIt runs the function right away.First the this value, then the other values one by one.myCall puts the function on the object under a Symbol key and calls it from there.
applyIt runs the function right away.First the this value, then one list: null, undefined, an array, or an array-like object.myApply checks the list, turns it into an array, and uses myCall.
bindIt doesn't run it. It returns a new function for later.First the this value to keep, then the values to put first.myBind returns a wrapper, tries to set name and length, and handles new.
Arrow functionsIt runs when you call it, like any function.call, apply, and bind can pass it values, but can't change its this.There is nothing to build, because its this can't be changed.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upWrite the core myCall trick

Fill in the helper so the last line prints Hi, Ada!.

Starter codePop out in the code editor (opens in a new tab)JavaScript
function myCall(fn, thisArg, ...args) {
  // 1. Pick the receiver: globalThis for null or undefined, otherwise Object(thisArg).
  // 2. Put fn on it under a Symbol key, call receiver[key](...args), then delete the key.
}
function greet(punctuation) {
  return "Hi, " + this.name + punctuation;
}
console.log(myCall(greet, { name: "Ada" }, "!"));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeFix apply when the list is null

    The starter calls Array.from(null), which throws. Fix it so apply works with no list.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    function brokenApply(fn, thisArg, argsArray) {
      return fn.call(thisArg, ...Array.from(argsArray));
    }
    function who() { return this.name; }
    try {
      console.log(brokenApply(who, { name: "Ada" }, null));
    } catch (error) {
      console.log(error.name);
    }

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeCheck the list in apply

      Add the check so myApply(noop, null, 7) throws, and the program prints the error's name.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      function myApply(fn, thisArg, argsArray) {
        if (argsArray == null) return myCall(fn, thisArg);
        // Add the check the built-in apply makes: throw a TypeError if the list is not an object.
      }
      function noop() { return "ok"; }
      try {
        myApply(noop, null, 7);
      } catch (error) {
        console.log(error.name);
      }

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeSave the first value with bind

        Finish the wrapper in myBind so double(6) uses the saved 2 and prints 12.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        function myBind(fn, thisArg, ...preset) {
          return function boundFunction(...later) {
            // Call fn with thisArg. Pass the preset values first, then the later ones.
          };
        }
        function multiply(a, b) { return a * b; }
        const double = myBind(multiply, null, 2);
        console.log(double(6));

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeMake myBind support new

          Finish the new case so new BoundPoint(2) prints 1,2 true.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function myBind(fn, thisArg, ...preset) {
            function boundFunction(...later) {
              const receiver = new.target ? this : thisArg;
              return fn.apply(receiver, preset.concat(later));
            }
            // Link boundFunction.prototype to fn.prototype here.
            return boundFunction;
          }
          function Point(x, y) { this.x = x; this.y = y; }
          Point.prototype.label = function () { return this.x + "," + this.y; };
          const BoundPoint = myBind(Point, { x: 99 }, 1);
          const point = new BoundPoint(2);
          try {
            console.log(point.label(), point instanceof Point);
          } catch (error) {
            console.log(error.name);
          }

          Answer, then press Check. Spacing and letter case don’t matter.

            Check your understanding

            8 QUESTIONS
            Polyfill call/apply/bind quiz · 8 questionsScore: first tries count
            1. Question 1 of 8Why does myCall put the function on the object under a Symbol key before calling it?

              Choose an answer to see the explanation.

            2. Question 2 of 8What do these strict and sloppy checks print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function sloppy() { return this === globalThis; }
              function strict() { "use strict"; return this === undefined; }
              console.log(sloppy.call(null));
              console.log(strict.call(undefined));

              Choose an answer to see the explanation.

            3. Question 3 of 8What does the built-in apply print when the list is a number?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function add(a, b) { return a + b; }
              try {
                console.log(add.apply(null, 7));
              } catch (error) {
                console.log(error.name);
              }

              Choose an answer to see the explanation.

            4. Question 4 of 8What does the bound multiplier print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function multiply(a, b) { return a * b; }
              const double = multiply.bind(null, 2);
              console.log(double(6));

              Choose an answer to see the explanation.

            5. Question 5 of 8What does binding the same function twice print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function show() { return this.name; }
              const once = show.bind({ name: "Ada" });
              const twice = once.bind({ name: "Grace" });
              console.log(twice());

              Choose an answer to see the explanation.

            6. Question 6 of 8What does this bound constructor code print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function Point(x, y) { this.x = x; this.y = y; }
              Point.prototype.label = function () { return this.x + "," + this.y; };
              const BoundPoint = Point.bind({ x: 99, y: 99 }, 1);
              const point = new BoundPoint(2);
              console.log(point.label());
              console.log(point instanceof Point);

              Choose an answer to see the explanation.

            7. Question 7 of 8What does calling a class with call print here?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              class Widget {}
              try {
                Widget.call({});
              } catch (error) {
                console.log(error.name);
                console.log(error.message.includes("cannot be invoked without 'new'"));
              }

              Choose an answer to see the explanation.

            8. Question 8 of 8What name and length does the built-in bind give here?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function multiply(a, b, c) { return a * b * c; }
              const bound = multiply.bind(null, 2);
              console.log(bound.name);
              console.log(bound.length);

              Choose an answer to see the explanation.

            Key takeaways

            • myCall puts the function on the object under a new Symbol key, calls it from there, then deletes the key.
            • myApply is myCall plus two steps: check the list, then turn it into an array with Array.from.
            • The Symbol trick can't give a strict function undefined as this. That is where it differs most from the built-in.
            • myBind returns a wrapper. The wrapper sets this, puts the saved values first, and uses new.target to handle new.
            • name, length, arrow functions, classes, and constructors that return objects are the cases that make a full polyfill hard.

            Remember the one-liner.
            call and apply call the function from the object now; bind makes a wrapper that does it later.

            Coming next: Build a promise from scratch.

            CompleteFrontend Clear concepts. Working examples.