01. 함수 : 선언적 함수

JavaScript에서 함수는 프로그램 내에서 재사용 가능한 코드 블록을 나타내는 중요한 개념입니다.
함수를 사용하면 특정 작업을 수행하는 코드를 논리적으로 묶어서 호출하고 실행할 수 있습니다.
이를 통해 코드의 재사용성을 증가시키고 유지보수를 용이하게 만들 수 있습니다.
함수는 자체 스코프 내에서 변수를 선언하고, 매개변수를 통해 입력을 받아 작업을 수행하며, 결과를 반환할 수 있습니다.

{
    function func(){
        console.log("실행되었습니다.");
    }

    func();
}

선언적 함수는 function 키워드를 사용하여 정의된 함수로 가장 기본적인 형태의 함수이다.

결과 확인하기
실행되었습니다.

02. 함수 : 익명 함수

익명함수는 이름없이 정의된 함수로, 함수 선언 시 함수의 이름이 없는 함수이다.
익명함수는 주로 다른 함수의 매개변수로 전달하거나 변수에 할당되어 사용되는 경우가 많다.

{
    const func = function (){
        console.log("실행되었습니다.");
    }
    func();
}

익명 함수는 이름이 없기 때문에 해당 함수에 직접 접근하거나 호출할 수 없다.
함수를 사용하려면 변수에 함수를 선언하고 할당하여 그 변수를 통해 함수를 호출해야 합니다.
익명 함수는 코드 내에서 필요한 곳에 동적으로 함수를 생성하고 사용하는 데에 유용하다.

결과 확인하기
실행되었습니다.

03. 함수 : 매개변수가 있는 함수

매개변수가 있는 함수는 함수 정의 시 함수 내에서 사용할 변수들을 지정하는 것을 말한다.
이렇게 정의된 매개변수들은 함수가 호출될 때 전달된 값들과 연결되어 함수 내부에서 사용된다.

{
    function func(str){
        console.log(str);
    }
    func("실행되었습니다.");
}

매개변수는 함수를 실행할 때 매개변수(parameter)에 값을 넣어 그 값을 함수에 대입시켜 실행하는 함수이다.
func함수를 설정할 때 str이라는 매개변수를 입력하도록 설정해서 func함수를 실핼할 때 ()안에 값을 넣어준 모습이다.

결과 확인하기
실행되었습니다.

04. 함수 : 리턴값 함수

리턴값(결과 or 종료)이 있는 함수는 return 제어문을 사용해서 함수의 연산 결과 중 원하는 값을 지정해서 호출위치로 복구시키는 기능이다.

{
    function  func(){
        return "실행되었습니다."
    }
    console.log(func());

    //리턴값함수 + 익명함수
    const func1 = function(){
        const x = 200;
        return x;
    }
    console.log(func1());
}

함수를 실행하다가 return을 만나면 거기서 함수를 탈출해 값을 내오는데, return에 x만 있으므로 함수를 실행하면 x값만 나오는 모습이다.

결과 확인하기
실행되었습니다.
200

05. 함수 : 매개변수 함수 + 리턴값 함수

함수끼리 응용하여 하나의 모습으로도 나타날 수 있다.

{
    function func(str){
        return str;
    }
    console.log(func("실행되었습니다."));

    // 매개변수 함수 + 리턴값 함수 + 익명 함수
    const func1 = function(str){
        return str;
    }
    console.log(func1(실행되었습니다.));
}

매개변수 함수와 리턴값 함수를 응용한 것으로,
매개변수 str을 return하여 결과값으로 내보내는 모습이다.

결과 확인하기
실행되었습니다.
실행되었습니다.

06. 화살표 함수 : 선언적 함수

선언적 함수를 화살표 함수로의 변형

{
    func = () => {
        console.log("실행되었습니다.");
    }
    func();
}

function 으로 함수를 선언하는 대신에 = () => {}으로 대신하였다.

결과 확인하기
실행되었습니다.

07. 화살표 함수 : 익명 함수

익명 함수를 화살표 함수로의 변형

{
    const func = () => {
        console.log("실행되었습니다.")
    }
    func();
}

