Understand JavaScript more deeply by writing a bind function

adamisom
40 min readJun 18, 2020

--

If you can do this, you know how JavaScript works. If you don’t, your foundations may be weak. Being a JavaScript developer with weak foundations is like continually traversing shaky ground — risky.

sourced from Unsplash (credit: Zach Lezniewicz)

My goal is to help you understand JavaScript more deeply.

The bind function is a great vehicle for exploring all of these important concepts and topics:

  1. the this keyword
  2. ‘losing’ context
  3. execution context vs. this
  4. variables as ‘pointers’/references
  5. methods vs. functions
  6. arrow functions and this
  7. .bind vs. .call vs. .apply
  8. prototypal ‘inheritance’
  9. everything is an object (almost)
  10. the difference between .__proto__ and .prototype
  11. first-class functions
  12. higher-order functions
  13. partial function application (sometimes incorrectly called currying)
  14. property descriptors
  15. using defineProperty to change a non-writable property like .name, and why you might want to
  16. the MDN Web Docs
  17. the ECMAScript specification
  18. the V8 engine source code

This article will build a bind function in four phases/versions, and along the way I’ll discuss every one of the 18 topics listed above.

Is this for you? This article is targeted to those who already know some JavaScript. To get the most out of it, you should already be comfortable writing small scripts. You should also be familiar with closures and the new keyword, and have some idea of how the this keyword and prototypes work. If you don’t have this level of familiarity yet, check out Launch School.

I hope you’re excited! You may be intrigued yet still not be familiar with the built-in .bind function or why you might use it. If so, the next section is for you. If you’re already familiar with .bind, please skip to Version 1.

Table of Contents:

What is the bind function and when should I use it? + How ‘this' works and function concepts you must know

The built-in .bind lets you bind a function to a particular execution context. It’s usually used to fix ‘lost’ context or just to otherwise explicitly say what the context should be. An example will contextualize the rest of the discussion:

Here, the ‘context’ is the object bob, which I’ll pretend is a person named ‘Bob’. The complimentBob function is supposed to run ‘in the context of Bob’, just as a complimentSue function might run ‘in the context of Sue’. In other words, a function’s context = who’s doing it.

Honestly, if this is your first time diving into execution contexts and the this keyword, this article will probably go over your head. I’m just providing a refresher.

Back to Bob. As it is, poor Bob can no longer assure himself that cargo shorts look great.

To fix this, we can make sure that complimentBob doesn’t forget that it came from Bob. After the change, Bob can assure himself that cargo shorts are stylish. Go Bob!

Okay, at this point, you should skip ahead to the subsection “Let’s read the documentation!” if you already feel you have a good grasp on these topics:

  • methods versus functions
  • execution context and the this keyword
  • when you might lose context (and a better way to think about context loss)
  • how arrow functions affect this
  • the differences between .bind , .call and .apply

However, if you feel any confusion about what just happened in the code above, keep reading.

What just happened? (1/3) — Methods versus Functions

If you look at either of the last two code snippets, you’ll notice that complimentBob is a variable whereas complimentSelf is a property (of bob). If you were to call bob.complimentSelf(), that would be invoking a method, but when I invoked complimentBob(), I was invoking a function. This is key to why I had to use bind. I’ll explain exactly how, but before I do, I’m going to zoom in on what a ‘method’ is versus a ‘function’.

First-class Functions, explained: In JavaScript, ‘methods’ aren’t as different from ‘functions’ as they are in most languages. Functions are ‘first class’, which just means they can be treated as any other value.

You may be wondering: What do you mean ‘like any other value?’

Well, in JavaScript, you can store functions in arrays, or as a property in an object. You can return functions from functions, and you can pass functions as arguments.

If you’re not sure what to make of that, just substitute “number” or “string” in most of the places I wrote “function” in the above paragraph. It’s not weird to store numbers in an array, or to pass a string as an argument, right? Since functions are treated as any other value, you can also store functions in an array, or pass functions as arguments, and so on.

Side Note on ‘storing’ functions: I spoke imprecisely when I said you can “store” functions in arrays and objects. You don’t do that exactly — instead you store a reference to a function. I like to imagine that I’m actually storing a long arrow, and that I can get to the function if I follow that arrow. Throughout this article, I’ll try to maintain this distinction. I usually use the terminology ‘points to’ to indicate I’m talking about a reference to a function, like this:

In var foo = function(){}, foo points to a function.

Higher-order Functions, explained: A higher-order function is simply a function that takes another function as an argument, or that returns a function. Or both, as seen below:

Methods are just properties whose values point to functions. That’s it! I want to be even more precise than that, but I don’t want to muddy the waters, so let me back up slightly and then come back to methods vs. functions.

Consider the statement var x = 3. I’m going to describe the 3 as a ‘number value’. Okay, now in the statement var x = function(){}, I’m going to describe the function(){} as a ‘function value’. Got it? This leads me to my next point: in a way, methods and functions are exactly the same thing.

A property consists of a key plus a value. A method is just a property, where the value of that property is a function value. Functions are much the same. Except for anonymous IIFEs (which can’t be called again!), functions are named, either implicitly or explicitly:

  • implicitly: function someName() {} — this effectively creates a someName variable
  • explicitly: var someName = function(){}

Either way, a “function” is really a name/label plus a function value. That name/label can either be a variable or a property key; it doesn’t really matter.

I have an exercise that will take you under a minute that should convince you there’s no fundamental difference between methods and functions. (If you’re not familiar with your browser’s developer tools yet, you should become familiar ASAP.) Open up your browser’s developer tools and define a function in the console: function f(){}. Now type and evaluate window.f. Did you see that? Your function was implicitly made a property of the global window object.

