가쟤의 해변일기 🐳

[Javascript] 함수 본문

Front-end

[Javascript] 함수

바닷가쟤 2023. 7. 18. 22:44

 

함수 선언문 (Declaration)

function hello () {

}

 

함수 표현식 (Expresstion)

const hello = function () {}
// 할당 연산자로 함수를 할당함.

hello() //호출

 

호이스팅이라는 개념에서 차이가 발생한다.

 

호이스팅 (Hoisting)

function hello() {
  console.log('hello~')
}

hello()

// 호출하는 위치에 상관 없이 출력 됨. -> 아직 정의되지 않은 함수도 !
// 유효 범위 내에서 가장 상단으로 끌어올려 동작함.

→  함수 선언문에서만 동작. 함수 표현식은 X

(자주 사용) 함수 선언문에서 호출 부분을 위에 적는 이유 :

추상적인 부분을 위쪽에 적어서 전체적 코드 흐름을 빠르게 파악하기 쉽게 하고

자세한 코드 내용(함수의 구현부)은 아래쪽에 위치하면 깔끔하게 작성할 수 있다.

 


매개변수 패턴 (parameter patten)

function getEmail({email = '이메일이 없습니다'}) {
  return email
}

=(이퀄기호)로 기본값을 설정할 수 있다. (값이 없을 때 출력할 값)

const { email } = user // <- 구조분해 할당
function getEmail({ email }){} // 이렇게 바꿔줄 수 있다.

 


나머지 매개변수 (Rest parameter)

function sum(...rest) {
  console.log(rest)
  console.log(arguments)  // 유사 배열 (Array-like) 배열이 아니라 reduce 못 씀
  return rest.reduce(function(acc, cur) {
    return acc + cur
  }, 0) // 0 이 기본값
}

console.log(sum(1, 2))  // 3
console.log(sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))  // 55

.reduce()배열 데이터의 item 개수만큼 콜백 함수를 실행한다.

acc : 값이 누적되는 파라미터 → 처음 반복할 땐 0 ( ,0 ← 기본값으로 설정해서)

cur : 현재 값 → 반복되는 첫 번째 값

return acc로 들어감 (두 번째 반복)


화살표 함수 (Arrow function)

function sum() {}
const sum = function() {}
const sum = () => {}  // 이게 화살표 함수다!

const sum = (a, b) => a + b  // { return a + b } 와 같다.
console.log(sum(1,2))

파라미터가 1개면 소괄호를 생략할 수 있다. (없거나 2개 이상이면 생략 불가능)

첫 번째 로직이 return 키워드로 시작하면 중괄호를 생략할 수 있다.

const a = () => ({a: 1})

객체 데이터면 중괄호라 잘못 해석되는 것을 방지하기 위해서 소괄호로 다시 묶어주면 데이터 취급!

 


즉시 실행 함수 (IIFE, Immediately-Invoked Function Expression)

const a = 7

const double = () => {
  console.log(a * 2)
}
double()  // 14

;(() => {
  console.log(a * 2)
})()  // 14

소괄호를 뒤에 붙여 즉시 실행되게 하는 함순데 자세히 알아보자.

;(() => {})()        // (F)()
;(function () {})()    // (F)()
;(function () {}())    // (F())
;!function () {} ()    // !F()
;+function () {} ()    // +F()

이런 여러 형태로 즉시 실행 함수를 구현할 수 있다. 

앞에 세미콜론을 붙이는 이유는 즉시 실행 함수의 바로 전 코드에서 세미콜론을 무조건 붙여줘야 정상 작동하기 때문이다.

 


콜백 (Callback)

const a = (callback) => {  // 2. a 함수의 매개변수(callbak)은 b
  console.log('a')
  callback() // b 호출 (callback = b)
}

const b = () => {
  console.log('b')
}

a(b) // 1. a 함수에 b를 매개변수로 설정

주석으로 코드 흐름 순서를 달아뒀다.

const sum = (a, b, c) =>{
  setTimeout(() => {
    c(a + b)
  }, 1000)
}