익명 함수를 화살표 함수로 변환한 것으로,
원래 모습은 const func = function(){}이지만 function을 생략하고
= () => {}으로 대신 하였다.

결과 확인하기
실행되었습니다.

08. 화살표 함수 : 매개변수가 있는 함수

매개변수가 있는 함수를 화살표 함수로의 변형

{
    func = (str) => {
        console.log(str);
    }
    func("실행되었습니다.");
}

매개변수가 있는 함수를 화살표 함수로 변형한 것으로 선언적 함수와 다른 점은 소괄호 안에 매개변수가 있다는 것이다.
이 매개변수는 함수를 실행시킬 때 괄호안에 원하는 값을 넣어 실행시켜 그 값을 함수안에 대입시켜 실행한다.

결과 확인하기
실행되었습니다.

09. 화살표 함수 : 리턴값 함수

리턴값 함수를 화살표 함수로의 변형

{
    func = () => {
        return "실행되었습니다."
    }
    console.log(func());
}

return이 있는 함수를 화살표 함수로 변형시킨 것으로
함수가 실행되다가 return을 만나면 그 값을 결과값으로 내오고 함수를 종료시킨다.
func()의 return에 "실행되었습니다"가 있으므로, 이 함수의 값으로 내온다.
다만 값으로 내올뿐 출력하는 실행문이 없기때문에 consloe로 보려면 console.log(func()); 이렇게 호출해야 한다.

결과 확인하기
실행되었습니다.

10. 화살표 함수 : 익명 함수 + 매개변수 + 리턴값

익명 함수 + 매개변수 + 리턴값을 합친것의 화살표 함수로의 변형

{
    //익명함수
    const func2 = (str) => {
        return str;
    }
    console.log(func2("실행되었습니다."));

    //괄호 생략
    const func3 = str => {
        return str;
    }
    console.log(func3("실행되었습니다."));

    // 리턴 생략
    const func4 = str => str;

    console.log(func4("실행되었습니다."));

    // 선언적
    func5 = str => str;

    console.log(func5("실행되었습니다."));
}

const func = (x) => { return str; }는 익명 + 매개변수 + 리턴값 함수를 합친 것으로 const로 익명함수가 있다는것을,
(str)를 보고 매개변수함수 return을 보고 리턴값 함수가 들어 있는 것을 알 수 있다.
또한 매개변수가 한개일 땐 하나 더 생략이 가능한데 매개변수가 들어가는 ()를 생략 가능하다.
리턴값의 return도 생략이 가능하며 익명함수의 const도 생략이 가능하긴 한데, 여기까지 생략해 버리면 가독성이 떨어져 추천하지는 않는다.

결과 확인하기
실행되었습니다.
실행되었습니다.
실행되었습니다.
실행되었습니다.

11. 함수 유형 : 함수와 매개변수를 이용한 형태

매개변수를 함수에 대입시킨 형태

{
    function func(num, str){
        console.log(num + ". " + str);
        console.log(`${num}. ${str}`);
    }
    func(11, "함수가 실행되었습니다.");
}

num과 str을 매개변수로 가져와 함수를 호출할 때 입력하였다.
console.log(`${num}. ${str}`);에서 ``을 사용하면 변수와 문자열을 합칠 때마다 +를 사용 안해된다.

결과 확인하기
11. 함수가 실행되었습니다.

12. 함수 유형 : 함수의 변수를 이용한 형태

변수를 함수에 적용

{
    const num = 12;
    const str = "함수가 실행되었습니다.";

    function func(num, str){
        console.log(`${num}. ${str}`);
    }
    func(num, str);
}

미리 만들어둔 변수를 함수에 적용하여 호출하는 방법이다.
변수 num과 str이 만들어져 있는 상태에서 호출할 때 불러왔다.

결과 확인하기
12. 함수가 실행되었습니다.

13. 함수 유형 : 함수와 배열을 이용한 형태

함수에 배열을 불러오기

{
    const num = [13, 14];
    const str = ["함수가 실행되었습니다.", "함수가 실행되었습니다."];
    function func(num, str){
        console.log(`${num}. ${str}`);
    }
    func(num[0], str[0]);
    func(num[1], str[1]);  
}