Okay, there is a difference between a function and method because there is a difference between a variable and a property. You can’t delete (declared) variables like you can delete (other) properties. It’s just how things are. Other than this, think of variables/properties and functions/methods as the same.

Side note on ‘named function expressions’, for the extra curious:

  • You can have a method whose value is a named function. You can also initialize a variable to a named function. In both cases, this double-naming is achieved by using a ‘named function expression’ as the value.
  • It’s not a big deal, and does not contradict the mental model I supplied earlier (of a name/label + function value). It’s not a big deal because outside of the function body itself, the function value is only callable using the first name. That is, even though the identifier bar in var foo = function bar(){} refers to the same function that foo refers to, you can only do bar() within the body of the function itself.
  • There’s nothing weird about calling bar within bar, unless you’re new to recursion — if you are new to it, just know recursion is an unrelated thing.
  • Examples of named function expressions:

What just happened? (2/3) — Execution Context and “this” Explained

First of all, you need to know that functions always execute in an ‘execution context’. There’s no such thing as a function executing without a context.

Execution context, this, and their difference. Let’s say your birthday is coming up soon, and someone in your life likes sending you an e-card every year. Let’s call this person ‘mom’.

Imagine that you have some code and a method or function represents the sending of an e-card. In this scenario, sending the birthday card is done in the context of your mom being the one sending it.

If it were your dog sending you an e-card, the choice of card and message would likely be quite different. (What, your dog doesn’t send you cards? Time to get a new dog!)

Think about execution context as the everyday sense of ‘environment in which something happens’. You might be surprised, since I try to be precise, but I think that this informal definition is the best way to think about it.

Usually, when we talk about the ‘execution context’, we’re talking about who’s doing it. However, the execution context is really the whole ‘environment’ your code runs in.

In the scenario of your mom sending you an e-card, the whole ‘environment’ or ‘context’ includes what website she uses to send it to you. But usually, to stretch the programming analogy, we only care about the fact that it’s your mom sending it to you.

The this keyword isn’t precisely the same as the execution context. The execution context, or ‘environment’, includes everything in scope during a function invocation — everything it has access to — for example, the function’s arguments, as well as the function’s closure that was created for the function when it was defined.

The this keyword is a reference to the who’s doing it part of the execution context. So, this could be mom, or dog.

You may have been wondering: What kind of ‘thing’ is this in code? It’s great to know this is “who’s doing it”, but that’s not exactly a data type, is it?

Well, that’s a good point. The answer: this always points to an object.

How this gets resolved for a function invocation. You should read this comprehensive guide by Dmitri Pavlutin. My list below for determining what this is ignores arrow functions as well as constructor invocations (which is what happens when you use the new keyword).

  1. If a function was invoked with a dot to the left of it, then this is the object to the left of the dot. Example: in obj.func(), this is obj.
  2. If a function was hard-bound with some context, that’s what this will be. The .bind method does this.
  3. If a function is called with an explicit context, via .call or .apply (which are discussed soon), then that’s what this will be.
  4. Otherwise, the default this is used.

What’s the default this?

  • Are you using ‘strict mode’? Then this = undefined, regardless of whether you’re running code in the browser or with NodeJS.
  • Is the JavaScript running in a browser? Then this = the global window object.
  • Is the JavaScript running in NodeJS? Then this = the module-scoped objectmodule.exports

It’s important to realize that a default this value will be used if there’s no reason that it should be different (refer back to scenarios 1–3). If you run into trouble with the this keyword, there’s a good chance that your trouble is because you assumed this would have a non-default value, but none of the non-default criteria were met, so you’ve got a case of “defaultthis value”.

Let’s look at an example. This example has a method calling another method:

You can see that method2 was called with a dot to the left of it. This means scenario 1 applies: it will execute each of the statements in its body with this set to object. What about inside method2? When the statement this.method1() is executed, the same rule applies. When that statement is reached, this points to object, so in effect, object.method1() is executed. Finally, what about inside method1? Again, the same rule applies: console.log(this.number) is effectively console.log(object.number).

What just happened? (3/3)— So, what happens when you extract a method from an object and then call it later?

Take a look back at the lost-context.js snippet from the very beginning of this section. Notice that the bob object has a property complimentSelf. Programmers and programming articles often discuss properties in terms of their keys, but more precisely the bob object has a property whose key is the string 'complimentSelf' and whose value is an anonymous function.

You may be wondering: What do you mean by an ‘anonymous’ function?

Well, a function is ‘anonymous’ if it has no name. That is, if it was defined as function() instead of function someName(). That is all.

When the complimentBob variable on line 8 in the lost-context.js snippet was set equal to the property bob.complimentSelf, you can imagine that the function was sliced out of the bob object. Sometimes I imagine it like that and I think it helps me. In other words, I look at the complimentSelf property and imagine ripping out just the value — just the part right after the complimentSelf: . The reason I imagine it like this is just to remember that the function value complimentBob points to has nothing to do with the key 'complimentSelf' (a string).

The important thing to realize here is that the variablecomplimentBob does not reference the method complimentSelf; instead, they both reference a third thing — the same anonymous function.

The variable complimentBob has no idea that the function it references came into existence by being assigned as the value for the key (complimentSelf) of some object (bob). All it knows is it points to some anonymous function.

When that anonymous function is called, it’s going to execute the body of the function value, which includes the expression this.clothingChoice. But when it figures out what this is, this is not going to be bob. If you run the lost-context snippet in the Chrome Dev Tools console,this will be window.

The solution? When you make a new variable that points to the function that complimentSelf points to, tell that variable to remember that this = bob.

That’s what .bind lets us do.

At this point, you should have a much better understanding of the two code snippets I started this section with. If you started with a vague, head-noddy kind of understanding, then I hope you deeply understand it now.

