Front/Javascript

함수(Function) - javascript 기본

oodada 2023. 9. 11. 22:23
반응형

1. 함수 선언하기

함수 선언문과 표현식의 차이점
함수 선언문은 호이스팅이 일어나지만, 함수 표현식은 호이스팅이 일어나지 않는다.

// 함수 선언문 (Declaration)
function helloA() {}

// 함수 표현식 (Expression)
const helloB = function () {}

helloA() // 함수 호출
helloB() // 함수 호출

2. 호이스팅이란?

함수 선언문이 코드의 최상단으로 끌어올려지는 것을 말한다.

  • 함수 선언문은 선언하기 전에 호출해도 정상적으로 실행된다.
hello1()

function hello1() {
    console.log('hello1') // hello1
}
  • 하지만, 함수 표현식은 호이스팅이 일어나지 않기 때문에, 함수 표현식을 선언하기 전에 호출하면 에러가 발생한다.
hello2()

const hello2 = function () {
    console.log('hello2') // TypeError: hello2 is not a function
}
  • 함수의 구현 부분은 보통 복잡하기 때문에 위쪽에 위치할 경우 코드의 가독성이 떨어진다.
    따라서 함수의 구현 부분은 아래쪽에 위치하는 것이 좋다.

3. 반환(Return) 및 종료(Exit)

함수는 return 키워드를 사용하여 호출한 곳으로 값을 반환할 수 있다.
return 키워드를 사용하면 함수가 종료된다.

function hello1() {
    return 'Hello' // Hello
    console.log('World~') // 실행되지 않는다.
}

function hello2() {
    return // undefined
}

function hello3() {
    return 1
    return 2 // 실행되지 않는다.
}

function hello4() {
    console.log('1')
    return // undefined
    console.log('2') // 실행되지 않는다.
}

console.log(hello1())
console.log(hello2())
console.log(hello3())
console.log(hello4())

- 예시

function getGrade(score) {
    if (score === 100) {
        return 'A+'
    } else if (score >= 90) {
        return 'A'
    } else if (score >= 80) {
        return 'B'
    } else if (score >= 70) {
        return 'C'
    } else if (score >= 60) {
        return 'D'
    } else {
        return 'F'
    }
}

const grade = getGrade(100)
console.log(grade) // A+

4. 매개변수 패턴

매개변수 (Parameter)는 함수를 호출할 때 값을 지정하여 호출한 곳에서 함수로 값을 전달할 수 있다.
매개변수는 함수 내부에서 변수와 동일하게 취급된다.
매개변수는 함수를 호출할 때 값을 지정하지 않으면 undefined가 할당된다.

- 기본값 (Default Value)

function sum(x, y) {
    return x + y
}

console.log(sum(1, 5)) // 6
console.log(sum(1)) // 1 + undifinde = NaN
  • 함수는 매개변수의 기본값을 설정할 수 있다.
function sum(x, y = 1) {
    return x + y;
}

console.log(sum(1, 5)); // 6
console.log(sum(1)); // 2

- 객체 구조 분해 할당

function ({ a, b }) { console.log(a, b); }

  • 일반적
const user = {
    name: 'winter',
    age: '2',
}

function getName(user) {
    return user.name // user 객체의 name 값을 반환한다.
}

console.log(getName(user)) // winter
// getName 함수는 user 객체를 매개변수로 전달받아 user.name을 반환한다.
  • 위의 코드를 구조 분해 할당을 사용하여 아래와 같이 변경할 수 있다.
const user = {
    name: 'winter',
    age: '2',
}

function getName(user) {
    const { name } = user
    // 구조분해할당을 사용해 user 객체에서 name 값을 추출한다.
    return name // 추출한 name 값을 반환한다.
}

console.log(getName(user)) // winter
  • 더 나아가
const user = {
  name: 'winter',
  age: '2'
  email: 'eehd10@naver.com'
}

function getName({ name }) { // 매개변수에 구조 분해 할당을 사용한다.
    return name; // 추출한 name 값을 반환한다.
}
function getEmail({ email = "이메일이 없습니다." }) { // 매개변수에 구조 분해 할당을 사용한다.
    return email; // 추출한 email 값을 반환한다.
}

console.log(getName(user)); // odada
console.log(getEmail(user)); // 이메일이 없습니다. - user 객체에 email 프로퍼티가 없기 때문에 undefined가 반환된다.

