Last active
August 29, 2015 14:01
-
-
Save bignimbus/45e9411fdf31478d0fac to your computer and use it in GitHub Desktop.
A brief explanation of JavaScript's native .apply() and .call() functions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// In a recent interview I was stumped by a question about JS's native | |
// function.apply() and function.call() methods. I resolved to learn more | |
// about why these methods are useful to a JS developer. Here's what I now | |
// understand: | |
// let's make a simple function that introduces an individual. | |
// We pass arguments defining the interests of the individual. | |
// The greeting is personalized by the value of this.name. | |
function introduceMe (interest1, interest2) { | |
var that = this; | |
if (!this.name) this.name = '... I forgot.'; | |
return { | |
greeting: 'Hi, my name is ' + this.name, | |
interests: [interest1, interest2], | |
context: that //for reference | |
} | |
} | |
// Now, for laughs, I'll call this function in the global context. | |
introduceMe('JavaScript', 'music'); | |
// => Object {greeting: "Hi, my name is ... I forgot.", interests: Array[2], context: Window} | |
// This function is clearly socially awkward. Let's see if I | |
// can help the poor thing out. | |
// Here are paul and john - they're objects (of our admiration). | |
var paul = {}, | |
john = {}; | |
// How are you going to introduce yourself without a name? | |
paul.name = 'Paul'; | |
john.name = 'John'; | |
// Paul needs a standard way to introduce himself. | |
// That way, he won't freeze up. Good thing we have introduceMe()! | |
paul.introduction = introduceMe('bass', 'Walrus'); | |
// => Object {greeting: "Hi, my name is ... I forgot.", interests: Array[2], context: Window} | |
// Poor Paul. John - you're up! | |
john.introduction = introduceMe('guitar', 'Yoko'); | |
// => Object {greeting: "Hi, my name is ... I forgot.", interests: Array[2], context: Window} | |
// Looks like our trouble is that pesky THIS. | |
// Maybe they need a friend to come and introduce them. | |
// In some cases, a simple constructor statement could work. | |
paul.introduction = new introduceMe('bass', 'Walrus'); | |
// => Object {greeting: "Hi, my name is ... I forgot.", interests: Array[2], context: introduceMe} | |
// | |
// But not this case! paul.introduction does not have access to | |
// paul.name, therefore his introduction is destined to fail. | |
// furthermore, the value of THIS is still not paul himself. | |
// I am heading in the right direction, though. | |
// As he always does, John is going to try something a little different. | |
john.introduction = introduceMe.call(john, 'guitar', 'Yoko'); | |
// => Object {greeting: "Hi, my name is John", interests: Array[2], context: Object} | |
// | |
// SUCCESS! john can now introduce himself without fear of social anxiety. | |
// And who says programmers don't have people skills? | |
// When we invoke a function using the .call() method, we add one argument. | |
// The first argument in .call() overrides the default value of THIS. | |
// So even though we are calling introduceMe() from john.introduction, | |
// we can still set the john Object as THIS. | |
// Paul, being the organized fellow he is, is going to refine this strategy | |
// a bit with the .apply() method. | |
// First, let's define paul's interest in a separate array object: | |
paul.faves = ['bass', 'Walrus']; | |
paul.introduction = introduceMe.apply(paul, paul.faves); | |
// => Object {greeting: "Hi, my name is Paul", interests: Array[2], context: Object} | |
// Not only did paul's approach work just as well as john's (at a very | |
// slight performance cost), but he opened up the possibility of | |
// introducing an arbitrary number of arrays with a few obvious tweaks. | |
// That's the main difference between .call() and .apply(). Here's a chart: | |
/* | |
Need to call a function and override THIS. | |
| | |
|---> Use function.call() or function.apply() | |
| | |
|---> Which one? | |
| | |
|---> .call() has a slight performance advantage but needs to pass comma-separated parameters. | |
| | |
|---> .apply() can pass all parameters as an array object. | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thanks for this - context can be really confusing and really is one of those things you need to play with to really "get", I still find it catches me from time to time.