Next, I’m going to talk more broadly about context (or this): in what situations can it get lost? And what other options are there besides bind? I’m discussing these because, as I said in the introduction, my real goal in this article is to help you understand JavaScript more deeply, not to help you write a .bind function. (After all, JavaScript already has one you can use.)

When can context get “lost”? A few situations

The example I started this whole section with (remember Bob’s cargo shorts?) showed the main use case: use it when methods are extracted from their object, and you want those methods to remember the object they came from.

In general, any time a function gets called but doesn’t meet one of the first three criteria I covered in the subsection ‘How this gets resolved’ will have the default this value— window if the code is running in a browser.

For example, any function used as a callback will, by default, have the default this value.

You may be wondering: What’s a ‘callback’?

Well, it’s just a weird term for a function used as an argument to another function. For example, the built-in forEach function takes a callback argument, and then calls it (the callback) for each item in an array.

Nested functions are a third and final common situation to watch out for. Even if a function is invoked in a particular context, that context is not ‘inherited’ by inner functions. Maybe it should work that way, but it doesn’t.

Nested functions and this can be confusing, so I’ll break it down. Earlier, I said that when a function executes, each of the statements in its body will use the this value set when it was invoked. And that’s true. But keep in mind that a statement that defines a function is not the same as a statement that invokes a function. When the interpreter comes across some code that defines a function, it just creates a function object, allocates memory, etc. But it doesn’t execute any of the statements in the function body. Furthermore, keep in mind that this isn’t set when a function is defined, only when it’s invoked. So, when an inner function is defined, this is not set. It is only set when the inner function is invoked. Just remember these two things: defining is not invoking, and this is only set when invoking.

The lost-context snippet below shows ‘lost’ context for both the ‘callback’ situation and the ‘nested-function’ situation:

If you run the code above, what do you see logged? And, if asked, could you explain why?

Arrow functions and ‘this’ + using them to fix ‘lost’ context

Arrow functions have different behavior with regard to how this is set. this will not get set during execution — it will actually get set when the function is defined. That’s very different!

Personally, I think arrow functions’ this is different enough from regular functions to not include it in the earlier list of scenarios — there’s regular functions, and then there’s arrow functions.

We can modify the last code snippet to use arrow functions so that the desired this value gets used, both for the callback situation and the nested situation:

Don’t try using arrow functions everywhere, though. Do you see the problem with the following ? If not, try running it, and then review the second-to-last paragraph and ask yourself where the arrow function is ‘defined’.

Also, arrow functions aren’t a great general solution to callbacks. Why not? Well, arrow functions only work if you can define the function right there, likeI did for logMessageToFolk. But that’s not super flexible: what if we wanted to be able to accept a callback (a function) from somewhere else? That’s pretty common. Here’s an example of getting a callback from ‘somewhere else’:

Arrow functions are better suited for the ‘nested’ situation. (Why doesn’t my point about the callback situation apply here? Because if you’re choosing to write one function definition inside another one, then implicitly you aren’t seeking ‘flexibility’ in the way those two functions interact.)

You may be wondering: Do arrow function have anything to do with .bind?

Well, in a way they do. You cannot use .bind on arrow functions. Arrow functions do not have a this of their own — they are inextricable from the ‘context’ in which they were defined.

Side Note: .forEach takes an optional thisArg. Many other Array methods also take an optional thisArg (most that take a callback also allow you to pass a thisArg). This effectively gives you a free .bind call, and can be regarded as a ‘hard-bind’ scenario, which is #2 from the subsection ‘How this gets resolved’. So, a better solution for the warnTheFam function is:

call vs. apply vs. bind + using call and apply to fix ‘lost’ context

Like .bind, .call and .apply can bind an execution context to a function. Here are some basic examples:

You may be wondering: What are the differences between .call, .apply, and.bind?

Well, if you call a function with .call or .apply, it’s immediately invoked with the context you provided to call or apply. But .bind does not immediately invoke the function — instead, .bind creates and returns a new function.

The difference between .call and .apply is minor and unimportant, but just so you know: .call expects to receive each argument individually, just like normal function calls do, but .apply expects to receive an array of arguments as the second argument.

So if you want to execute a function right away in some other context, then use .call or .apply. If you want to save it for later, use .bind.

One advantage to using .bind is that if you save the bound function to a variable, you can call the bound version as many times as you want later. With .call and .apply, you have to keep re-binding every time.

Another advantage to using .bind is that sometimes you can’t use .call or .apply to set the context, because the context object is out of scope by the time you call the function you want to bind.

You may be wondering: When would this scenario occur?

Well, think about built-in functions like forEach and map which take callbacks. When the callback executes, it’s in a different scope than the scope where you pass it in. And the scope where you pass it in is when you have the opportunity to bind it to a context. (Even if the context you wanted to bind was in scope in the function body of forEach or map, you don’t have access to those function bodies. The internals of how forEach and map work are hidden to you.) .bind would be a good tool for callbacks. In fact, because the need to bind callbacks to built-in functions that take callbacks is so common, most of those methods take an optional thisArg.

The following example illustrates binding in one context and calling the bound function in another. Go ahead and see what happens if you remove the .binds:

In conclusion, when should you use “bind”?

You may want to use it whenever you want to preserve or explicitly set the execution context, but you don’t want to execute the function right away.

Side Note: You might wonder why JavaScript doesn’t auto-bind methods. I believe it’s because part of what makes functions powerful is that they’re flexible — that you can call them in different contexts if you want to. Because functions were designed to play center of stage in JavaScript, the default behavior for them should be to be flexible, not to hard-bind.