- 배열 구조 분해 할당

function ([ a, b ]) { console.log(a, b); }

  • 일반적
const animals = ['dog', 'cat', 'fish']

function getSecond(array) {
    return array[1] // 배열의 두 번째 요소를 반환한다.
}

console.log(getSecond(animals)) // cat
// getSecond 함수는 animals 배열을 매개변수로 전달받아 animals[1]을 반환한다.
  • 위의 코드를 구조 분해 할당을 사용하여 아래와 같이 변경할 수 있다.
const animals = ['dog', 'cat', 'fish']

function getSecond([, b]) {
    // 매개변수에 구조 분해 할당을 사용한다.
    // const [a, b, c] = array; // 구조분해할당을 사용해 array 배열에서 두 번째 요소를 추출한다.
    return b // 추출한 두 번째 요소를 반환한다.
}

console.log(getSecond(animals)) // cat
// getSecond 함수는 animals 배열을 매개변수로 전달받아 animals[1]을 반환한다.
  • 더 나아가 (기본값 설정)
const animals = ['dog', 'cat', 'fish']
const numbers = [1, 2, 3]

function getSecond([, b = '두 번째 요소가 없습니다.']) {
    // 매개변수에 구조 분해 할당을 사용한다.
    return b // 추출한 두 번째 요소를 반환한다.
}

console.log(getSecond(animals))
// 두 번째 요소가 없습니다. - animals 배열에 두 번째 요소가 없기 때문에 undefined가 반환된다.

console.log(getSecond(numbers)) // 2
// getSecond 함수는 numbers 배열을 매개변수로 전달받아 numbers[1]을 반환한다.

- 나머지 매개변수 (Rest Parameters)

나머지 매개변수는 매개변수 이름 앞에 ...을 붙여서 사용하고 함수에 전달된 인수들의 목록을 배열로 전달받는다.

  • 개념
function sum(...rest) {
    console.log(rest)
    // return이 없으면 undefined가 반환된다.
}

console.log(sum(1, 2)) // [1, 2]
console.log(sum(1, 2, 3, 4)) // [1, 2, 3, 4]
console.log(sum(1, 2, 3, 4, 5, 6, 7, 8)) // [1, 2, 3, 4, 5, 6, 7, 8]

// a, b를 매개변수에 추가하여 상태 확인
  • 배열 데이터의 모든 숫자를 더하는 로직
function sum(...rest) {
    // 매개변수 rest는 인수들의 목록을 배열로 전달받는다.
    console.log(rest)
    // return이 없으면 undefined가 반환된다.

    return rest.reduce(function (account, current) {
        // reduce 메소드는 배열의 첫 번째 요소부터 순차적으로 접근하며, reduce 함수의 반환값은 누적된 결과값이다.
        // reduce 메소드는 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수를 반복 호출한다.
        // account는 누적된 결과값이고, current는 현재 요소이다.
        return account + current // 배열의 모든 요소를 더하여 반환한다.
    }, 0) // reduce 메소드의 두 번째 인수는 초기값이다. 초기값을 생략하면 배열의 첫 번째 요소가 초기값이 된다.
}

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

5. 화살표 함수 (Arrow Function)

화살표 함수는 function 키워드 대신 =>를 사용하여 좀 더 간략한 방법으로 함수를 선언할 수 있고
익명이기 때문에 함수 표현식으로만 사용할 수 있다.

화살표 함수의 기본 문법

() => { ... } // 매개변수가 없을 경우
x => { ... } // 매개변수가 한 개인 경우, 소괄호를 생략할 수 있다.
(x, y) => { ... } // 매개변수가 여러 개인 경우, 소괄호를 생략할 수 없다.
function helloWorld1() {} // 함수 선언문
const helloWorld2 = function () {} // 함수 표현식
// 화살표 함수는 항상 익명이기 때문에 화살표 함수를 호출하려면 함수 표현식을 사용해야 한다.
const helloWorld3 = () => {
    console.log('hello!')
} // 화살표 함수 ES6 (ECMAScript 2015)

helloWorld1() // hello!
helloWorld2() // hello!
helloWorld3() // hello!

sum 함수에 적용

// const sum = (a, b) => { // 매개변수가 여러 개인 경우, 소괄호를 생략할 수 없다.
//    return a + b;
//}
const sum = (a, b) => a + b // 중괄호를 생략하면 return 문도 생략할 수 있다.

