# Defining Functions

• Provide:
1. Function name
2. Parameter names
3. Body
• No parameter, return types:
```function average(x, y) {
return (x + y) / 2
}```
• What if the arguments aren't numbers?
```const result = average('6', '7') // Whatever happens, happens
```
• `return` exits the function immediately:
```function indexOf(arr, value) {
for (const i in arr) {
if (arr[i] === value) return i
}
}```
• If a function exits without `return`, it returns `undefined`

# Higher-Order Functions

• Functions are values:
• Can store functions in variables.
• Can pass functions to functions.
• Can return functions from functions.
• `(...)` operator invokes function:
```let f = average
const result = f(6, 7) // `result` is 6.5
f = Math.max
result = f(6, 7) // `result` is 7
```
• `map` method takes a function parameter:
`result = [0, 1, 2, 4].map(Math.sqrt) // `result` is `[0, 1, 1.4142135623730951, 2]``

# Function Literals

• Tedious to make functions for small jobs:
```function multiplyBy10(x) { return x * 10 }
result = [0, 1, 2, 4].map(multiplyBy10)
```
• Remedy—function literal:
```result = [0, 1, 2, 4].map(function (x) { return 10 * x })
```
• No need for named functions:
`const average = function (x, y) { return (x + y) / 2 }`

# Arrow Functions

• Compact form for function literals:
`const average = (x, y) => (x + y) / 2`
• Parentheses optional for single parameter:
`const multiplyBy10 = x => x * 10`
• Empty parentheses if no parameters:
`const dieToss = () => Math.trunc(Math.random() * 6) + 1`
• Use block and `return` for complex bodies:
```const indexOf = (arr, value) => {
for (const i in arr) {
if (arr[i] === value) return i
}
return undefined
}```
• Caution: Use parentheses when returning object literal:
```const stats = (x, y) => ({
average: (x + y) / 2,
max: Math.max(x, y),
...
})```

# The Power Of Functional Thinking

• `map` applies a function and collects the results:
```const enclose = (tag, contents) => `<\${tag}>\${contents}</\${tag}>`
const listItems = items.map(i => enclose('li', i))```
• Actually, we should remove blank items:
• ```const listItems = items
.filter(i => i.trim() !== '')
.map(i => enclose('li', i))
```
• Now put everything in an `ul` element:
• ```const list = enclose('ul',
items
.filter(i => i.trim() !== '')
.map(i => enclose('li', i))
.join(''))
```
• No loop!
• What, not how.

# Closures

• `setTimeout` executes an action some milliseconds in the future:
`setTimeout(() => console.log('Goodbye'), 10000)`
• Let's make this more flexible:
```function sayLater(text, when) {
const task = () => console.log(text)
}```
• How does `text` in the arrow expression stay around?
• The arrow body runs long after `sayLater` returned.
• The nested function captures all variables that it needs.
• Closure:
1. A block of code
2. Parameters
3. “Free” variables—declared outside the function
• The arrow expression also captures `console`.
• In JavaScript, the variable is captured:
```let text = 'Goodbye'
setTimeout(() => console.log(text), 10000)
text = 'Hello' // After 10 seconds, displays `Hello````

# Hard Objects

• Objects + function values + closures = OO.
```function createAccount() {
...
return {
deposit: amount => { ... },
withdraw: amount => { ... },
getBalance: () => ...
}
}```
• Create any number of accounts:
```const harrysAccount = createAccount()
const sallysAccount = createAccount()
sallysAccount.deposit(500)```
• Where is the data?
```function createAccount() {
let balance = 0
return {
deposit: amount => { `balance` += amount },
...
}
}```

# Supplying Fewer Arguments

• Missing argument? Parameter is `undefined`:
```function average(x, y) {
return y === undefined ? x : (x + y) / 2
}```
• Alternate solution—default argument.
• Used when no argument (or `undefined`) is supplied in a call.
```function average(x, y = x) {
return (x + y) / 2
}```
• Multiple default arguments ok:
```function average(x = 0, y = x) {
return (x + y) / 2
}```

# Supplying More Arguments