Pop Quiz!

  1. Can context get ‘lost’?
  2. What does line 6 of the following code log, and why? (This is tricky.)
  3. What do lines 7, 8, and 9 log?
  4. What does line 10 of the following code log, and why?
  5. Bonus: Is scope the same as execution context? (Note: I do not cover scope in this article, but I really wanted to include the difference between the two in this article. The answer gives you bonus knowledge.)

Answers:

  1. It depends on how you think about it. If you think about this as just rules you need to know, then context is never ‘lost’. Hypothetically, if you know the rules well, then whenever you write code that could later lead to a ‘lost context’ bug, you won’t, because you’ll instantly know what to do in your particular situation to make this what you want it to be.
  2. Line 6 logs undefined. Do you know why? (Answer: because in the context of that function call, this was window; and if you try accessing properties you didn’t define, you get undefined. So the function tried accessing window.b and got undefined).
  3. Lines 7, 8, and 9 all log 2.
  4. Line 10 logs a representation of a function, something like f func()... Do you know why? (Answer: because .bind doesn’t immediately invoke the function to the left of the dot.)
  5. They’re not the same. Scope is determined based on where a function was defined in the source code (often called ‘lexical scoping’). So, scope is determined long before a function is executed. So, no matter how many times a function is called, all of the calls share the same scope. But execution context is only fully determined when the function gets — wait for it — executed. In particular, the value of this is set when the function is invoked. (Invoked, called, executed — they all mean the same thing here.) So, scope is the same between calls of the same function, but this differs.

I’ve covered a lot of ground in this section and we’re almost ready to code the first version of bind — there’s just one thing left.

Let’s read the documentation!

The MDN Web Docs are excellent, so let’s see what they have to say about bind:

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

In order of decreasing importance:

  1. this gets set
  2. a new function is returned
  3. all passed-in arguments are preserved (I’ll explain this later)

Notice what #2 means: when you call a bound function, it’s a different function than the original one.

Do you see how the following code illustrates the first 2 points above?

Version 1: a basic bind function

Understanding the Problem

What does our bind need to do? Stop and think for a moment.

Okay, here’s my framing of it: Let’s say we have a function named func that we want to bind to some particular object context. Let’s call the result of binding the function boundFunc. Writing it out like this, we see that func and context should likely be arguments to bind, which should return boundFunc.

Let’s look at each of those arguments in turn, starting with how to deal with func.

A First Stab at the Solution

Your first thought might be that boundFunc should simply invoke func. In the below snippet, I’m glossing over the fact that we don’t know how to deal with context yet. I’m assuming we will solve it later, which gives us the freedom to consider just the func aspect.

The approach above is not going to work. Why not? I’ll show you in the snippet below, which illustrates how we might use our bind function above. But I recommend you pause after lines 14–16 to see if you can detect the problem yourself. Hint: a bound version of a function should be able to take and use arguments, just like the original one. That’s why I wrote “arguments” in my snippet above this paragraph.

So that’s not going to work — what we actually want is a new function that when invoked calls func.

A Better Approach

This is what we actually want, if we again temporarily pretend the context problem is solved:

Now the example code from earlier will work as intended: boundFunc is now a function. Like all functions (except arrow functions), it can receive arguments which are accessible to the inside of the function via the special arguments object. By the way — did you notice that the bind function is an example of a higher-order function?

Okay, so the func part is solved. How on earth can we execute a function in another context?

Well, we can’t, in one sense. JavaScript does not give programmers the flexibility we want to ‘build a bind function from scratch’ the way we might want to. There are simply some things you can do within the confines of the language and some things you cannot do. As a user of the JavaScript language, we have to use one of the built-in methods .bind, .call, or .apply to do it.

So that’s what we’ll do. If you find this unsatisfying, rest assured that I come back to this point at the end of the article, where I investigate why this might be by looking at JavaScript’s specification as well as some ‘behind the scenes’ code.

Version 1 Solution

Note how the function above makes use of .apply. As a reminder, what .apply does is immediately call the function to the left of the dot (func in this case), and it calls it in whatever context was passed in as the first argument. Then the rest of the arguments are applied normally. .apply is a better fit than .call here simply because arguments is an array-like object (but it wouldn’t be hard to use .call instead— look up the spread operator if you’re not familiar with it yet).

Here’s an example using the Version 1bind:

Yay!

But notice what’s different about our bind from the built-in .bind that was explored near the beginning:

Let’s build a .bind that can be called on functions, instead of requiring the function be passed in.

Version 2: a bind function you can call on other functions + Crash course in prototypes and OO JS concepts you must know

Isn’t it weird that you can even do func.bind at all? That’s how the built-in bind function is supposed to be used, after all — the name of your function, then a dot, then the word bind.

If that’s not weird to you, you either have a good grasp on JavaScript’s prototypal and object-oriented nature, or you think you do, or you didn’t realize there was something weird going on.

You: Okay, I’ll bite — why should it be weird?

Me: Because we never defined a “bind” property on our function.

Also Me: Also, can functions even have properties?!

Buckle up — it’s time for a crash course in object-oriented JavaScript.

If you’re sure you already know the following facts, please skip ahead to the Version 2 solution:

  • an object can delegate behavior to its prototype object, also called ‘prototypal inheritance’
  • this ‘prototypal inheritance’ uses a ‘prototype chain’
  • almost everything is an object, including functions
  • every object has a .__proto__ property
  • every function has a .prototype property
  • every object has a constructor function
  • an object’s constructor function is not quite the same as that same object’s prototype object, though they are related

If you’re understanding of any of those is fuzzy, I hope I can help de-fuzzify them. Although to be honest, and I know this probably sounds repetitive, but if you’re not already familiar with some of these topics, my little crash course may not be enough.

Functions are objects too

Yep. That means functions can have arbitrary properties. In fact, this code works, although it doesn’t make sense:

But the fact that functions can have properties is one piece of the puzzle (the puzzle is how every function has access to .bind).

