What is `this`? The Inner Workings of JavaScript Objects

Eric Elliott
Mar 26, 2019 · 5 min read
Photo: Curious by Liliana Saeb (CC BY 2.0)

JavaScript is a multi-paradigm language that supports object-oriented programming and dynamic binding. Dynamic binding is a powerful concept which allows the structure of your JavaScript code to change at runtime, but that extra power and flexibility comes at the cost of some confusion, and a lot of that confusion is centered around how this behaves in JavaScript.

Dynamic Binding

Dynamic binding is the process of determining the method to invoke at runtime rather than compile time. JavaScript accomplishes that with and the prototype chain. In particular, the meaning of inside a method is determined at runtime, and the rules change depending on how that method was defined.

Let’s play a game. I call this game “What is ?"

Before you continue, write down your answers. After you’ve done so, your answers to check them. Did you guess right?

Let’s start with the first case and work our way down. In the context of an ES6 module, returns . In a script tag, it’s . In the Node REPL, it’s .

Why? Arrow functions can never have their own bound. Instead, they always delegate to the lexical scope. In the root scope of an ES6 module, the lexical scope would have an undefined . is also , for the same reason. For arrow functions, can't be reassigned, even with or . It will always delegate to the lexical .

gets its binding via the normal method invocation process. If there is no previous binding, and the function can have bound (i.e., it's not an arrow function), gets bound to the object the method is invoked on with the or property access syntax.

is a little trickier. The method calls a function with a given value and optional arguments. In other words, it gets its binding from the parameter, so returns the object.

With , we're trying to bind an arrow function, which we've already determined will not work, so we're back to (or or ) for both , and .

You can bind regular methods, so returns , as expected, and because it's already been bound with , respects the first binding and returns instead of .

Curve Ball

Same challenge, but this time, with using the public fields syntax (Stage 3 at the time of this writing, available by default in Chrome and with ):

Write your answers down before you continue.

Ready?

With the exception of , these all return the object instance. The exception returns the object. The arrow function still delegates to lexical . The difference is that lexical is different for class properties. Under the hood, that class property assignment is being compiled to something like this:

In other words, the arrow function is being defined inside the context of the constructor function. Since it’s a class, the only way to create an instance is to use the keyword (omitting will throw an error).

One of the most important things that the keyword does is instantiate a new object instance and bind to it in the constructor. This behavior, combined with the other behaviors we've already mentioned above should explain the rest.

Conclusion

How did you do? Did you get them all right? A good understanding of how behaves in JavaScript will save you a lot of time debugging tricky issues. If you got any of the answers wrong, it would serve you well to practice. Play with the examples, then come back and test yourself again until you can both ace the test, and explain to somebody else why the methods return what they return.

If that was harder than you expected, you’re not alone. I’ve tested quite a few developers on this topic, and I think only one developer has aced it so far.

What started as dynamic method lookups that you could redirect with , , or has become significantly more complex with the addition of and arrow function behavior. It may be helpful to compartmentalize a little. Remember that arrow functions always delegate to the lexical scope, and that is actually lexically scoped to the constructor functions under the hood. If you're ever in doubt about what is, remember to use your debugger to verify the object is what you think it is.

Remember also that in JavaScript, you can do a lot without ever using . In my experience, almost anything can be reimplemented in terms of pure functions which take all the arguments they apply to as explicit parameters (you can think of as an implicit parameter with mutable state). Logic encapsulated in pure functions is deterministic, which makes it more testable, and has no side-effects, which means that unlike manipulating , you're unlikely to break anything else. Every time you mutate , you take the chance that something else dependent on the value of will break.

That said, is sometimes useful. For instance, to share methods between a large number of objects. Even in functional programming, can be useful to access other methods on the object to implement algebraic derivations to build new algebras on top of existing ones. For instance, a generic can be derived by accessing and :

Eric Elliott is a distributed systems expert and author of the books, “Composing Software” and “Programming JavaScript Applications”. As co-founder of DevAnywhere.io, he teaches developers the skills they need to work remotely and embrace work/life balance. He builds and advises development teams for crypto projects, and has contributed to software experiences for Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica, and many more.

He enjoys a remote lifestyle with the most beautiful woman in the world.

JavaScript Scene

JavaScript, software leadership, software development, and…