By the end of this talk, developers should be able to:
- Use block scope to identify which variables are accessible in a function
- Create and invoke functions that take an arbitrary number of arguments
- Create and invoke functions that take reference types as arguments
- Create and invoke functions that return reference types
- Create and invoke functions that take functions as arguments
- Create and invoke functions that return functions
- Fork and clone this repository.
- Create a new branch,
training
, for your work. - Install dependencies with
npm install
.
JavaScript function argument and return values
Scope refers to where variables and functions are accessible.
Block scope means our different scopes are defined by blocks { }
.
// I am not inside a block
if (true) {
// i am inside a block
}
// I am not inside a block
NOT objects but blocks.
if (true) {
// i am inside a block
}
let obj = {
prop1: "I am not inside a block",
prop2: "This is an object silly"
}
The outer most scope is the global scope
and all inner scopes are considered
local scopes
.
// global scope
if (true) {
// local scope
}
// global scope
Variables are accessible within the scope they are declared.
// global scope
if (true) {
// local scope
let x = 1 // what would happen if `var` were used instead?
console.log(x) // 1
// When should we use `console` functions?
}
// global scope
console.log(x) // ReferenceError: x is not defined
They are accessible to any inner scopes (child scopes).
// global scope
let x = 1
if (true) {
// local scope
x = 2
console.log(x) // 2
}
// global scope
console.log(x) // 2
But not to the scopes above them (parent scopes).
// global scope
let x = 1
if (true) {
// local scope
let y = x
console.log(y) // 1
}
// global scope
console.log(x) // 1
console.log(y) // ReferenceError: y is not defined
Variables are not accessible from sibling scopes.
if (true) {
// local scope of 1st sibling
let a = 1
console.log(a) // 1
}
if (true) {
// local scope of 2nd sibling
console.log(a) // ReferenceError: a is not defined
}
Different scopes can have variables that are declared with the same name and they do not conflict or know about each other.
// global scope
const x = 1
console.log(x) // 1
if (true) {
// local scope
const x = 2
console.log(x) // 2
}
// global scope
console.log(x) // 1
So that means a variable declared in the global scope is accessible by all of the scopes we create and a variable declared in a local scope is only accessible to itself and its child scopes.
// global scope
let a = 1
if (true) {
// local scope of 1st nested if statement
let b = 2
if (true) {
// local scope of 2nd nested if statement
let c = 3
console.log(a) // 1
console.log(b) // 2
console.log(c) // 3
}
// local scope of 1st nested if statement
console.log(a) // 1
console.log(b) // 2
console.log(c) // ReferenceError: c is not defined
}
// global scope
console.log(a) // 1
console.log(b) // ReferenceError: b is not defined
console.log(c) // ReferenceError: c is not defined
Conditions are just 1 example of block scope. Loops are another example of block scope.
while (true) { // don't run this
let a = 1
console.log(a) // 1
}
console.log(a) // ReferenceError: a is not defined
For Loops still have block scope even though the syntax is different.
for (let i = 1; i < 2; i++) {
console.log(i) // 1
}
console.log(i) // ReferenceError: i is not defined
Functions are another example of block scope.
const anyFunction = function() {
let a = 1
console.log(a) // 1
}
console.log(a) // ReferenceError: a is not defined
The scope of our parameters are within the function block as well
const print = function(a) {
console.log(a)
}
print(1) // 1
console.log(a) // ReferenceError: a is not defined
Some functions do not have parameters when they are defined and do not need to be passed arguments when they are called.
const printHello = function(){
console.log("Hello World")
}
printHello()
Some functions define 1 or more parameters and expect 1 or more arguments to be passed when called.
const subtract = function(num1, num2){
return num1 - num2
}
subtract(2, 1) // 1
The order of the arguments matter.
const subtract = function(num1, num2){
return num1 - num2
}
subtract(1, 2) // -1
subtract(2, 1) // 1
The type of the arguments matter.
const add = function(num1, num2){
return num1 + num2
}
add(1, 2) // 3
add("cat", 1) // "cat1"
It is up to the developer to know the order and type of arguments a function is expecting.
The arguments passed to a function can be any primitive data types or objects which include objects, arrays, and functions.
// array
const subtract = function(nums){
return nums[0] - nums[1]
}
// number
const add = function(num1, num2){
return num1 - num2
}
subtract( [2, 1] ) // 1
add( 2, 1 ) // 3
In Javascript a function can accept an unlimited number of arguments since
every function has an arguments
object that is a mechanism to handle
arguments not in the function definition. This object is referred to as array like
and is available within any function. We'll examine how this object is
used by creating some seemingly parameterless functions.
const print = function () {
console.log(arguments[0])
}
print() // undefined
print("cat") // "cat"
print(100, 200) // 100
// takes an arbitrary number of arguments (each arg
// should be a number), finds the largest one, and
// returns that member
const max = function () {
}
Could we accomplish something similar using a single argument?
Write a function maxOfArray
that takes an array of numbers and returns the
max.
Reference types passed as arguments can be modified within the functions.
let num = 1
const change = function (num) {
num++
console.log(num)
}
change(num) // 2
console.log(num) // 1
let numbers = [1, 2, 3]
const change = function (numbers) {
numbers.push(4)
console.log(numbers)
}
change(numbers) // [1, 2, 3, 4]
console.log(numbers) // [1, 2, 3, 4]
let person = {
name: "Mike",
age: 100
}
const getOlder = function (person) {
person.age++
console.log(person.age)
}
getOlder(person) // 101
console.log(person.age) // 101
const addProperty = function addProperty(obj, prop, val) {
// this function takes an object and adds a property
// to it
}
Functions are valid arguments. A function that is passed to another function is called a callback.
const add = function (num1, num2){
return num1 + num2
}
const subtract = function (num1, num2){
return num1 - num2
}
const doMath = function (num1, num2, operation) {
return operation(num1, num2)
}
doMath(2,1, add) // 3
doMath(2,1, subtract) // 1
What is a callback? A callback is a function that is passed to another function.
Primitive data types returned are a new instance of the data type
let num = 1
const increase = function (num) {
num++
return num
}
let newNum = change(num)
console.log(newNum) // 2
console.log(num) // 1
Reference types declared within the function that are returned from functions create new instances of that reference type.
const createArray = function () {
let result = []
for (let i = 0; i < arguments.length; i++) {
result[i] = arguments[i]
}
return result
}
let outcome = createArray(1,2,false,true)
console.log(outcome) // [1, 2, false, true]
console.log(result) // ReferenceError: result is not defined
Reference types not declared within the function that are returned from functions are still the same reference type and not new instances.
let numbers = [1, 2, 3]
const change = function (numbers) {
numbers.push(4)
return numbers
}
let newNumbers = change(numbers)
console.log(newNumbers) // [1, 2, 3, 4]
console.log(numbers) // [1, 2, 3, 4]
newNumbers.push(5,6,7)
console.log(newNumbers) // [1, 2, 3, 4, 5, 6, 7]
console.log(numbers) // [1, 2, 3, 4, 5, 6, 7]
Write a function that takes an array of developers and a callback function Loops through the developers to check if they cheated and if they did then applies the correct callback function to adjust their score.
const developer = {
name: "Mike",
late: true,
score: 100
}
const anotherDeveloper = {
name: "Bernard",
late: false,
score: 90
}
const developers = [developer, anotherDeveloper]
const deductForCheating = function (developer) {
developer.score = 0
}
// write a callback that can be passed to runLateScript
// it should have a parameter for a developer object
// to note the late submission was early in the course
const firstWeek = function () {
}
// the function should accept an array of developers
// and two callback functions
const runLateScript = function () {
// loop through the developers array and check who was late
// then pass them as an argument to the correct callback
}
// the function should get passed an array of developers
// and two callback functions
runLateScript()
const createPerson = function (givenName, surname, bornOn, height, weight, eyeColor) {
}
Functions returned from functions generate a closure. Closures provide great utility.
const memoFactory = function (memo) {
let rememberMe = memo
return function () {
console.log(rememberMe)
}
}
let memoOne = memofactory("Hello World")
memoOne() // "Hello World"
Functions returned from functions generate a closure. Closures provide great utility.
const counterFactory = function(count) {
}
Combine the last two concepts and we can have a counting list of memos.
const memoFactory = function (memo) {
let total = 0
return function () {
total+= 1
return total + ": " + memo
}
}
const memo = memoFactory()
const entryMonday = memo("Monday was fun")
const entryTuesday = memo("I liked Tuesday")
const entryWednesday = memo("Ugh Wednesday")
console.log(entryMonday) // "1: Monday was fun"
console.log(entryTuesday) // "2: I liked Tuesday"
console.log(entryWednesday) // "3: Ugh Wednesday"
- All content is licensed under a CCBYNCSA 4.0 license.
- All software code is licensed under GNU GPLv3. For commercial use or alternative licensing, please contact [email protected].