Almost everything in JavaScript is — if just temporarily — an object

Primitive values like 42 or 'hello world' are just values. However, behind the scenes, when you want to do something like convert a string to uppercase, JavaScript creates a String object which has the same value as the string primitive. You can imagine JavaScript takes your primitive 'hello world' and creates the object { value: 'hello world' } ). A String object is more complex than a primitive string — in particular, a String object has access to methods, like toUpperCase(). If you want to see what a String object looks like, you can make one with new String() and see what properties it has.

This fact isn’t terribly relevant for our purposes, but it is definitely eye-opening to realize that ‘everything is an object’ if you didn’t already know.

Objects have constructors, which are functions

All new objects get created by a function, whether you know it or not. (Objects, not primitives.) When you create an array literal with [] or an object literal with {}, then behind the scenes, the built-in Array and Object functions were called (respectively). Let’s hone in on arrays for a moment.

The “constructor function” of your new [] array is Array, which is a function that returns a new array object.

As you can see, your new array [] actually has a .constructor property. That’s just JavaScript being nice to you by giving you an easy, predictable property name to look up what the “constructor function” was for an object. Just don’t confuse the two. The .constructor property isn’t really that important in the grand scheme of things, but the fact that objects have a constructor function is.

Constructor functions are just ordinary functions that are intended to be called with the ‘new’ keyword

Here’s an example of a ‘constructor’ function:

The following should stick out:

  • I invoked it with the new keyword.
  • The return value was an object, since line 7 console-logged an object.
  • The body of the Person function added properties to this.
  • The function name was capitalized (this is a convention, nothing more).

I’m not going to fully cover how this interacts with the new keyword in this article. I will mention a few things about calling functions with/without new.

First, I’ll note that you could call any function with the ‘new’ keyword — it’s just unlikely to be useful.

Conversely, you can neglect to use the new keyword when you invoke a function that was supposed to be used as a constructor function. (Again, a ‘constructor’ function is just a function intended to be called with new.) That’s a bad idea.

You may be wondering: what happens if I use a constructor function without new?

Well, I’ll show you what gets returned by calling Person if you forget new:

As you can see, properties were assigned to the global object window. Oops.

Those constructor functions have a .prototype property which is an object

The Array function has a .prototype property, which is an object. Below, I show all of the “own” keys that exist on Array.prototype:

Furthermore, the .push method on arrays happens to live there: so the method’s full name is Array.prototype.push.

Notice that a new array like [] doesn’t have its own .push method. Instead, it borrows the method that lives on Array.prototype. (You may notice I use hasOwnProperty, which you can read about here.)

All objects have a .__proto__ property

Okay, technically they ‘inherita .__proto__ property, using the same ‘inheritance’ pattern JavaScript uses for everything else. So not only does .__proto__ play a crucial role role in providing for ‘inheritance’ for everything else, but it is itself ‘inherited’. However, this isn’t important; for practical purposes, we’ll say objects do have their own .__proto__.

What matters is your new array literal[] ‘has’ a .__proto__. Everything does. (By the way, the .__proto__ property is special in the sense that you’re not supposed to interact with it directly.)

That .__proto__ property points to their constructor function’s .prototype object

The code explains it:

I also drew the diagram below. If we pretend that var arr = new Array() is code that actually executed, then arr.__proto__ was set equal to Array.prototype. (This is part of what the new keyword does.)

But what that really means is that arr.__proto__ was set to a reference to the same object that Array.prototype references.

If, before reading this article, you were fuzzy on what an array’s ‘prototype’ is, you are fuzzy no more. Now you know that Array is not the ‘prototype object’ for []; Array.prototype is.

Functions have both .__proto__ and .prototype but they serve totally different roles

Functions are objects, so what is their constructor? A special function with the name Function. That’s right, there’s a function Function. It creates and returns functions. When you declare a function, behind the scenes something very similar to new Function() happens (per MDN, there’s a difference).

But a function’s .__proto__ and its .prototype play totally different roles.

A function’s .__proto__ is used for itself. If you try accessing a property on a function, and the function doesn’t have that property itself, it will look in its prototype. That prototype object is Function.prototype.

A function’s .prototype is used for others. If an object is created as a result of calling that function with the new keyword, then that object’s prototype object will be that function’s .prototype object.

Constructor functions’ prototype property have a constructor property pointing back to themselves

Okay, that’s a mouthful, so I’ll break it down. As you know, a ‘constructor function’ is just the conventional name for a function used to ‘construct’ new objects, and to construct them using new).

As discussed earlier, constructor functions have a .prototype property. In fact, all functions have a .prototype property. If this wasn’t the case, I’d be lying to you when I said constructors are ‘just’ functions! But they are just functions, so all functions must have one — and all functions do have one. It’s just that the .prototype property never matters for most functions.

Anyway, on every such .prototype object, there’s a .constructor property. And that constructor property points back to the original function. That’s still a lot — but all that really means is that Array.prototype.constructor = Array.

This is not highly consequential, but cool to know. And because functions, including Array also have a .name property, we can now verify that[].__proto__ points to Array.prototype. You should now be able to understand this code, which verifies the claim that “a prototype’s constructor points back to itself”:

The prototype chain of an object is how it finds missing properties

If an object doesn’t have a method, then it looks at its prototype. If its prototype doesn’t have that method, then it looks at its prototype. And so on.

In the code above, I check if arr has an ‘own’ property length. It does. But then I wonder: who owns hasOwnProperty?

First I check whetherarr itself has an ‘own’ property called hasOwnProperty, and it doesn’t. So, I reason that arr's prototype should be Array.prototype, and I confirm that.