num과 str은 배열로 불러오는 방법은 크게 다르지 않다.
함수를 호출할 때 원하는 배열의 위치를 함수의 괄호안에 넣어서 적용할 수 있다.

결과 확인하기
13. 함수가 실행되었습니다. 14. 함수가 실행되었습니다.

14. 함수 유형 : 함수와 객체를 이용한 형태

함수에 객체 불러오기

{
    const info = {
        num: 15,
        str: "함수가 실행되었습니다."
    }
    function func(num, str){
        console.log(`${num}. ${str}`);
    }
    func(info.num, info.str);
}

info는 객체로 info.num에 15가 info.str에 함수가 실행되었습니다. 라는 데이터가 들어있다.
이를 함수를 호출할 때 입력하여 함수가 실행될 때 적용되도록 하였다.

결과 확인하기
15. 함수가 실행되었습니다.

15. 함수 유형 : 함수와 객체 및 배열을 이용한 형태

함수에 배열과 객체가 섞인 데이터를 불러오기

{
    const info = [
        {num: 16, str: "함수가 실행되었습니다."},
        {num: 17, str: "함수가 실행되었습니다."},
    ]
    function func(num, str){
        console.log(`${num}. ${str}`);
    }
    func(info[0].num, info[0].str);
    func(info[1].num, info[1].str);
}

info[0].num에 16, info[0].str에 함수가 실행되었습니다.
info[1].num에 17, info[1].str에 함수가 실행되었습니다. 라는 데이터가 들어있다.
이를 호출할 때도 원하는 값을 함수를 실행할 때 입력시켜 호출할 수 있다.

결과 확인하기
16. 함수가 실행되었습니다. 17. 함수가 실행되었습니다.

16. 함수 유형 : 객체 안에 함수를 이용한 형태

객체 안에 함수

{
    const info = {
        num: 18,
        str: "함수가 실행되었습니다.",
        result: () => {
            console.log(`${info.num}. ${info.str}`);
        }
    }
    info.result();
}

함수와 객체가 따로있는 상태가 아닌, 객체 안으로 함수가 들어가 있는 형태이다.
함수를 호출하려면 객체를 호출하는 방법과 함수호출방법을 섞어야 하는데
. 뒤에 함수가 들어있는 키값을 입력 후 ()를 붙여서 호출한다.

결과 확인하기
18. 함수가 실행되었습니다.

17. 함수 유형 : 객체 생성자 함수

객체 생성자 함수

{
    function Func(num, str){
        this.num = num;
        this.str = str;
        this.result = () => {
            console.log(`${this.num}. ${this.str}`);
        }
    }
    // 인스턴스 생성
    const info1 = new Func(19, "함수가 실행되었습니다.");
    const info2 = new Func(20, "함수가 실행되었습니다.");

    // 호출
    info1.result();
    info2.result();
}

함수안에 객체를 넣은 듯한 형태로 함수생성, 인스턴스 생성, 호출이 이루어진다.
이때 함수 내부에서 사용되는 매개변수일 시 Func대신 this로 사용이 가능하다.
매개변수의 값은 인스턴스에 입력할 수 있다.

결과 확인하기
19. 함수가 실행되었습니다. 20. 함수가 실행되었습니다.

18. 함수 유형 : 프로토타입 함수

프로토타입 함수

{
    function Func(num, str){
        this.num = num;
        this.str = str;
    }
    Func.prototype.result = function(){             // 함수를 밖으로 빼면 화살표 함수 불가
        console.log(`${this.num}. ${this.str}`);
    }

    // 인스턴스 생성
    const info1 = new Func(21, "함수가 실행되었습니다.");
    const info2 = new Func(22, "함수가 실행되었습니다.");

    // 호출
    info1.result();
    info2.result();
}

객체 생성자 함수에서 필요한 함수를 계속 선호하는것이 번거로워 생긴것으로
함수를 따로 밖으로 빼내어 porototype으로 함수를 만든 것이다.
단 함수를 밖으로 빼내면 화살표 함수로 함수 선언이 불가능하다.

