Javascript: From Fundamentals to Functional JS
Introduction
The link to the course slideshow is here
The link to the course on FrontEnd Masters is here
Tips for Learning
-
Difficulty ramps up considerably, but if you stick with it you will reap the rewards
-
Take responsibility for your learning - don’t make excuses for why you cannot learn something, figure out how to measure your learning (it is different for everyone)
-
Consider the questions asked
-
Don’t read too much. If you are trying to learn a skill that requires you to solve problems, it’s not always as productive as it may feel
-
Teach other people, explain what you learned and how it works
Functional Programming
Functional programming has become popular to the point that functional programming and utility methods have been integrated into modern frameworks. Functional programming is about breaking code into verbs, vs object oriented programming being about nouns. It is easier to think about software in terms of objects because that’s where we, as humans, live, in the physical world. Whereas with functional programming, you need to think in terms of the actions. In functional programming, the focus is on… functions. Lots of functions, functions being passed to functions, functions being returned from functions, working with parameters and arguments. One benefit of functional programming vs object oriented programming: Pure functions don’t have side-effects - makes code easier to test
Objects
Property Access
Assignments with Dots
Anything that ever uses a dot in JavaScript is an object.
A primitive value is a string, number, boolean, null, or undefined. A non-primitive valye is an object, array, function, promise. Primitive values get passed by value, non-primitive values get passed by reference. If you are passing primitive values, a copy is made, non-primitive values are passed as a reference. This behavior can produce unpredictable results if you are not careful. For example, if you were to assign person.name
to a variable i.e. who
, then reassign person.name
, who would retain the original reference for person.name
.
Arrays
Arrays are objects, and because of that, the rules are exactly the same. The major difference between an array and an object are the available methods for either, an example of which is .length
being an available method for arrays, but not objects. If you check the typeof
for the person
variable in the code block above, the console should return object
.
Bracket Notation
The person[plea] = "I would never!"
will create a new property in the person object based on the original value of the plea variable "wouldShe"
, which will make the person object look like this:
If the intention was to create a plea
key for the person object, then you need to surround the plea
with quotes. i.e. person["plea"] = "I would never!"
. The person object would then look like this:
Reviewing what we’ve learned about objects and arrays:
-
An array is an object that has methods available to it.
-
A property string can be passed with dot notation or brackets and quotes.
-
Dot notation coerces to a string, but cannot coerce a number to a string, it will result in a SyntaxError. JavaScript will start to evaluate the number as a number and then throw the SyntaxError.
-
If you receive a SyntaxError when trying to access a variable within an object with dot notation, use bracket notation and quotes around the variable name to access it.
Non-Valid Characters
Try not to use non-valid characters as property names, like '^&*'
, that is not a very good property name both because it uses non-valid characters and it is not named in a very memorable or sensible way. You can certainly use non-valid characters to name your properties, but the name will need to be surrounded by quotes. Try to keep your code to the point and don’t get too fancy.
Q&A
Q: What is the difference between an array and an object? (this seems to have already been answered in the previous section)
A: An array is a special kind of object. The most special thing about an array is the .length property which is a property that is computed as you add numerical indices. Numerical indices are different than properties on an array because an array captures that and will increment the length.
If you have an array containing any number of items and add something to an index that does not exist; if you add something to the array at an index position that is more than 1 greater than the current .length [numnber of index positions] of the array, empty values will be inserted until it reaches the requested index position. i.e. original array is y[0,1,2,3,4,5]
and you would like to add y[10]=number
, the array will now be y[0,1,2,3,4,5,,,,number]
Arrays are easier to reverse and loop through than objects.
Game Characters Challenge
Exercise: Create an object using bracket and dot notation that represents the characters and related data you may find in a game of Clue.
Characters Weapons Rooms
Game Characters Solution
If you took the above array and made it into an object, it might look something like this:
Object Review
JavaScript Object Rules
You can use dot or bracket notation when working with;
Dot Notation: strings
Bracket Notation: strings, numbers, variables, weird characters, expressions
Why would you even use dot notation? Because it is less characters than bracket notation
ES6 Destructuring
Destructuring is a simplified way of defining variables and taking them outside of an object or an array.
i.e. Destructuring an Array
const
and let
are features of ES6
const
is used when you want the value of the variable to remain constant
const will not apply to the properties of the object unless you explicitly ‘freeze’ them using Object.freeze
let
is used when you want to restrict a variable to a certain scope
i.e. Destructuring an Object
Objects do not have an order, but the names do have to match. If you think or expect that an object needs an order, you should be using an array.
Destructuring Challenge
Create an object that looks like this:
{“name”: “Rusty”, “room”: “kitchen”, “weapon”: “candlestick”}
Extract out the weapon and location using destructuring
Destructuring Solution
let {name, room, weapon} = {“name”: “Rusty”, “room”: “kitchen”, “weapon”: “candlestick”}
Destructuring Examples
On extracting data and working with nested data structures
There are many more notes in the course itself covering destructuring but the instructor does not cover them and suggests to look for a course on ES6
List Transformations
List Transformations
Nesting
Nesting had been talked about earlier, below is an example.
Considering the above, what would game[suspects]
return?
nothing… because the quote marks were missing around ‘suspects’. With the added quote marks, it would return an array with the suspect objects.
Looping Exercise
Using the nested structure from the previous section, loop through it using any for
loop of your choice.
Looping Solution
Here is a solution by a participant of the in-person class
Looping Exercise, Part 2
Loop through all of the properties of the suspect objects in the suspects array, mark them if you think they are guilty.
Looping Solution, Part 2
Here is a solution by a participant of the in-person class
Looping Exercise, Part 3
Destructure the nested data structure into two variables with the strings ‘red’ and ‘orange’
Looping Solution, Part 3
Here is a solution by a participant of the in-person class
.forEach() Function
Using Functions
This section covers list transformations with functions and shows how to convert data into a class
In JavaScript classes are just functions that return objects.
Using the above code, how would you create a suspect object from each suspect in the suspects array?
One way would be to loop through the list like this:
forEach Function
_.each takes 2 arguments, the first thing is a list and the second thing is a callback function, also known as an iterator function because it is used on things that can be looped through (arrays). Using _.each, the callback function will be called on each item in the first argument; the list. i.e.
_.each / forEach defined
-
Iterates over a list of elements, passing the values to a function
-
Each invocation of iterator, the function, is called with three arguments: (element, index, list). If list is a JavaScript object, iterator’s arguments will be: (value, key, list).
Each is useful for looping through lists
The difference between _.each and .forEach is: .forEach is a method on the array itself, _.each takes in the array as an argument
What would the following log?
forEach and _.each Exercises
Complete the rest of this function so that it works as described in the previous sections:
forEach and _.each Solution
.map() Function
_.map() vs .map() Functions
_.map([1, 2, 3], function(v, i, list) {console.log(v)})
-
Produces a new array of valuse by mapping each value in list through a transformation function ( iterator ).
-
Each invocation of iterator is called with three arguments: (element, index, list). If list is a JavaScript object, iterator’s arguments will be: (value, key, list).
map is used to take lists and transform them into a new array - manipulate, change, update
_.map() Exercise
Unrelated Note: If you want to quickly test out a function in a library, you can usually visit the library’s site and open the console. i.e. visit underscorejs.org, open the console and type _.map()
_.map() Solution
_.map() vs _.each()
No notes. Was merely a comparison of underscore.js _.map and _.each. Refer to above notes for comparison.
_.map() Exercise, Part 2
Map returns an array
Like each, map iterates through a list
_.map() Solution, Part 2
Pro tip: Seek to understand the internals of the code you are implementing. Don’t rely on; change, save, check, change, save, check. Understand and clearly model what you are doing. It may (seem to) take more time up-front, but the payoff is greater in the long-run. If your code is getting too difficult to hold in your mind, that could be a sign that your code is too complex and may be an opportune time to revisit and simplify your code.
.filter() Function
.filter() Exercise
What is filter? Filter is a function that takes an array and a callback. It returns a new array that only contains the values that result in true when passed through the callback function.
The exercise was not detailed. So it is in the solution
.filter() Solution
.filter() Application Exercise
Using the below object videoData
and _.filter, return an array of objects containing only the people that were present
.filter() Application Solution
Functions In-Depth
Anatomy of a Function
How exactly does our code execute?
Check out the anatomy of a function
A function definition does not invoke the function, the invocation happens after the function has been declared, usually by functionName(arguments).
Parameters of a function hold no value, their value is determined by the arguments passed at call-time.
Function Scavenger Exercise
Function Scavenger Solution
-
Function definitions can be spotted whenever you see the word ‘function’
-
Function names come in a few flavors, in this exercise nameImprover, .hide(), .forEach(), .on(), .log(), and $ are function names
-
Function bodies are whatever shows up between the {}. They do not get run until the function is invoked
-
Function invocations here are; return, .hide(), .forEach, console.log, .on(), $
-
Function arguments and parameters. Arguments have a value, parameters are the name. Parameters; name, adj, val Arguments; ‘body’, ‘button’, ‘click’, function()…
-
Function return is shown where the word ‘return’ appears. A side effect is anything that reaches beyond the {} of a function; i.e. console.log(‘I am a side effect!’). $(‘body’).hide(); is a side effect as well.
ES6 Arrow Functions
=> replaces the function
keyword
If there is only one parameter, it does not need to be wrapped in parenthesis.
Arrow functions do not have their own value for this
. Arrow functions reach into their parent scope for this
.
If you are trying to return something from an arrow function, it is best to explicitly declare the return statement.
Side note: Template strings (surrounded by backticks), are ES6 syntax. It allows you to reference variable names i.e. ${variable}
without the need to plus signs and quote symbols all over the place.
Projecting Exercise
Projecting is when you take a value out of one data structure and turn it into another data structure.
Filter and then map this data structure to get the names of the final suspects to send back to the “team”
Projecting Solution
Spread Operator
Quick Review; what will this return?
[['It', 'could'], ['be', 'anyone']]
With the addition of the […] spread operator, what will this return?
[['It', 'could'], ['be', ['anyone', 'no one']]]
Since createTuple
only takes 4 arguments (a, b, c, d), ‘no one’ gets left out. But with the spread operator, the remaining values will be places into an array with the final value.
Arguments Keyword
The arguments keyword references all of the arguments as a pseudo-array. A pseudo-array is an object that looks like an array, but it is actually an object. This means that we do not have access to any array methods (push, pop, slice, etc).
The arguments keyword is useful when a variable has been passed in, but it was not accounted for with a parameter.
The above would log: '[It', 'be', 'could', 'anyone', 'no one']
Default Parameters
A default parameter is the value that your parameter defaults to when it is not passed an argument.
The default value of b
is 2, so if an argument is not passed, it will default to that value.
ES5 Rewrite Exercise
Using ES5, how would you set a default parameter for:
Solution:
ES5 Rewrite Solution
The above exercise has the solution.
Array-Like Object
Array.from
Array.from can turn the arguments pseudo-array into an actual array… replaces Array.prototype.slice.call
. It has many more features described here
_.from() Exercise
Implement _.from() to mimick Array.prototype.slice.call in a function
_.from() Solution
Scope
Scope Walkthrough Setup
Scope is the area where a variable has access to some value. A global variable is accessable to the entire codebase. Local variables are inside of functions or blocks. The setup is using the Mocha testing library.
Function scope states that a function has access to the variables or values that are inside, or in the parent function. You can only look up the tree, but not down.
Scope Walkthrough, Part 1
Continue walking through the testing suite
Scope Walkthrough, Part 2
Variables declared within a function are scoped to that function. If you declare a variable and then redeclare that variable within a function, the value of that variable will be as it has been set inside of the function.
Whenever you call a function, you create a brand new function scope (execution context) each time.
Scope Walkthrough, Part 3
You can pull a function out of the local scope of a document and attach it to the window i.e. window.theFunctionIWant = theFunctionIMade;
The appropriate time to use let
is when you want to scope a variable inside of a block that is not a function.
Scope Takeaways
- Execution Context - an abstract concept of an environment where the Javascript code is evaluated and executed. Whenever any code is run in JavaScript, it’s run inside an execution context.
Callbacks
Higher-Order Functions & Callbacks
Higher-Order Functions in JavaScript is what enables us to do functional programming techniques. In JavaScript, functions are treated as data, similar to objects, or other elements.
A Higher-Order Function can take a function as an input i.e. addEventListener
.
Callbacks are functions that are passed to functions.
The above is a very basic example of a callback function. ifElse is being passed: true and 2 anonymous functions. The condition
is true, so the true
will be printed in the console.
Passing Arguments
Translate into ES6 Exercise
Translate into ES6 Solution
See above solution
Passing Arguments, Part 2
You can pass an argument to a callback function by passing in an additional parameter to the function that the callback function is called in. i.e. const ifElse = (condition, isTrue, isFalse, argument)...
_.reduce() Exercise
Implement _.reduce()
_.reduce() Solution
The above exercise has the solution.
Empty Room Exercise
Link to dataset for this exercise
Empty Room Solution
Functional Utilities
Currying
Currying is when you create a function that can then later be called multiple times with different arguments.
For example:
Currying allows you to break up arguments passed by the number of arguments.
Composing
Composing is when you take two functions and combine them.
For example:
Advanced Scope: Closure
Closure
Closure, Part 2
Creating Closure
If you continue to call funcAlert();
, the count
value would continue to increase by 1 each time the function is called and it would be independent of the execution contect of funcAlert2();
; which would still be at 0 until called.
Closure Demonstration
With the above function, you can create separate execution contexts by declaring variables that are equal to the function countClues()
; i.e. counter = countClues(); counter2 = countClues;
Closure Recipe
Here is the slide for the closure recipe
A closure is when a function is inside of another function and it creates scope isolation. This can be acheived by returning a function from within a function which allows the function to retain access to its parent scope even after it has been executed.
The recipe for a closure is as follows:
-
Create your parent function
-
Define some variables in the parent function’s local scope
-
Define a function inside the parent function. This is called a child
-
Return the child function from inside the parent function
The execution piece of a colsure is as follows:
-
Run the parent function and save it to a variable. This variable will now hold whatever the parent function returns; i.e. the child function
-
Optional… Check what the variable now holds as it value, it should be the child function
-
Run the inner function by calling your newly created variable
-
What happened?
Same as above, but with console.log(s)
Currying and Componsing Exercises
Skips right to solutions…
Currying and Componsing Solutions
Currying
Composing
Wrapping Up “JavaScript: From Fundamentals to Functional JS”
Wrapping Up
We covered functional utility methods, scope, functions, objects, and arrays. Mostly covered in ES5 with some ES6 thrown in. Moving forward, use and apply what you have learned in future courses.