Last active
August 22, 2019 07:23
-
-
Save ckipp01/45fafccecf06c982938c0e7206cd4529 to your computer and use it in GitHub Desktop.
Javascript function examples
This file contains 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
'use strict' | |
/* | |
This is meant to be a concise explanation on the difference between | |
functions declaration, function expressions, and es6 fat arrow functions | |
You should be able to just clone this or paste it in a file and run `node <filname>` | |
*/ | |
/* | |
Ex. 1 | |
Traditionally, you probably would have seen function declarations | |
the most. That's what you are seeing below if you find where add5 | |
is defined. Key features of a function declaration is that the function | |
is hoisted. This means that the function declaration is loaded before any | |
code is executed and available in your program before you reach the line | |
where it's defined. | |
*/ | |
log('Ex. 1', add5(3)) | |
/* | |
Ex. 2 | |
The biggest difference with a function expression is that the function | |
definition is not hoisted. Therefore when we try to call expressionAdd5 | |
below it won't be able to call the function until after creation, meaning that | |
it's not available until the line of code that creates it has ran. | |
*/ | |
try { | |
expressionAdd5(2) | |
} catch (err) { | |
log('Ex. 2', err.message) | |
} | |
/* | |
Ex. 3 | |
es6 arrow function expressions are also not hoisted. | |
Therefore calling es6ArrowAdd5 here will also result | |
in a reference error | |
*/ | |
try { | |
es6ArrowAdd5(2) | |
} catch (err) { | |
log('Ex. 3', err.message) | |
} | |
// function declaration | |
function add5 (num) { | |
return num + 5 | |
} | |
// function expression | |
const expressionAdd5 = function (num) { | |
return num + 5 | |
} | |
// es6 function expresssion / es6 arrow function / fat arrow funciton | |
const es6ArrowAdd5 = num => { | |
return num + 5 | |
} | |
/* | |
Ex. 4 & Ex. 5 | |
Now that we've passed where the two function expressions have been | |
created above and assigned to variables, we can reference them below | |
with no issue | |
*/ | |
log('Ex. 4', expressionAdd5(3)) | |
log('Ex. 5', es6ArrowAdd5(3)) | |
/* | |
Ex. 6 | |
There are also two ways to write a pre-es6 function expression. | |
The way we did it above with expressionAdd5 was actually an | |
anonymous function expression that was assigned to the variable | |
expressionAdd5. You could also do this with a named function expression | |
like below. Calling them will result in exactly the same thing. | |
*/ | |
const namedAdd5 = function add5WithName (num) { | |
return num + 5 | |
} | |
log('Ex. 6', namedAdd5(3)) | |
/* | |
Ex. 7 | |
es6 arrow functions are always anonymous. There is no such thing as | |
a named es6 function expression. One thing to keep in mind with | |
anonymous functions is that they do save a bit of key strokes, but | |
they do make debugging a bit harder because they are anonymous. | |
You will see two different ways of writing es6 arrow functions. | |
One will have an explicit return like you see in the es6ArrowAdd5, but | |
that is only necessary when you have a block statement. If you don't, the | |
return is implicit. For example, the function below is equivelent to es6ArrowAdd5 | |
and a bit more concise. | |
*/ | |
const implicitReturnEs6Add5 = num => num + 5 | |
log('Ex. 7', implicitReturnEs6Add5(3)) | |
/* | |
One of the largest differences between es6 arrow functions and both function | |
declarations and regular function expressions is that es6 functions have a lexical | |
this binding. This means that the value of `this` inside of the function is | |
determined by where the arrow functions is defined, now where it is used. | |
*/ | |
/* | |
Ex. 8 | |
You'll notice below that when we call update on the myOldObject | |
the this is referring the value defined within the object and updates it | |
*/ | |
const myOldObject = { | |
value: 3, | |
update: function () { | |
this.value++ | |
} | |
} | |
/* | |
Ex. 9 | |
However, if you try to with an arrow funciton, the this is lexically | |
scoped meaning it only has access to the closure created by the update | |
function, not the object value. | |
*/ | |
const myNewObject = { | |
value: 3, | |
update: () => { | |
this.value++ | |
} | |
} | |
log('Ex. 8a', myOldObject.value) | |
myOldObject.update() | |
log('Ex. 8b', myOldObject.value) | |
log('Ex. 9a', myNewObject.value) | |
myNewObject.update() | |
log('Ex. 9b', myNewObject.value) | |
/* | |
Notes on choosing which type | |
While different people may have differnt opinions, and it heavily | |
depends on the context, here are a couple of places you should maybe | |
consider not using arrow functions | |
1) Object methods since the this isn't bound to anything and will | |
inherit the value of this from its parent scope | |
2) Callback functions with event handlers | |
The function expression vs declaration choice is a bit different as you | |
need to think about whether or not you need hoisting. While hoisting seems | |
nice you are also polluting your global scope, whereas using function | |
expressions avoid that. | |
This is in no way an exhaustive list of the types of functions that you | |
have available to you, but this should at least give you a good idea of | |
the difference between function declarations and expressions. For further | |
reading and exploring, feel free to check out any of the below topics all | |
related to functions. | |
1) Immediately-Invoked Function Expression (IIFE) | |
2) Recursive functions | |
3) Curried functions | |
3) Factory functions | |
4) Object Constructors | |
5) Classes | |
*/ | |
// When ran you should see the following results | |
/* | |
❯ node function-examples.js | |
Ex. 1 --> 8 | |
Ex. 2 --> expressionAdd5 is not defined | |
Ex. 3 --> es6ArrowAdd5 is not defined | |
Ex. 4 --> 8 | |
Ex. 5 --> 8 | |
Ex. 6 --> 8 | |
Ex. 7 --> 8 | |
Ex. 8a --> 3 | |
Ex. 8b --> 4 | |
Ex. 9a --> 3 | |
Ex. 9b --> 3 | |
*/ | |
// helpers | |
function log (name, functionOrVal) { | |
console.log(`${name} --> ${functionOrVal}`) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment