Working with JavaScript’s Built-in Function Methods

Uriel Rodriguez
5 min readFeb 13, 2021

In JavaScript, anything that is not a primitive value such as strings or integers is an object. What this means is that functions are actually objects or at least specialized objects. This also means that functions have access to properties and methods like all other objects do. JavaScript defines built-in properties and methods on functions like the name property which returns the name of the function declaration or the variable name that binds to the function object within function expressions.

function thisFunc() {
...
}
console.log(thisFunc.name) // => thisFunc
const thatFunc = () => ...
console.log(thatFunc.name) // => thatFunc

Included in these built-in properties, are the call(), apply() and bind() methods. These methods allow functions to work like methods on objects without needing to be defined as methods within the objects.

Call()

function addProperty(name, value) {
this[name] = value
}
const myObj = {}addProperty.call(myObj, "myProp", "myValue")console.log(myObj) // => { myProp: "myValue" }

In this example, a function “addProperty” is defined which references an object via the “this” value, and sets a property on that object using the passed arguments. Ordinarily, within a function declaration like the one above, the invocation context usually is the global object and if “addProperty” is invoked like a normal function, it will set a property on the global object. However, the “addProperty” function is invoked indirectly by invoking its call() method instead, which takes as its first argument an object, or a “this” value. By providing the “myObj” object to the call() method, we define the “this” value within the “addProperty” function. After the first “this” argument, call() receives the arguments that the function it is invoked expects, in this case, “addProperty” function expects a “name” and “value” argument.

Apply()

Similar to the call() method, apply() also defines a “this” value for the function it is invoked on. But unlike call() which receives further arguments as individual values, apply() takes in arguments as elements in an array. This is a convenient way to provide an indeterminate amount of arguments to a function. For example:

const nums = [3, 4, 6, 7, 9]let max = Math.max(nums)let maxNum = Math.max.apply(null, nums)console.log(max) // => NaN
console.log(maxNum) // => 9

In this example, you can see that invoking Math.max() with an array of numbers produces the value “NaN”. This is because Math.max() expects an arbitrary amount of integer arguments and returns the max value from them. Those integer arguments must be provided as single arguments and not within an array structure. By invoking apply() on Math.max(), we are able to get around that issue, because apply takes in arguments in the form of an array and then distributes them within the function it is invoked on. One thing to note is that this issue can also be handled with the spread operator, as it's the more modern approach.

const nums = [3, 4, 6, 7, 9]let maxNum = Math.max(...nums)console.log(maxNum) // => 9

Another thing to note is that the “this” value in the apply() invocation is set to null because in this case, the function we are invoking apply() on, Math.max() does not make use or computes on a “this” value.

Bind()

Finally, the last of the function methods trio is the bind() method which behaves similarly to the call() or apply() methods in that it is used to have a function act on an object. However, the big difference with bind() is that it permanently binds a function to an object, and returns a new function that will always operate on the object it was bound to. This is the case even if the function returned from invoking bind is assign as a method in another object.

const person = { age: 20 }function increaseAge() {
this.age++
}
const growOlder = increaseAge.bind(person) // => returns a functiongrowOlder()
console.log(person.age) // => 21
growOlder()
console.log(person.age) // => 22
---------const newPerson = { age: 25, growOlder }
newPerson.growOlder()
console.log(newPerson.age) // => 25
console.log(person.age) // => 23
console.log(newPerson)
// => { age: 25, growOlder: [Function: bound increaseAge] }

As you can see, invoking bind() on a function ties that function to the object that is passed in as the argument. It returns a function that can be invoked to carry out the bound function’s operation on the object. And because the function is permanently bound to the object, even if the returned function is assigned as a new property or used in any other context, it will always refer to the “this” it was bound to.

Another functionality of the bind() method is that of binding additional arguments to the parameters of the function bind() is invoked on, also known as “currying”. For example:

const multiply = (x, y) => x * yconst double = multiply.bind(null, 2)console.log(double(3)) // => 6
console.log(double(12)) // => 24
const triple = multiply.bind(null, 3)console.log(triple(4)) // => 12

This example demonstrates currying, in that the additional arguments after the first argument designated for the “this” value are bound to function, and in this case, to the parameters of the function bind() is invoked on. The first argument passed to bind() is null because the function multiply() does not work with the “this” value. The following argument provided is the number 2 which is bound to the “x” parameter, returning a new function that simply only requires a value for the “y” parameter.

Although you have seen how these function methods allow the redefining of a function’s “this” value, they do not work with arrow functions. Arrow functions inherit the “this” value from the environment or namespace in which they are defined. This inheriting feature of arrow functions can not be overwritten with these function methods. With that being said, common usage for the bind() method includes making regular functions behave like arrow functions, except by explicitly binding the function to a particular “this” value.

With this, you can now see the additional functionalities JavaScript functions provide. These methods provide function objects additional flexibilities for varying applications. To learn more about functions and their methods, particularly call(), apply() and bind(), JavaScript MDN has great documentation.

--

--

Uriel Rodriguez

Flatiron School alumni and Full Stack web developer.