Then I check if Array.prototype has an ‘own’ property hasOwnPrototype and it doesn’t have it either. So, I reason that Array.prototype's prototype should be Object.prototype, and I look for it there.

And there I find it. Object.prototype.hasOwnProperty is a method.

This illustrates the prototype chain in action.

Side Note: the prototype chain is used for non-method properties too.

A function’s .__proto__ is used for itself. If you try accessing a property on a function, and the function doesn’t have that property itself, it will look in its prototype. That prototype object is Function.prototype.

A function’s .prototype is used for others. If an object is created as a result of calling that function with the new keyword, then that object’s prototype object will be that function’s .prototype object.

Time for a break, don’t you think?

Honestly, if you’re not already familiar with most of this, you need a proper course to learn it well, like Launch School’s courses on object-oriented JavaScript. Even if you are, though, I hope I clarified one or two things that represented a gap in your mental models.

Given what you know now, if someone were to ask you why the ‘simple’ code below works…

… I hope you would be able to answer something like this (if they wanted this level of detail):

The string primitive ‘hello world’ is boxed to a String object; that object doesn’t have a toUpperCase method, so it looks to its .__proto__ property, which points to the String function’s prototype property, which points to an object which does have a toUpperCase method. That method is then called in the context of the boxed String object, and that method returns an uppercased string primitive. That uppercased string is the final result of evaluating the right-hand expression, and then gets bound, via the assignment operator, to the identifier ‘uppercased’.”

WHOA.

The most relevant part in all this is that objects of a certain type look for their ‘Type.prototype’ for methods. But to really understand JavaScript, it’s also important to know that the ‘prototype object’ of an object is actually set via the .__proto__ property, which just happens to point to some function’s .prototype property. (It is possible to set the .__proto__ to whatever you want, though it’s a bad idea).

One more time, because it’s important: objects have prototypes.

Pop Quiz!

  1. All __ have a .__proto__ property
  2. All __ have a .prototype property
  3. An object’s __ __ is how an object finds properties it doesn’t have
  4. Are functions also objects? What about arrays?

Answers

  1. objects
  2. functions
  3. prototype chain, though I would also accept “an object’s prototype object”. But make sure you know the difference: if an object’s prototype object doesn’t have a property, then the prototype object’s prototype is checked, and then its prototype, and so on. All those prototype objects comprise the object’s prototype chain.
  4. yes & yes

You’ve learned a ton in this section. Just so you know, you’re through with the majority of the hard conceptual stuff.

Version 2 Solution

Now that you know a lot about OO JS, you should be able to follow this solution and see how it enables us to call .alternativeBind on every function we write.

Version 3: a bind function that supports partial function application

I recommend you read my brother’s article, which covers currying too (a related topic). But I’ll give a quick overview here as well.

Partial application of a function means you’re hard-coding some of the arguments. Here’s an example that should clarify what it could possibly mean to ‘hard-code’ an argument:

displayLetterDoctor is similar to displayLetter, right? What if we could programmatically obtain displayLetterToDoctor from displayLetter? That’s what partial function application lets you do. Here’s some code that does it:

Did you notice that applyHonorific returned a function, just like .bind does? That is what partial function application is supposed to do: return a new function with one or more arguments fixed. Hey, .bind does that too!

In fact, since this and function arguments are both part of the ‘execution context’ for a function invocation, it makes sense that the built-in .bind lets you ‘bind’ either one. (So by adding the ability to do partial application, we’re just helping our .bind function embrace its true nature.)

Before adding partial function application to our .bind, let’s see how to do partial function application without .bind. Below, I show a general partiallyApply function that expects to receive, as arguments, a function to partially apply, followed by one or more arguments to apply. You’ll notice I use the arguments object (I recommend you google if you don’t know what it is.)

I recommend you compare the partiallyApply function here to the applyHonorific function from the previous snippet. See if you can figure out exactly how I made a general function here from the more specific one there.

At this point it’s easy to add partial function application support to our bind. Note that in the solution below I’m no longer naming any parameters to the function like I did in the last version of bind; instead I’m extracting arguments from the arguments object. I’m also calling the arguments to apply argsBeingBound here, as compared to argsToApply in partiallyApply above.

Version 3 Solution

Example of using it:

Version 4: finishing touch — a bind function that gives itself a good name

The MDN Web Docs for .bind mention something interesting at the bottom of the ‘Polyfill’ section:

According to ECMA-262, name of the returned bound function should be “bound “ + name of target function.

Huh! In that same paragraph in the spec that I quoted from, I learned that functions have a .name property. You can read all about .name in the MDN docs. This property is cool because it shows up in stack traces, and informative function names like bound+target, sure are helpful when debugging.

The spec doesn’t say to capitalize the name of the target function, but I want to. Here’s my first attempt updating .bind:

But that doesn’t work. A bound function funky should be named boundFunky, but isn’t:

If you’re wondering where the name boundFunction is coming from, take a closer look at the buggy alternativeBind snippet just above this one.

So, why didn’t re-assigning the name work?

It didn’t work because the .name property isn’t writable (you can’t overwrite it). Every JavaScript property has “property descriptors” under the hood, and you can see what they are with Object.getOwnPropertyDescriptor. Below, I inspect the .name property on a function and see ‘writable: false’.

Luckily, Object.defineProperty lets you overwrite a property. (In fact, the MDN docs for the .name property mentioned this.)

After updating our code to use Object.defineProperty, we’re done.

Version 4 Solution

Here’s an example, using the alternativeBind from above. We get a function named boundForGreatness, just as expected.

A brief look at the ECMAScript specification and V8 engine source code

Remember how, all the way back in version 1, I said we have to use a built-in like .apply to set execution context, and how I’d come back to that? Well, now is the time to revisit it. Why can’t we explicitly set execution context without one of those three built-ins?