console.log(sum(1, 2)) // 3

화살표 함수의 다양한 예시

// 매개변수가 없는 경우
const a = () => {}
// 매개변수가 한 개인 경우
const b = (x) => {}
// 매개변수가 여러 개인 경우
const c = (x, y) => {}
// 함수의 리턴이 있는 경우
const d = (x) => {
    return x * x
}
// 함수의 리턴이 있는 경우, 중괄호 생략
const e = (x) => x * x
// return 키워드로 시작하지 않는 경우, 중괄호 생략하면 안된다.
const f = (x) => {
    console.log(x * x)
    return x * x
}

// 객체데이터 반환하는 경우
const g = () => {
    return { a: 1 }
}
// const h = () => { a: 1 };
// 객체데이터의 중괄호를 화살표 함수의 중괄호와 구분하기 위해 소괄호를 사용한다.
const h = () => ({ a: 1 })

// 배열데이터 반환하는 경우
const i = () => {
    return [1, 2, 3]
}
const j = () => [1, 2, 3]

6. 호출 스케줄링 (Scheduling)

setTimeout

setTimeout(함수, 시간, ...인수)

  • setTimeout은 일정 시간이 지난 후 함수를 실행한다.
  • setTimeout은 함수를 호출하면서 타이머를 설정, 인수를 전달할 수 있다.
  • clearTimeout을 통해 타이머를 취소할 수도 있다.
const hello = () => {
    console.log('Hello')
}

setTimeout(hello, 3000) // 3초 후에 timer 함수를 실행한다.

clearTimeout

clearTimeout(타이머)

  • setTimeout 함수의 타이머를 취소할 수 있다.
const hello = () => {
    console.log('Hello')
}

const timerOut = setTimeout(hello, 2000) // 2초 후에 hello 함수를 실행한다.

const h1El = document.querySelector('h1') // h1 요소를 찾는다.
h1El.addEventListener('click', () => {
    console.log('취소되었습니다.')
    clearTimeout(timerOut) // h1 요소를 클릭하면 setTimeout을 취소한다.
})

setInterval, clearInterval

setInterval(함수, 시간, ...인수)
clearInterval(타이머)

  • setInterval은 일정 시간 간격으로 함수를 실행한다.
const hello = () => {
    console.log('Hello')
}

const timerOut = setInterval(hello, 2000) //  2초마다 hello 함수를 실행한다.
const h1El = document.querySelector('h1') // h1 요소를 찾는다.
h1El.addEventListener('click', () => {
    console.log('취소되었습니다.')
    clearInterval(timerOut) // h1 요소를 클릭하면 타이머를 취소한다.
})

7. 콜백(Callback)

콜백 함수란 함수를 인수로 전달받아 특정 시점에 호출하는 함수이다.

  • 콜백은 함수를 다른 함수의 인수로 사용할 때 사용한다.
  • 콜백은 함수를 호출한 곳으로 전달된다.
  • 콜백은 함수를 호출한 곳에서 필요한 시점에 호출된다.

개념

const a = (callback) => {
    callback()
    console.log('A')
}

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

a(b) // B A
// 콜백 함수는 함수를 호출한 곳으로 전달되기 때문에 a() 함수 내부에서 callback()을 호출하면 b() 함수가 호출된다.
// b() 함수는 a() 함수를 호출한 곳에서 필요한 시점에 호출된다.

예시 - 1초 후에 콜백 함수를 호출하는 함수

  • a, b를 인수로 전달받아 a + b를 반환하는 함수
const sum = (a, b) => {
    return a + b
}

console.log(sum(1, 2)) // 3
console.log(sum(4, 12)) // 16
  • 위 코드에서 setTimeout 함수(1초 후에 콜백 함수)를 추가
  • sum 함수는 setTimeout()의 실행을 기다리지 않고 즉시 실행을 완료하고 반환한다.
const sum = (a, b) => {
    // setTimeout(() => {}, 1000) setTimeout 함수 실행시에도 콜백을 사용했다.

    setTimeout(() => {
        return a + b
    }, 1000)
}
// sum 함수는 'setTimeout' 함수가 실행되기 전에 반환되므로
// sum 함수의 반환값은 undefined가 된다.

