JS Fundamentals:
Functions 101
(and beyond!)
Classwork:
https://github.com/RebootJeff/jsFunctions
Presented by:
Jeff Lee
Curriculum by:
Bianca Gandolfo
Who is Jeff?
Full-Stack JavaScriptivore
Hack Reactor VII
Who is Bianca?
Curriculum Goddess
Hack Reactor OG
Who are you?
- Completed JS tutorial like Codecademy, CodeSchool, Khan Academy, or Bloc.io
- 3-6mos experience learning JavaScript
- Want to solidify fundamentals
- Looking for more practice
- Interested in getting into Hack Reactor
Part 1
Review and solidify core JS principles with project.
Part 2
Deep dive into how JS functions can be used.
After
Use fundamentals to grow as a JS coder.
(Learn prototype chain and OOP?)
What are the JS Fundamentals classes?
Class Format
- Silence your friggin' ringtones (please)
- Ask questions (between slides)
- Answer my questions
- Show thumbs
- Ask for help during exercises
- Lunch at some point (unless your phone rings during lecture)
Review: Function Anatomy
Thumbs?
2 ways to make function vars
var spitASickRhyme = function() {
console.log('I\'m in the pursuit of Princess Peach and I know');
console.log('When I think I\'ve won, she\'s in another castle');
};
// function EXPRESSION <(•_•^) and (v•_•)> function DECLARATION
function spitASickRhyme() {
console.log('I\'m in the pursuit of Princess Peach and I know');
console.log('When I think I\'ve won, she\'s in another castle');
}
Hoisting
Let's explore it with live coding!
Scope
- Local
- Global
- Nested Scopes
- Precedence
- Block Scope
SCOPE-RELATED CONCEPTS
Local Scope
var func = function(){
var local = true;
};
console.log(local);
var x = 'global!';
//inside a function
function addToGlobalScope(){
y = 'global here, too!';
}
//inside a function
function addToGlobalScope(){
y = 'global here, too!';
window.z = 'also global!';
// `window` is for browsers only
// (not Node.js)
}
Global Scope
REMEMBER: z and y are not declared until addToGlobalScope is called.
Parent vs Child Scope
var g = 'global';
// Side note: `blender` is in global scope too
function blender(fruit) {
var y = 'yogurt';
function mix() {
alert( fruit + ' and ' + y + ' makes ' +
fruit + ' swirl');
}
mix();
}
blender('blueberry');
What happens when there is a child function nested within a parent function??
creating scopes
When are scopes actually created?
The scope of a function is created when the function is called.
Precedence
var g = "global";
function go() {
var l = "local";
var g = "in here!";
alert(l + " inside local");
alert(g + " inside go");
}
go();
alert(g + " outside go");
Block Scope
var message = 'yes';
for(var i = 0; i < 5; i++){
var message = 'no';
};
console.log('Is there block scope? ' + message);
Questions
Exercise Time!
- Equipment?
- Repo?
- SpecRunner?
- TAs?
- Pairs?
- References:
- Slides
- DevDocs.io
https://github.com/RebootJeff/jsFunctions
Closures
Closure Example #1
var closureAlert = function(){
var x = 'Help! I\'m a variable '+
'stuck in a closure!';
var alerter = function(){
alert(x);
};
alerter();
};
Closure Example #2
var closureAlert = function(){
var x = 0;
var alerter = function(){
x++;
alert(x);
};
return alerter;
};
var alerter1 = closureAlert();
var alerter2 = closureAlert();
alerter1();
alerter2();
Closure Example #3
var add = function(num){
var num1 = num;
var addToNum1 = function(num2){
return num1 + num2;
};
return addToNum1;
};
var addEleven = add(11);
var result = addEleven(22);
console.log(result);
Closure Example: counter
function counter() {
var n = 0;
return {
count: function() { n++; return n; },
reset: function() { n = 0; }
};
};
var c = counter();
var d = counter();
c.count();
d.count();
c.reset();
c.count();
d.count();
Recipe: creation
1. Create your parent function.
2. Define some variables in the parent's local scope.
(they can be accessed by the child function)
3. Define a function inside the parent function.
(aka defining a "child" function or "nested" function)
4. Return that child from inside the parent.
function outerFunc() { var parentVar = "local to parent"; function innerFunc() { return parentVar + ' but accessed by child!'; }; return innerFunc; }
1. 2. 3. 4.
RECIPE: Execution
function outerFunc() {
var parentVar = "local to parent";
function innerFunc() {
return parentVar + ' but accessed by child!';
};
return innerFunc;
}
// STEP 1 - Run the parent function.
var example = outerFunc();
console.log(example);
// We see example now stores the child.
// STEP 2 - Run the child function.
var result = example();
console.log(result);
// What's the end result?
Gotcha!?
var sayAlice = function(){
var makeLog = function() {
console.log(alice);
};
var alice = 'Why hello there, Alice!';
return makeLog;
};
var log = sayAlice();
log();
Example #2,350,987
var makeStopwatch = function(){
var elapsed = 0;
var stopwatch = function(){
return elapsed;
};
var increase = function(){ elapsed++; };
setInterval(increase, 1000);
return stopwatch;
};
var x = makeStopwatch();
Module Pattern - Boilerplate
var Module = function(){
var privateProperty = 'I like big fonts,' +
' and I cannot lie';
function privateMethod(params){
// do something
};
return {
publicProperty: 'JS rulez!!',
publicMethod: function(params){
// do something
},
privilegedMethod: function(params){
privateMethod(args);
}
};
};
Module Pattern - Example
var CarMaker = function(){
var brakeLightsOn = false, seatbeltLocked = false;
function useABS(pressure) {
// 1. Use Electronic Brakeforce Distribution.
// 2. If necessary, activate Stability Control.
// 3. Check if wheels are locking up.
// 4. If necessary, release and re-apply EBD.
}
return {
color: 'blue',
honkHorn: function() {
console.log('HONK!!!');
},
hitBrakes: function(pressure){
brakeLightsOn = true;
seatbeltLocked = true;
useABS(pressure);
}
};
};
Questions
Exercises
Different format & new partners!
Quick Tip: When talking with your partner and TAs, practice using technical terminology. Be specific! Be precise!
var hello;
function foo() { }
var foo = function() {};
foo;
foo();
var woohoo = [1, 2, 3];
woohoo[i]
woohoo[0]
var yay = {
kool: 'aid'
};
kool
'aid'
kool: 'aid'
variable declaration (undefined variable)
function definition/declaration
function definition/expression
function, function reference
function call/invocation
element of woohoo, woohoo-sub-i
first element, woohoo-sub-0
key, property name
value, property value
key-value pair, property of yay
E.g., never say "thing";
specify which element of an array;
mention line numbers.
Higher- Order Functions and Callbacks
1. Take a function as an input (argument)
Higher-Order Functions
var time = 1;
setInterval(function(){
console.log(time++ + ' seconds have passed.');
}, 1000);
2. Return a function as the output
var add = function(num){
var num1 = num;
var addToNum1 = function(num2){
return num1 + num2;
};
return addToNum1;
};
If a function does at least one of the following two things, then it is a baller higher-order function.
Higher-Order Functions
In JavaScript...
"higher-order" functions can exist because
JS treats functions as "first-class objects".
In other words...
functions can be:
- created (defined)
- stored (into variables)
- passed (as arguments)
- returned (by functions)
...just like any other object in JS
(just like numbers, strings, booleans, arrays, etc).
Callbacks
var ifElse = function(condition, isTrue, isFalse){
if(condition){
isTrue();
} else {
isFalse();
}
};
ifElse(true,
function(){ console.log(true);},
function(){ console.log(false);}
);
var ifElse = function(condition, isTrue, isFalse){
if(condition){
isTrue();
} else {
isFalse();
}
};
var logTrue = function(){ console.log(true); };
var logFalse = function(){ console.log(false); };
ifElse(true, logTrue, logFalse);
Passing Arguments
var ifElse = function(condition, isTrue, isFalse){
if(condition){
isTrue(); // no arguments
} else {
isFalse(); // no arguments
}
};
var ifElse = function(condition, isTrue, isFalse, arg){
if(condition){
isTrue(arg); // Look! An argument! Whoa.
} else {
isFalse(arg); // <(^.^<) OMG it's another one.
}
};
Passing Arguments
var increment = function(n){
return n + 1;
};
var square = function(n){
return n*n;
};
var doMathSoIDontHaveTo = function(n, func){
return func(n);
};
doMathSoIDontHaveTo(5, square);
doMathSoIDontHaveTo(4, increment);
[Extra credit]
Passing Arguments
var ifElse = function(condition, isTrue, isFalse){
if(condition){
isTrue.apply(this, [].slice.call(arguments,3));
} else {
isFalse.apply(this, [].slice.call(arguments,3));
}
};
Questions
Exercises
New partners!
(again)
Underscore.js
underscore.js
A utility library that provides functional methods.
WHERE IS IT?
http://underscorejs.org/
ANNOTATED SOURCE:
http://underscorejs.org/docs/underscore.html
_.each() usage
var pocketmons = ['Charisaur', 'Bulbazard', 'Twomew'];
var logger = function(val){
console.log(val);
};
_.each(pocketmons, logger);
//_.each(list, iterator)
aka _.forEach()
_.forEach(pocketmons, logger);
http://underscorejs.org/#each
- Iterates over a list of elements, yielding each in turn to an iterator function.
- 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.
var _ = {};
_.each = function(list, callback) {
if(Array.isArray(list)) {
for(var i = 0; i < list.length; i++) {
callback(list[i], i, list);
}
} else {
for(var key in list) {
callback(list[key], key, list);
}
}
};
_.EACH() DEFINED
Looping with _.each
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
var farm = [];
for(var i = 0; i < animalNames.length; i++){
farm.push(AnimalMaker(animalNames[i]));
}
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
var farm = [];
_.each(animalNames, function (name) {
farm.push(AnimalMaker(name));
});
Nested Looping with _.each()
var studentA = {
firstName: 'Ryan',
lastName: 'Gosling'
};
var classA = {
subject: 'JavaScript',
teacher: '@RebootJeff',
students: [ /* studentA, studentB, etc... */ ]
};
var classes = [ /* classA, classB, etc... */ ];
for(var i = 0; i < classes.length; i++) {
for(var j = 0; j < classes[i].students.length; j++) {
var fullName = classes[i].students[j].firstName +
' ' + classes[i].students[j].lastname;
console.log(fullName);
}
}
_.each(classes, function(class) {
_.each(class.students, function(student) {
var fullName = student.firstName + ' ' + student.lastName;
console.log(fullName);
});
});
How do we print all the names
of all the students
of all the classes?
for(var i = 0; i < classes.length; i++) {
var students = classes[i].students; // This improves readability
for(var j = 0; j < students.length; j++) {
var fullName = students[j].firstName + ' ' + students[j].lastname;
console.log(fullName);
}
}
MUCH easier to read:
var pocketmon = ['Charisaur', 'Bulbazard', 'Twomew'];
var stokedArr = function(val){
return val + '!!!';
};
var stokedPocketmon = _.map(pocketmon, stokedArr);
_.MAP() usage
//_.map(list, iterator)
_.map() defined
var _ = { each: function(/*...*/) { /*...*/ } };
_.map = function(list, iterator) {
var result = []; // make a new array
_.each(array, function(item, index, list) {
result.push(iterator(item, index, list));
});
return result;
};
- Produces a new array of values 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).
Looping with _.map
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
var farm = [];
_.each(animalNames, function (name) {
farm.push(AnimalMaker(name));
});
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
var farm = _.map(animalNames, function (name) {
return AnimalMaker(name);
});
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
// Remember coding WITHOUT Underscore?
var farm = [];
for(var i = 0; i < animalNames.length; i++){
farm.push(AnimalMaker(animalNames[i]));
}
_.map vs _.each
function AnimalMaker(name) {
return {
speak: function () {
console.log("my name is ", name);
}
};
};
var animalNames = ['Frog', 'Falcon', 'Fox'];
// Mapping builds up an array and returns it.
var farm = _.map(animalNames, function (name) {
return AnimalMaker(name);
});
// An each loop returns nothing.
// Just use it to iterate over an array.
_.each(farm, function (animal) {
animal.speak();
});
I want to simply loop through an array or object.
I want a new array based on an existing one.
Questions
Exercises
New partners!
(of course)
Extra Credit is available if you finish early.
Debrief
- each loop vs for loop (simplicity vs flexibility)
- Underscore.js vs Lodash.js vs vanilla JS
- Go check out other Underscore methods/tools!
- Want to be a TA?
- Feedback:
- Difficulty level? Topics?
- Class format? Exercises?
- Organize some study groups amongst yourselves
- ...and don't forget THE MOST IMPORTANT THING!!!
Follow me @RebootJeff (I follow the 80% rule)
Read my words on RebootJeff.com (for coding + career advice)
Follow Bianca @BiancaGando (GDI)
If there is enough time
then we can discuss other topics such as...
- Other JavaScript topics (probably not enough time for these)
- Anonymous Functions vs Named Functions
- Function.call() and Function.apply()
- Context and "this" keyword
- Prototypes, inheritance, etc.
- Other Software Engineering topics
- Privacy and Interfaces
- What does "API" really mean?
- Career stuff
- Hack Reactor
- Life of a software engineer
BUT... there are no slides or prepared materials for these topics.
(Treat this like a Q&A session)
JS Functions 101
By rebootjeff
JS Functions 101
1/11/2015
- 2,269