결과 확인하기
21. 함수가 실행되었습니다. 22. 함수가 실행되었습니다.

19. 함수 유형 : 객체 리터럴 함수

객체 리터럴 함수

{
    function Func(num, str){
        this.num = num;
        this.str = str;
    }
    Func.prototype = {
        result1: function(){
            console.log(`${this.num}. ${this.str}`);
        },
        result2: function(){
            console.log(`${this.num}. ${this.str}`);
        }
    }
    const info1 = new Func(23, "함수가 실행되었습니다");
    const info2 = new Func(24, "함수가 실행되었습니다");

    info1.result1();
    info2.result2();
}

프로토타입 함수의 가시성을 보완한 것이다.
Func은 두 개의 매개변수 num과 str을 받는 생성자 함수이다.
이 함수가 호출될 때, this.num과 this.str 프로퍼티에 인자로 전달된 값들을 할당한다.
Func 생성자 함수의 프로토타입 객체에 result1과 result2라는 두 개의 메서드를 추가한다.
이 메서드들은 this.num과 this.str을 사용하여 콘솔에 메시지를 출력한다.
info1.result1()을 호출하면 result1 메서드가 실행된다.
info1.result2()을 호출하면 result2 메서드가 실행된다.

결과 확인하기
23. 함수가 실행되었습니다. 24. 함수가 실행되었습니다.

20. 함수 : 즉시실행함수

즉시실행함수

{
    (function(){
        console.log("25. 함수가 실행되었습니다.");
    })();

    (() => {
        console.log("26. 함수가 실행되었습니다.");
    })();
}

함수를 정의하고 즉시 실행하는 방식으로
따로 호출하지 않아도 괄호로 둘러싼 익명 함수는 정의되자마자 즉시 실행된다.

결과 확인하기
25. 함수가 실행되었습니다.
26. 함수가 실행되었습니다.

21. 함수 : 파라미터 함수

파라미터 함수

{
    function func(str = "27. 함수가 실행되었습니다."){
        console.log(str);
    }
    func();

    const func1 = (str = "28. 함수가 실행되었습니다.") => {
        console.log(str);
    }
    func1();
}

기본 매개변수 값을 사용하여 함수를 정의하는 방법으로
매개변수에 값이 전달되지 않았을 때 사용할 기본 값을 정의하는 데 유용하다.
기본 매개변수를 사용하면 함수를 호출할 때 필요한 매개변수를 생략하거나 값을 전달하지 않았을 때 기본값을 사용하여 함수가 예상대로 동작하도록 할 수 있다.

결과 확인하기
27. 함수가 실행되었습니다.
28. 함수가 실행되었습니다.

22. 함수 : 재귀함수

자기 자신을 호출하는 함수

{
    function func1(num){
        if(num < 1) return;

        console.log("30. 함수가 실행되었습니다.");
        func1(num - 1);
    }
    func1(10);
}

num이 1미만이 되면 함수가 종료되도록 되어있는데,
이를 함수 내부에서 자신을 다시 호출하고 num - 1을 하여 num의 값이 변화하도록 하였다.

결과 확인하기
30. 함수가 실행되었습니다.
30. 함수가 실행되었습니다.
30. 함수가 실행되었습니다.
30. 함수가 실행되었습니다.
30. 함수가 실행되었습니다.
30. 함수가 실행되었습니다.
30. 함수가 실행되었습니다.
30. 함수가 실행되었습니다.
30. 함수가 실행되었습니다.

23. 콜백함수

다른 함수로 실행되는 함수

{
    // 23-1. 이벤트 콜백함수
    function func(){
        console.log("31. 함수가 실행되었습니다.");
    }
    btn.addEventListener("click", func());

    // 23-2. 함수를 다른 함수의 인자로 전달
    function func1(){
        console.log("32. 함수가 실행되었습니다.")
    }
    function func2(callback){
        callback();
    }
    func2(func1);

    // 23-3. 반복문으로 콜백함수 만들기
    function func3(num){
        console.log(num + ". 함수가 실행되었습니다.");
    }
    function func4(callback){
        for(let i=33; i<=38; i++){
            callback(i);
        }
    }
    func4(func3);
}