Let’s start with the docs. The MDN Web Docs page on this does say:

It can’t be set by assignment during execution

But let’s dig a little bit deeper.

And let’s start by asking: What even is JavaScript?

The spec

JavaScript is an idea, formalized as a specification — there’s just one spec that matters, and that’s the ECMAScript spec, or ES spec. A spec is (more or less) implemented as a program.

The ES spec, when implemented as a program, can interpret and execute JavaScript.

Those programs are called ‘engines’, like the V8 engine, which is used in the Chromium project, which powers browsers like Chrome, Edge, Opera and Brave.

As a special treat (dubious), I thought it would be fun to briefly look at both the spec and then the source code, seeing what we can find about the built-in functions that set execution context.

Here’s the ES 2019 spec. If you search for “keyword this”, you’ll notice it only appears in section 8.3. (If their built-in search on the top left doesn’t work for you, just do what I did and Ctrl/Cmd-F the whole page.)

It appears that ‘this’ is actually a binding to an abstract entity called EnvironmentRecord. The whole section 8 title is “8 Executable Code and Execution Contexts”. However, if you scroll to the top of section 8, then to the bottom of section “8.1 Lexical Environments” you’ll see this paragraph:

Lexical Environments and Environment Record values are purely specification mechanisms and need not correspond to any specific artefact of an ECMAScript implementation. It is impossible for an ECMAScript program to directly access or manipulate such values. [emphasis mine]

By the way, if you read section 8, even for just a few minutes, you come to realize that “execution context” is definitely not the “same as” the keyword this. Rather, this is simply a keyword meant to give you access to (some part of) the execution context, which you can think of as the total ‘environment’ your code runs in. Of course, you already know this, from the ‘Version 1’ section of this article. But you can now feel more confident in this knowledge knowing it comes from the spec.

Admittedly, the spec seems pretty firm — ‘impossible’ is the word it used. But dangit, I want to see why I can’t do it. Into the belly of the beast! (Spoiler: I end up running right back out, tail between my legs.)

The source

You can browse the Chromium source code here. I myself am new to browsing it, so we’re in this together.

There’s a lot of stuff here. Since V8 is the JS engine, and I want to look at source code, the first thing I’m going to do is restrict my search to the v8/src folder. In fact, after searching with bind filetype:v8/src, there are still way too many results. I noticed a subdirectory builtins, and my search results when I narrow down to bind filetype:v8/src/builtins look promising:

If you check out the search results yourself, you’ll notice something interesting: there are multiple files that contain what looks, to my untrained eye, like Assembly code, targeted to different computer architectures. Of all the files in my search results, only the ‘builtins-functions.cc’ file looks the most promising / conceivably legible to me.

The only downside is that it’s C++ code. And I don’t know C++.

Truth be told, I can only sort of understand a fraction of it. But I soldier on.

