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.
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:
- the
this
keyword - ‘losing’ context
- execution context vs.
this
- variables as ‘pointers’/references
- methods vs. functions
- arrow functions and
this
.bind
vs..call
vs..apply
- prototypal ‘inheritance’
- everything is an object (almost)
- the difference between
.__proto__
and.prototype
- first-class functions
- higher-order functions
- partial function application (sometimes incorrectly called currying)
- property descriptors
- using
defineProperty
to change a non-writable property like.name
, and why you might want to - the MDN Web Docs
- the ECMAScript specification
- 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 - Version 1: a basic bind function
- Version 2: a bind function you can call on other functions + Crash course in prototypes and OO JS concepts you must know
- Version 3: a bind function that supports partial function application
- Version 4: finishing touch — a bind function that gives itself a good name
- A brief look at the ECMAScript specification and V8 engine source code
- Recap
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 asomeName
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
invar foo = function bar(){}
refers to the same function thatfoo
refers to, you can only dobar()
within the body of the function itself. - There’s nothing weird about calling
bar
withinbar
, 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).
- 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: inobj.func()
,this
isobj
. - If a function was hard-bound with some context, that’s what
this
will be. The.bind
method does this. - If a function is called with an explicit context, via
.call
or.apply
(which are discussed soon), then that’s whatthis
will be. - 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 globalwindow
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 .bind
s:
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!
- Can context get ‘lost’?
- What does line 6 of the following code log, and why? (This is tricky.)
- What do lines 7, 8, and 9 log?
- What does line 10 of the following code log, and why?
- 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:
- 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 makethis
what you want it to be. - Line 6 logs
undefined
. Do you know why? (Answer: because in the context of that function call,this
waswindow
; and if you try accessing properties you didn’t define, you getundefined
. So the function tried accessingwindow.b
and gotundefined
). - Lines 7, 8, and 9 all log
2
. - 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.) - 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, butthis
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 itsthis
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:
this
gets set- a new function is returned
- 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 tothis
. - 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 ‘inherit’ a .__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’.”
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!
- All __ have a
.__proto__
property - All __ have a
.prototype
property - An object’s __ __ is how an object finds properties it doesn’t have
- Are functions also objects? What about arrays?
Answers
- objects
- functions
- 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.
- 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, becausethis
lets a function access additional data, additional to the variables in its scope. Namely, whatever data is attached to thethis
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, orthis
, is one such argument. However, partial function application usually refers to fixing one or more other arguments (notthis
). 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 thenew
keyword works (a topic for another time), constructor functions attach properties tothis
, 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 toArray.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 atFunction.prototype
next, and that’s where.bind
is. There exists a propertyFunction.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 bind
function” 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)
— — — — —