23-1은 함수를 정의한 후 해당 이벤트가 발생시 실행되도록 하였고,
23-2는 func1을 정의한 후 func2를 실행시키면 func1이 실행되도록 정의하였다.
23-3은 func4 함수가 func3 함수를 반복해서 호출하여 숫자와 함께 메시지를 출력하도록 되어있다.

결과 확인하기
31. 함수가 실행되었습니다.
32. 함수가 실행되었습니다.
33. 함수가 실행되었습니다.
34. 함수가 실행되었습니다.
35. 함수가 실행되었습니다.
36. 함수가 실행되었습니다.
37. 함수가 실행되었습니다.
38. 함수가 실행되었습니다.

24. 함수 : 비동기함수 - 콜백 함수

비동기 함수를 콜백함수로 구현

{
    // 24-1 동기적인 함수 호출
    function func1(){
        console.log("39. 함수가 실행되었습니다.");
    }
    function func2(){
        console.log("40. 함수가 실행되었습니다.");
    }
    func1();
    func2();

    // 24-2 비동기적인 함수 호출
    function func3(){
        setTimeout(() => {
            console.log("41. 함수가 실행되었습니다.");
        }, 1000);
    }
    function func4(){
        console.log("42. 함수가 실행되었습니다.");
    }
    func3();
    func4();

    // 24-3 비동기적인 콜백 함수 호출
    function func5(callback){
        setTimeout(() => {
            console.log("43. 함수가 실행되었습니다.");
            callback();
        }, 1000);
    }
    function func6(){
        console.log("44. 함수가 실행되었습니다.");
    }
    func5(function(){
        func6();
    });
    
    //콜백 지옥
    function funcA(callback){
        setTimeout(() => {
            console.log("funcA가 실행되었습니다.");
            callback();
        }, 1000);
    }
    function funcB(callback){
        setTimeout(() => {
            console.log("funcB가 실행되었습니다.");
            callback();
        }, 1000);
    }
    function funcC(callback){
        setTimeout(() => {
            console.log("funcC가 실행되었습니다.");
            callback();
        }, 1000);
    }
    function funcD(){
        setTimeout(() => {
            console.log("funcD가 실행되었습니다.");
        }, 1000);
    }

    funcA(function(){
        funcB(function(){
            funcC(function(){
                funcD();
            });
        });
    });
}

일반적으로 함수를 호출하면 24-1처럼 순차적으로 실행되어
39. 함수가 실행되었습니다.
40. 함수가 실행되었습니다.
이렇게 나오는데, 만약 비동기 방식으로 호출이 된다면 먼저 로딩이 되는 순서대로 나오므로,
24-2처럼 func4가 먼저 실행되어
42. 함수가 실행되었습니다.
41. 함수가 실행되었습니다.
이렇게 나오게된다. 이를 방지하고자 순서대로 호출하려면 func5에 func6을 콜백함수로 넣어 func5가 실행된 후 func6이 실행되도록 할 수 있다.
근데 구조가 단순하면 상관없지만 복잡해지면 콜백지옥처럼 가독성이 안좋아진다.

결과 확인하기
39. 함수가 실행되었습니다.
40. 함수가 실행되었습니다.
42. 함수가 실행되었습니다.
41. 함수가 실행되었습니다.
43. 함수가 실행되었습니다.
44. 함수가 실행되었습니다.
funcA가 실행되었습니다.
funcB가 실행되었습니다.
funcC가 실행되었습니다.
funcD가 실행되었습니다.

25. 함수 : 비동기 함수 - 프로미스

프로미스