Searching for ‘bind’ on that page reveals a line starting as follows: BUILTIN(FunctionPrototypeBind) { return DoFunctionBind. If that does what it sounds like it does, then DoFunctionBind is the only thing I need to check out. That function is in the same file, right above the BUILTIN line in fact.

So I take a look at that function. Luckily, there are comments in the function body. After reading them, I think the only part I need to care about is the part with comment starting // Allocate the bound function with the given {this_arg} and {args}. In that section, the code seems to maybe just handle an edge case of this_arg being undefined, populate a new array of args into argv, and then call something called NewJSBoundFunction with this_arg and argv. I think that’s all I need to know from this function.

To learn more, I have to venture to NewJSBoundFunction. Time for a new search!

I’m not sure exactly which file this function is from, so I remove the builtins subdirectory from my search query. After doing a search with phrase NewJSBoundFunction filepath:v8/src, I don’t have many results to look at.

See for yourself. In fact, only the factory.h and factory.cc files define a function, and since header files (.h) don’t define function bodies, I only need to look at factory.cc.

Here’s the file I’m browsing. If you do a Ctrl-F/Cmd-F for NewJSBoundFunction, you’ll quickly find its definition. Again, it has helpful comments, like // Determine the prototype of the {target_function}. And there’s another interesting comment: // Create the [[BoundArguments]]

Why is that interesting? Because [[BoundArguments]] is the sort of thing you see in the specification. It represents an abstract entity, that an interpreter is supposed to implement. So, the comment about [[BoundArguments]] shows a connection between the spec and the source code. Of course, we already knew how they relate, but I think it’s cool to see the spec-code connection explicitly.

Anyway, still in the NewJSBoundFunction, I see something interesting about ‘setting up a map’. I don’t understand what that means, but I see code I’m curious about, bound_function_with_constructor and bound_function_without_constructor. So I do another search, and there’s just one C++ file in the results that actually defines a function of that name, a file named js-heap-broker.cc. I open that and search for bound_function. If the -> I’m looking at is indeed a pointer, and pointers are like references in JavaScript, then these functions might just be aliases for SerializePrototype. I check that out, but it doesn’t seem interesting. I think that ‘serializing’ is probably a low-level task that’s not interesting to my purposes, so I head back to the NewJSBoundFunction.

The last part of that function, per the comment, is to // Setup the JSBoundFunction instance. The function call set_bound_this sure looks interesting.

Unfortunately, that seems to be a dead-end. When I search all of the Chromium source code for that term, there are only a few files, and none of them seem to be defining a function of that name in a way I can make any sense of.

My brief foray into JavaScript internals ultimately left me confused, though intrigued. Unfortunately, I just don’t understand enough of the C++ to know how to proceed. Of course, it was hubristic to think I could, when I haven’t specifically studied C++ nor a language like it.

To be honest, my ignorance goes way beyond that: I don’t even what ‘executable’ code means in the context of assembly or machine code. But while my journey is far from over, I have to pause here.

We learned that JavaScript is itself written in code — and that helps explain why you can’t do some things. Programming languages have limitations on their expressiveness, for better or worse, in part because they themselves are programs.

Side Note: Lisp apparently doesn’t have many limits on expressiveness. I know almost no Lisp (tiny bit of Racket), but I take Paul Graham’s opinion seriously and he’s pretty religious about it. I think I’ll learn a Lisp in the future. The future is a magical place where there’s time for everything.

To end on a hopeful note: if I learn C++ someday, then next time I get a case of curiosity — and dip into the code behind the code — I’ll learn more.

Recap

You’ve hopefully deepened your understanding of JavaScript now. I sure have, just in writing this.

Note: The following recap does, in a few places, extend beyond what I covered above. If you’ve made it this far, though, you’re clearly all about the learning.

  • Functions always execute in an ‘execution context’.
  • The this keyword gives you access to part of that context.
  • You can determine what this is for any given function invocation — the rules are pretty simple and short.
  • Arrow functions set this in a totally different way from ordinary functions (it’s set when the function is defined — like closures).
  • Methods are just properties whose values point to functions.
  • Variables and properties assigned to objects, including function objects, don’t ‘contain’ those objects, but instead ‘contain’ references to those objects.
  • .bind, .call, and .apply all let you specify the execution context for a function. .bind returns a new function but doesn’t execute it.
  • Scope is lexical and execution context is runtime. (But, in a way — and I’m not wedded to this view— this adds to the scope a function invocation can see, because this lets a function access additional data, additional to the variables in its scope. Namely, whatever data is attached to the this object when the function is invoked is the ‘additional’ data ‘in scope’.)
  • Functions that return other functions, or take functions as arguments, are “higher-order functions”. The JavaScript language’s support for first-class functions in general is what enables specific functions to be higher-order.
  • If you need to make a modified version of a function, you might want to write a higher-order function. That function would take as input the function you want to modify, and as output it would return a function that, when called, calls the original (input) function. However, wrapping the original function gives you the opportunity to modify how the original gets called, either by fixing some arguments (partial function application), or the context it runs in (with something like .bind), or by doing something else, like perhaps running an additional function before or after the original function (this idea was not explored, but you could add a before-or-after ‘hook’ onto an existing function.)
  • Partial function application is actually what .bind does. It means that some arguments are fixed. And the execution context, or this, is one such argument. However, partial function application usually refers to fixing one or more other arguments (not this). You certainly don’t need to bind execution context in order to partially apply a function.
  • Almost everything is an object. Even primitives are temporarily converted to objects as needed.
  • Specifically, functions are objects.
  • All objects have a constructor function.
  • A constructor function is just any function that’s intended to be called with the new keyword. Because of how the new keyword works (a topic for another time), constructor functions attach properties to this, and they also return objects.
  • All objects have a ‘prototype object’, which is how they ‘inherit’ behaviors they don’t have themselves. (Inheritance isn’t the best way of thinking about it, but that’s for another time as well.)
  • Objects know what their ‘prototype object’ is because all objects have a .__proto__ property, and whatever that points to is their prototype.
  • By default, an object’s .__proto__ points to the .prototype property of their constructor function. That is, obj.__proto__ — >constr.prototype. For example, arrays have a .__proto__ pointing to Array.prototype.
  • This is why you can call .bind on functions: because functions are objects, they can have properties, and if they don’t have a property you’re trying to access, they’ll look at Function.prototype next, and that’s where .bind is. There exists a property Function.prototype.bind.
  • Constructor functions’ prototype property have a constructor property pointing back to themselves. That’s a mouthful but all it really means is that, for example,Array.prototype.constructor === Array.
  • All object properties have descriptors, including a ‘writable’ descriptor. (The ‘enumerable’ one is important too, but for another time.)
  • You can use Object.defineProperty to overwrite non-writable properties. (It has other uses too.)
  • JavaScript starts from a specification. You can read that spec if you want to. The spec talks in terms of abstract entities. In particular, double-bracket terms are meant to be implemented in code somehow, but are not meant to be available to you as a JavaScript programmer. For example, .__proto__ implements the [[Prototype]] internal attribute. You’re not supposed to be able to access that, but browsers implemented it anyway. Most double-bracket terms are not implemented as accessible properties.
  • The spec gets implemented as an engine (usually written in something like C++), and then you run your JavaScript code. You can always read the source code if you want to.
  • Turns out if you don’t know C++ or something similar, you’re gonna have a bad time trying to read the V8 source code.
  • Last but not least, MDN’s Web Docs are worth referencing frequently.

Congrats on reading this beast of an article. (Oh, and Hello, skimmers and those who skip to the end! You know who you are!) I admit, the whole “write a bindfunction” thing was just cover for me to talk about… well, everything.

If you understand all this, you probably have solid foundational knowledge of JavaScript.

Pitch for the school I go to: If you don’t ‘get’ everything yet, that’s 100% fine too. It’s best to take your time to understand fundamental concepts like these — check out LaunchSchool.com. I’m a student there, and I recommend it for anyone willing to hop off the mad ‘what should I learn?? what frameworks are hot??’ train and actually. learn. fundamentals. They have written and interview assessments to help ensure you know your stuff, and I honestly have no idea how they’re profitable when they’re so affordable, especially when compared to a bootcamp. The only reason I’m pitching it is because it’s a gem.

This article, by the numbers:

  • 10,205 words
  • longest section: the first (4,003 words)
  • shortest section: Version 4 (278 words)
  • 100+ tabs opened for research
  • 8 images created and/or found
  • 1 diagram created
  • 2 pop quizzes
  • 12 memes
  • 42 code snippets

— — — — — DFTBYS: don’t forget to bind(you, success)— — — — —

--

--