JavaScript Fundamentals:
Slides:
https://slides.com/rebootjeff/js-functions
Classwork:
https://github.com/RebootJeff/jsFunctions
Original Curriculum by:
Bianca Gandolfo
Edited and Presented by:
Jeff Lee
Basics of Functions
and Hoisting
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');
}
// function expression
var haveFun = function() {};
// function declaration
function learnJS() {}
// variable declaration
// and assignment
var greeting = 'hello, world';
if(false) {
var jeffIsAmazing = 'duh';
}
// declarations
var haveFun;
function learnJS() {}
var greeting;
var jeffIsAmazing;
// definitions
// and assignments
haveFun = function() {};
greeting = 'hello, world';
if(false) {
jeffIsAmazing = 'duh';
}
console.log(jeffIsAmazing);
// will log `undefined`
Let's explore through live coding!
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)
}
REMEMBER: z and y are not declared until addToGlobalScope is called.
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??
When are scopes actually created?
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");
var message = 'yes';
for(var i = 0; i < 5; i++){
var message = 'no';
};
console.log('Is there block scope? ' + message);
JavaScript only has LEXICAL scoping
Lexical Scoping = Function Scope with Nesting
https://github.com/RebootJeff/jsFunctions
var closureAlert = function(){
var x = 'Help! I\'m a variable '+
'stuck in a closure!';
var alerter = function(){
alert(x);
};
alerter();
};
var closureAlert = function(){
var x = 0;
var alerter = function(){
x++;
alert(x);
};
return alerter;
};
var alerter1 = closureAlert();
var alerter2 = closureAlert();
alerter1();
alerter2();
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);
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();
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.
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?
var makeLog = function(){
var sayAlice = function() {
console.log(alice);
};
var alice = 'Why hello there, Alice!';
return sayAlice;
};
var log = makeLog();
log();
var makeStopwatch = function(){
var elapsed = 0;
var stopwatch = function(){
return elapsed;
};
var increase = function(){ elapsed++; };
setInterval(increase, 1000);
return stopwatch;
};
var x = makeStopwatch();
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);
}
};
};
var makeNewCar = 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);
}
};
};
Different format & new partners!
Quick Tip: When talking with your partner and TAs, practice using technical terminology. Be specific! Be precise!
var hello;
hello = 'hiiii!';
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)
assignment (value assigned to 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.
and Callbacks
1. Take a function as an input (argument)
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.
In JavaScript...
"higher-order" functions can exist because
JS treats functions as "first-class objects".
In other words...
functions can be:
...just like any other object in JS
(just like numbers, strings, booleans, arrays, etc).
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);
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.
}
};
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);
New partners!
(again)
A utility library that provides functional methods.
Where is it?
http://underscorejs.org
Annotated Source:
http://underscorejs.org/docs/underscore.html
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
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);
}
}
};
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));
});
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:
Simplicity vs Flexibility
var arr = ['a', 'b', 'c'];
for(var i = arr.length - 1; i >= 0; i--) {
// do stuff with elements in reverse order
}
for(var i = 0; i < arr.length; i += 2) {
// do stuff with even-indexed elements
}
each
for
var pocketmon = ['Charisaur', 'Bulbazard', 'Twomew'];
var stokedArr = function(val){
return val + '!!!';
};
var stokedPocketmon = _.map(pocketmon, stokedArr);
//_.map(list, iterator)
var _ = { each: function(/*...*/) { /*...*/ } };
_.map = function(list, iterator) {
var result = []; // make a new array
_.each(list, function(item, index, list) {
result.push(iterator(item, index, list));
});
return result;
};
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]));
}
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.
New partners!
(of course)
Extra Credit is available if you finish early.
Follow @RebootJeff
Read words on RebootJeff.com
(for coding + career advice)
then we can discuss other topics such as...
BUT... there are no slides or prepared materials for these topics.
(Treat this like a Q&A session)