{
    let data = true;

    const func = new Promise((resolve, reject) => {
        if(data){
            resolve("45. 함수가 실행되었습니다.");
        } else {
            reject("45. 함수가 실행되지 않았습니다.");
        }
    });

    func
        .then(
            result => console.log(result)
        )
        .catch(
            error => console.log(error)
        )

    콜백 지옥 -> 프로미스
    function funcA(){
        return new Promise((resolve) => {
            setTimeout(() => {
                console.log("funcA가 실행되었습니다.")
                resolve();
            }, 1000);
        })
    }
    function funcB(){
        return new Promise((resolve) => {
            setTimeout(() => {
                console.log("funcB가 실행되었습니다.")
                resolve();
            }, 1000);
        })
    }
    function funcC(){
        return new Promise((resolve) => {
            setTimeout(() => {
                console.log("funcC가 실행되었습니다.")
                resolve();
            }, 1000);
        })
    }
    function funcD(){
        return new Promise((resolve) => {
            setTimeout(() => {
                console.log("funcD가 실행되었습니다.")
                resolve();
            }, 1000);
        })
    }
    funcA()
        .then(funcB)
        .then(funcC)
        .then(funcD)
        .catch((error) => {
            console.log(error)
        })
}

첫 번째 코드 블록에서, func라는 Promise를 생성합니다. data가 true인 경우 resolve를 호출하여 성공 상태로 설정하고, 그렇지 않은 경우 reject를 호출하여 실패 상태로 설정합니다.
그런 다음 .then과 .catch를 사용하여 해당 Promise가 성공하거나 실패했을 때 실행할 작업을 정의
두 번째 코드 블록에서, funcA, funcB, funcC, 및 funcD라는 비동기 함수가 정의됩니다. 각 함수는 1초 동안 대기한 후 로그를 출력하고 resolve를 호출하여 Promise를 완료
그런 다음 funcA().then(funcB).then(funcC).then(funcD)를 사용하여 각 함수가 연속적으로 실행되도록 연결합니다. 이러한 함수는 하나가 완료되면 다음 함수가 실행됩니다.
이를 통해 콜백 지옥을 피하고 코드를 더 읽기 쉽게 만든다.

결과 확인하기
45. 함수가 실행되었습니다.
funcA가 실행되었습니다.
funcB가 실행되었습니다.
funcC가 실행되었습니다.
funcD가 실행되었습니다.

26. 함수 : 비동기 함수 : async/await

async/await

{
    // 26-1
    function func(){
        console.log("46. 함수가 실행되었습니다.");
    }
    func();

    // 26-2
    async function func2(){
        console.log("47. 함수가 실행되었습니다.");
    }
    func2();

    // 26-3     에러 발생시 잡아내기 불가
    async function func3(){
        const result = await fetch("https://webstoryboy.github.io/webstoryboy/w_json/gineungsaShort.json")
        const data = await result.json();
        console.log(data)
    }
    func3();

    // 26-4    에러가 발생시 잡아낼 수 있음
    async function func4(){
        try {
            const result = await fetch("https://webstoryboy.github.io/webstoryboy/w_json/gineungsaShort.json")
            const data = await result.json();
            console.log(data)
        } catch (error){
            console.log(error);
        }
    }
    func4();
}

26-1: 간단한 동기 함수입니다. func 함수를 호출하여 "46. 함수가 실행되었습니다."라는 메시지를 콘솔에 출력합니다.
26-2: async 함수인 func2를 정의합니다. async 함수 내에서 await를 사용하지 않았으므로 이 함수는 동기 함수와 유사하게 동작합니다.
func2 함수를 호출하여 "47. 함수가 실행되었습니다." 메시지를 콘솔에 출력합니다.
26-3: async 함수인 func3를 정의합니다. 이 함수에서는 fetch를 사용하여 원격 JSON 데이터를 요청하고 await를 사용하여 결과를 기다립니다.
이러한 방식으로 코드가 비동기로 동작하며, await가 사용된 위치에서 해당 작업이 완료될 때까지 기다립니다.
그러나 이 함수에서는 에러를 캐치하지 않아서 네트워크 요청 중 에러가 발생하면 코드는 실패합니다.
26-4: async 함수인 func4를 정의합니다. 이 함수는 에러 처리를 위해 try...catch 블록을 사용합니다.
따라서 네트워크 요청 중 에러가 발생하면 catch 블록 내의 코드가 실행되고 에러 메시지가 콘솔에 출력됩니다.

결과 확인하기
46. 함수가 실행되었습니다.
47. 함수가 실행되었습니다.
data
data