• Extra arguments are ignored:
```const result = average(3, 4, 5)
```
• Capture in rest parameter:
```function average(...args) {
let sum = 0
for (x of args) sum += x
return sum / Math.max(1, args.length)
}```
• What if the arguments are already in an array (or any iterable)?
```const numbers = [3, 4, 5]
const result = average(numbers) // Error!
```
```const result = average(...numbers)
```
• Spread also works inside array literals:
```const clone = [...numbers]
const characters = [...'Hello 🌐']
```

# Simulating Named Arguments with Destructuring

• No named arguments in JavaScript functions.
• Simulate with object literal:
`mkString(array, { leftDelimiter: '(', rightDelimiter: ')' })`
• In implementation, look up properties and supply defaults:
```function mkString(array, config = {}) {
if (config.separator === undefined) config.separator = ','
...
}```
• Neat trick: Use destructuring.
```function mkString(array,
{ separator = ',', leftDelimiter = '[', rightDelimiter = ']' } = {}) {
...
}```
• Defines three parameter variables `separator`, `leftDelimiter`, and `rightDelimiter`.
• Each has a default value.
• Note the default `{}` if no configuration is supplied.

# Throwing Exceptions

• Use `throw value` to throw an exception.
• Can throw a value of any type.
• Customary to throw an object produced by `Error` function:
```function indexOf(arr, value) {
if (!Array.isArray(arr)) throw Error('indexOf: arr not an array')
for (const i in arr) {
if (arr[i] === value) return i
}
return undefined
}```
• `throw` terminates current function and its callers.
• Transfers control to enclosing `catch` or `finally`
• Exceptions are intended for failures that may need to be handled upstream, not the immediate caller.
• Example: JSON from server doesn't parse.
• What can the caller of `JSON.parse` do about it?

# Catching Exceptions

• Simple form of `try` statement:
```try {
Do work
} catch (e) {
Handle exceptions
}```
• Variable `e` contains exception value.
• Conventionally an `Error` object.
• Methods `name` and `message`
• `name` is `Error`, `SyntaxError`, `ReferenceError`, and so on.
• Tip: Don't analyze the exception object.
• `console.log(e)` also shows the stack trace.
• Ok to rethrow:
```try {
// Do work ...
} catch (e) {
console.log(e)
throw e
}```

# The `finally` Clause

• Intended for managing resources:
```try {
// Acquire resources ...
// Do work ...
} finally {
// Relinquish resources ...
}```
• Can even have `try`/`catch`/`finally`
• Caution: Avoid `return`/`break`/`throw` in `finally` clause.
```try {
// Do work ...
return true
} finally {
return false // Error—masks `true` return value
}```

# Hoisting

• Scope of local variable/function: From declaration to end of block.
```{ // Start of block
... // Attempting to access `someVariable` throws a `ReferenceError`
let someVariable // Scope starts here
... // Can access `someVariable`, value is `undefined`
someVariable = 42
... // Can access `someVariable`, value is 42
} // End of block, scope ends here```
• Not quite so simple:
```{
function doWork() {
console.log(someVariable) // Ok to access variable
...
}
let someVariable = 42
doWork() // Prints 42
}```
• Variable is “hoisted” to enclosing block.
• “Temporal dead zone” from beginning of block to declaration.
• Hoisting isn't all bad—can call a function before it was declared:
```function isEven(n) { return n == 0 ? true : !isOdd(n -1) }
function isOdd(n) { return n == 0 ? false : !isEven(n -1) }
```

# Tagged Template Literals

• Tagged template literal: Template literal prefixed by function name.
`greeting = String.raw`Hello C:\Windows\System``
• Template literals have embedded expressions:
`message = `Next year, \${person.name} will be \${person.age + 1}.``
• Tagged template function gets the pieces: n + 1 strings followed by n arguments.
```function strong(fragments, ...values) {
let result = fragments[0]
for (let i = 1; i < fragments.length; i++)
result += `<strong>\${values[i - 1]}</strong>\${fragments[i]}`
return result
}```
• In the call
`strong`Next year, \${person.name} will be \${person.age + 1}.``
the `strong` function is called as
`strong(['Next year, ', ' will be ', '.'], 'Harry', 43)`
• `fragments.raw` is an array of fragments in which `\` is only an escape character for ``` and `\$`.