sum(1, 2, (value) => {
  console.log(value)  // 다른 함수가 호출될 때 인수로 사용되는 함수
})

코드를 스스로 작성할 수 있을만큼 연습해야 할 것 같다. 아직은 로직 이해정도..?

1초 뒤에 파라미터 둘을 더한 값을 콘솔에 출력한다. 콜백함수를 활용해서 만든 함수다. 

const loadImage = (url, cb) => {
  const imgEl = document.createElement('img')
  imgEl.src = url
  imgEl.addEventListener('load', () => { // 콜백 함수
    setTimeout(() => { //콜백 함수
      cb(imgEl)
    }, 1000)
  })
}

const containerEl = document.querySelector('.container')
loadImage('https://www.gstatic.com/webp/gallery/4.jpg', (imgEl) => { // 콜백 함수
  containerEl.innerHTML = ''
  containerEl.append(imgEl)
})

새 이미지가 1초 뒤에 로드되는 함수다.

 


재귀(Recursive)

let i = 0

const a = () => {
  console.log('A')
  i += 1
  if (i < 4) {  // 멈출 수 있는 조건 추가
    a()
  }
}

a()

함수에서 자기 자신을 다시 내부에서 호출해 사용하는 방법이다.

0, 1, 2, 3 으로 총 4번 a가 콘솔에 출력된다. (if문이 console.log 이후에 작성되어 있음)

const userA = { name: 'A', parent: null }
const userB = { name: 'B', parent: userA }
const userC = { name: 'C', parent: userB }

const getRootUser = (user) => {
  if (user.parent) {
    return getRootUser(user.parent)
  }
  return user
}

console.log(getRootUser(userC))

이 코드를 보고 반복문이 생각났다.

반복문이 있는데 왜 이런 방식으로 사용하는거지? 

재귀와 반복문의 차이를 알아보겠다.

일단, 반복문 만으로 풀기 어려운 문제가 있다고 한다. (DFS, DP, Combination 등)

 

### 반복문

- 명령을 반복 실행
- 초기화, 조건, 루프 내 명령문 실행과 제어 변수 업데이트 포함
- 설정한 조건 도달 시까지 반복 실행
- 무한 루프는 CPU 사이클을 반복적으로 사용
- 스택 메모리를 사용하지 않음
- 빠른 실행
- 코드 길이가 길어지고 변수가 많아져 가독성이 떨어짐

### 재귀함수

- 함수 자체를 호출
- 종료 조건만 지정 (조건이 추가될 수도 있음)
- 함수 호출 본문에 조건부가 포함, 재귀를 호출하지 않고 함수를 강제 반환
- 조건에 수렴하지 않을 경우 무한 재귀 발생
- 무한 재귀는 스택 오버플로우 발생
- 스택 메모리 사용 : 함수가 호출 될 때마다 새 로컬 변수와 매개 변수 집합, 함수 호출 위치를 저장하는데 사용
- 느린 실행
- 코드 길이와 변수가 적어 가독성이 좋음

이럼에도 재귀 함수를 사용하는 이유

  1. 알고리즘이 재귀적 표현이 더 자연스러울 경우 재귀함수 사용이 유용하다.
  2. 변수 사용을 줄일 수 있고 가독성이 향상된다.

호출 스케줄링 (Scheduling a function call)

const hello = () => {
  console.log('hello~')
}

const timeout = setTimeout(hello, 1000)

const h1El = document.querySelector('h1')
h1El.addEventListener('click', () => {
  console.log('clear!')
  clearTimeout(timeout)
})

호출되는 시간을 조절할 수 있다. 

clear로 호출되는 시간 전에 호출을 중지할 수도 있다.

 


this

const timer = {
  title: 'TIMER!',
  timeout: function () {  // 일반 함수
    console.log(this.title)
    setTimeout(() => {    // 화살표 함수
      console.log(this.title)
    }, 1000)
  }
}

timer.timeout()

this는 함수에 따라 범위가 다르다.

일반 함수의 this는 호출 위치에서 정의하고, 화살표 함수의 this는 자신이 선언된 함수(렉시컬) 범위에서 정의한다.

 

 

728x90