절차지형 언어의 경우 함수나 변수가 선언되는 위치가 굉장히 중요하다. 자바스크립트 또한 절차지향언어의 하나이다. 따라서 sub-programing이 중요하다.

자바스크립트는 class가 추가되어서 OOP라고 할 수 있지만 순수한 OOP는 아니고 prototype를 활용한 가짜 OOP이다.

함수

  • 프로그램을 구성하는 기본적인 building block
  • sub-program이라고도 불리며 재사용이 가능함
  • 한가지 작업이나 값을 계산하기 위해서 사용된다
  • 하나의 함수는 반드시 한개 의 작업만 실행해야 한다!!!
  • 자바스크립트에서 함수는 오브젝트 이다(나중에 일급함수로 사용되는걸 같이 보자)

함수 선언식

function name(param1, param2) { body ... return}

함수이름은 현재형 동사를 사용하는 것이 권장된다 (ex: doSomething, checkSomething)

function printHello() {
  console.log('Hello World!')
}
printHello() // 'Hello World!'

function printMessage(message) {
  console.log(message)
}
printMessage('Hi there!') // 'Hi there!'
// 타입스크립트의 경우 함수선언식의 파라미터뒤에 타입을 붙인다
function name(param: String): number {
  return value // must be number type
}

// 기본인자(ES6에 추가)
function showMessage(message, from='kim') {
  console.log(`${message}, by ${kim}`)
}
showMessage('hello') // 'hello, by kim'

// 나머지 인자(ES6에 추가)
function printAll(...args) {
  // 1.
  for (let i = 0; i < args.length; i++) {
    console.log(args[i])
  }
  // 2.
  for (const arg of args) {
    console.log(arg)
  }
  // 3.
  args.forEach((arg) => console.log(arg))
}
printAll('dream', 'comes', 'true') // dream comes true

스코프

Closure, lexical environment를 위해선 꼭 알아야 함.

알아야 할 하나의 원칙: **밖에서는 안이 보이지 않고 안에서만 밖을 볼 수 있다**

let globalMessage = 'global' // global variable
function printMessage() {
  let message = 'hello' // local variable
  function printAnother() {
    const childMessage = 'child'
    console.log(message) // 'hello'
  }
	console.log(childMessage) // Error!
}

Early return, early exit

// good
function upgradeUser(user) {
  if (user.point <= 10) {
    return;
  }
  // upgrade logics...
}

// bad
function upgradeUser(user) {
  if (user.point > 10) {
    // upgrade logics...
  }
}

함수표현식

const print = function () {}

  • 변수에 함수를 할당하는 형태로 쓴다.
  • 함수의 이름이 없이 필요한 부분만 작성하므로 anonymous function이라고도 한다.
  • 만일 이름을 붙인다면 named function이라고 부른다.
const print = function () { console.log('print') }
print() // 'print'
const printAgain = print
printAgain() // 'print'

함수표현식의 경우 호이스팅의 적용을 받지 않는다. 따라서 선언되는 위치가 중요하다!

콜백함수

function randomQuiz(answer, printYes, printNo) {
  if (answer === 'correct') {
    printYes()
  } else {
    printNo()
  }
}

const printYes = function() { console.log('Yes!') }
const printNo = function print() { console.log('No!') }
// named function은 디버깅 시 사용된 함수의 이름이 보인다는 장점이 있다
// 또한 재귀호출이 가능하게 하는 장점이 있다

randomQuiz('wrong', printYes, printNo) // 'Yes!'
randomQuiz('correct', printYes, printNo) // 'No!'

화살표함수

const arrowFunction = () => {}

  • 화살표 함수는 익명함수이다.
  • ES6에 추가된 기능이다.
  • 다른 함수와 다르게 화살표 함수는 this 를 가지지 않는다. (global한 this를 쓰지 않고 블록 스코프를 따른다)

기본구문

const arrowFunction = (param1, param2) => { statements } // statement를 실행할 때
const arrowFunction = (param1, param2) => { return expression } // 값을 반환할 때
const arrowFunction = (param1, param2) => expression  // 바로 위의 함수와 같은 기능을 한다

// 매개변수가 하나뿐인 경우 괄호의 생략이 가능하다
const arrowFunction = (param1) => { statements }
const arrowFunction = param1 => { statements }

// 매개변수가 없더라고 괄호가 필요하다
const arrowFunction = () => { statements }

// 객체 리터럴을 반환하는 경우 함수 본문(body)을 괄호 속에 넣어야 한다.
const arrowFunction = () => ({ key: 'value' }) // O
// 괄호가 없으면 {} 안에 있는 내용은 해석할 '문장'으로 취급한다. 주의!
const arrowFunction = () => { key: 'value' } // X

// 기본매개변수와 나머지매개변수를 지원한다
const arrowFunction = (param1, ...arr) => { statement }
const arrowFunction = (param1, param2 = 'defaultValue') => { statement }

다음과 같이 활용할 수 있다.

const simplePrint = function () { console.log('simple print') }
const simplePrint = () => console.log('simple print')
// 위의 두 표현식은 동일한 기능을 한다.

const add = (a, b) => a + b;
const multiply = (a, b) => {
  return a * b;
}

IIFE: Immediately Invoked Function Expression

(function hello() {
  console.log('hello IIFE')
})()
// 함수 자체를 괄호로 묶고 함수 뒤에 괄호를 넣어주면 함수가 바로 실행된다
// 요즘은 많이 쓰이지 않는 추세이나 함수를 작성하고 바로 실행결과를 보고 싶을 때 유용하다!