Function Borrowing in JavaScript

When we create JavaScript objects, we typically associate them with certain behavior. Consider the below example:

We’ve created a class Dog with three properties and two methods, one of which is tellUsAboutYourSelf(). We’ve also created a new instance of Dog, which is saved into the variable fido. Pretty straightforward. Now, let’s create another class and instantiate a new instance:

We’ve created a Cat object with the same properties as our Dog object, but our instance of Cat, which is saved into the variable sparkles, isn’t able to tell us about itself. We could refactor our code so that the class Cat inherits from the class Dog, but in that scenario, all of our Cat objects would be able to “woof,” which doesn’t seem appropriate or necessary. Enter: function borrowing.

How does it work?

Given the objects we created above, take a look at function borrowing in action:

fido.tellUsAboutYourSelf.call(sparkles)//=>’My name is Sparkles. I am a Siamese and I am 5 years old.’
fido.tellUsAboutYourSelf.apply(sparkles)//=>’My name is Sparkles. I am a Siamese and I am 5 years old.’
const describeSparkles = fido.tellUsAboutYourSelf.bind(sparkles)describeSparkles()//=>’My name is Sparkles. I am a Siamese and I am 5 years old.’

Each of these examples work because this, when referenced inside a method, refers to the object that received the method call. .call(), .apply(), and .bind() work by allowing us to alter the object to which this refers inside of the .tellUsAboutYourSelf() method. Whereas .call() and .apply() immediately execute the function call, .bind() saves the function for later. Once we’ve saved the borrowed function into the variable describeSparkles, we can call invoke describeSparkles one hundred lines later and still see the same output.

What’s the point?

The most important practical application of function borrowing pertains to native methods, and specifically, to Array.prototype.slice. There are several list-like data structures that aren’t arrays, and it’s useful to be able to treat them as arrays and operate on them as such. One of the most prevalent list-like data structures that isn’t an array is arguments. The arguments object represents all the parameters passed in to a given (non-arrow) function.

Take, for example, the below function:

In the above example, findO is a variadic function, which means it takes a variable number of arguments. We’ve passed it four strings, and we’d like to see which of those strings contain the letter ‘o’. The arguments object holds those four strings, but we can’t simply call .filter() on arguments because it is not an array. We’re able to convert it into an array, however, by borrowing the .slice method from Array.prototype, and setting this to equal the arguments object. Once it has been converted to an array, we have access to all of the built-in methods on Array.

Nifty!

front end engineer / poet / editor / www.betsysallee.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store