console.log(sum(1, 2)) //  undefined
console.log(sum(4, 12)) // undefined
  • 위 코드를 수정하여 콜백 함수를 사용

a와 b는 더할 두 숫자이고, c는 콜백 함수입니다.
setTimeout() 함수 내부에서 a와 b를 더한 후, 그 결과를 콜백 함수 c에 인자로 전달하여 호출합니다.

const sum = (a, b, c) => {
    setTimeout(() => {
        return c(a + b) // 콜백 함수를 호출 (a + b)의 결과값을 c함수의 인수로 전달한다.
    }, 1000)
}

sum(1, 2, (value) => {
    console.log(value) // 3 - 콜백 함수를 호출하면서 인수로 3을 전달한다.
})
sum(4, 12, (value) => {
    console.log(value)
})

8. 재귀 (Recursive)

재귀 함수는 함수 내부에서 자기 자신을 호출하는 함수이다.

  • 재귀 함수는 반복문을 대체할 수 있다.
  • 재귀 함수는 반드시 종료 조건을 만들어야 한다.
const a = () => {
    console.log('a')
    a() // 자기 자신을 호출한다.
}

a() // 무한 호출되니까 저장하지 마삼~
  • 재귀 함수는 자기 자신을 호출하기 때문에 반드시 종료 조건을 만들어야 한다.
let i = 0
const a = () => {
    console.log('A')
    i++
    if (i < 4) {
        a()
    }
}

a() // a가 4번 호출된다.

예시

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

const getRootUser = (user) => {
    // getRootUser 함수는 user 객체를 인수로 전달받는다.
    if (user.parent) {
        // user 객체에 parent 프로퍼티가 있으면
        return getRootUser(user.parent) // 재귀 호출
    }
    return user // user 객체에 parent 프로퍼티가 없으면 user를 반환한다.
}

console.log(getRootUser(userD)) // { name: 'A', parent: null }

9. this

this는 함수를 어떻게 호출하느냐에 따라서 this가 가리키는 대상이 달라진다.

  • 일반 함수는 호출 위치에서 this가 결정된다.
  • 화살표 함수는 자신이 선언된 함수 범위에서 this가 결정된다.

일반 함수의 this

  • 일반 함수는 호출 위치에서 this가 결정된다.
// fullname 출력하는 함수
const obj = {
    firstName: 'winter',
    lastName: 'Kim',
    getFullName: function () {
        // 일반 함수로 호출
        //getFullName() { // 위 코드 축약
        retrun`${this.firstName} ${this.lastName}` // this는 obj를 가리킨다.
    },
}

console.log(obj.getFullName()) // winter Kim

화살표 함수의 this

  • 위 코드의 getFullName 메소드의 일반 함수를 화살표 함수로 변경하면
  • 호출 위치가 함수가 아닌 객체이기 때문에 undefined가 출력된다.
  • 화살표 함수의 this는 자신이 선언된 함수에서 결정되기 때문이다.
const obj = {
    firstName: 'winter',
    lastName: 'Kim',
    getFullName: () => {
        // 일반 함수를 화살표 함수로 변경하면
        return `${this.firstName} ${this.lastName}` // this는 자신이 선언된 함수에서 결정되기 때문에
    },
}

console.log(obj.getFullName()) // undefined undefined 가 출력된다.
  • 화살표 함수의 this는 자신이 선언된 함수에서 결정되기 때문에
  • 객체를 함수로 만들어 호출 위치를 함수로 변경해준다.
function user() {
    // user 함수 내에서 속성을 정의하고, 객체를 반환한다.
    // 이 속성들은 함수 내에서 변수처럼 사용된다.
    // this 키워드를 사용하여 함수 객체의 속성으로 설정한다.
    this.firstName = 'fall'
    this.lastName = 'Jeong'

    return {
        firstName: 'winter',
        lastName: 'Kim',
        getFullName: () => {
            return `${this.firstName} ${this.lastName}` // this는 user 함수 범위에서 결정된다.
            // 따라서 getFullName의 this는 user 함수가 호출될 때의 this를 가리키게 됩니다.
        },
    }
}

const u = user()
console.log(u.getFullName()) // fall Jeong
// user 함수의 getFullName 메소드를 바로 호출할 수 없어서 user 함수를 호출하여 user 객체를 반환받고,
// user 객체의 getFullName 메소드를 호출한다.
반응형
티스토리 친구하기