배꼽파지 않도록 잘 개발해요

[코드잇] 모던 자바스크립트 ① 모던 자바스크립트 이해, 동작원리, 함수 다루기 본문

코드잇 Codeit/Front-End

[코드잇] 모던 자바스크립트 ① 모던 자바스크립트 이해, 동작원리, 함수 다루기

꼽파 2023. 12. 14. 15:52


 

  • 1. 모던 자바스크립트 이해하기

  • 2. 자바스크립트의 동작 원리

  • 3. 함수 다루기

  • 1. 모던 자바스크립트 이해하기

    모던 자바스크립트에 대한 이해

    ECMAScript : 자바스크립트 표준 명세서 (JavaScript Specification)
    ·  'Standard ECMA-262'라는 이름으로 관리되고 있음.
    · ES1 : 1997년에 등장
    · ES6 : 2015년에 등장 (정식 명칭 : ES2015)
    · 웹브라우저가 당장 새로운 버전의 문법을 지원하지 않음. → 최신 버전을 바로 적용하는 것이 힘듦.
    · 보편적으로 사용되는 브라우저들이 지원하는 범위 내에서 ECMA스크립트를 준수하는 것이 일반적임.
    Modern JavaScript : 현시점에 사용하기 적합한 범위 내에서 최신 버전의 표준을 준수하는 자바스크립트


    2. 자바스크립트의 동작 원리

    데이터 타입의 특징과 종류

    자바스크립트의 데이터타입 특징

    • Python : 데이터 타입이 다른 변수끼리는 연산 불가능 (ex. 2 + "3")
    C, Java : 변수에도 데이터 타입을 지정, 타입이 정해진 변수에 다른 타입은 지정 불가
    Javascript :

    - 데이터타입이 다른 경우도 연산 가능
      ex. 2 + "3" = "23" (숫자 + 문자열 = 문자열)
      숫자 2를 문자열 2로 인식해서 문자열끼리의 연산으로 계산함.

    // + 연산자 : 문자열 연결을 수행
    // 나머지 산술 연산자 : 숫자 간에만 작동
    
    a = 2 + "3"
    console.log(a)  // 23
    console.log(typeof(a))  // string
    
    b = 2 * "3"
    console.log(b)  // 6
    console.log(typeof(b))  // number
    
    c = 2 / "3"
    console.log(c)  // 0.6666666666666666
    console.log(typeof(c))  // number
    
    d = 2 - "3"
    console.log(d)  // -1
    console.log(typeof(d))  // number


    - 변수에 따로 타입을 정해주지 않기 때문에 언제든지 다양한 타입의 값으로 재할당이 가능함.

    let x = 0;
    
    x = 'Codeit';
    x = false;
    x = null;
    x = undefined;
    x = {};


    자바스크립트에서는 데이터 타입에 대한 이해가 중요함.
    내가 작성한 코드가 어떤 타입의 데이터인지 알고 있어야 예상치 못한 결과로 오류 나는 상황을 피할 수 있음.

     

    자바스크립트 데이터타입 종류

    • 기본형 (Primitive Type) : Number, String, Boolean, Symbol, BigInt, Null, Undefined
    - Symbol : (ES2015) 유일한 값을 만들 때
    - BigInt : (ES2020) 엄청 큰 숫자를 다룰 때
    • 참조형 (Reference Type) : Object


    Symbol과 BigInt

    Symbol

    코드 내 유일한 값을 가진 변수 이름을 만들 때 사용

    const user = Symbol();
    const user = Symbol('this is a user');
    const symbolA = Symbol('apple');
    const symbolA = Symbol('banana');
    // SyntaxError: Identifier 'symbolA' has already been declared


    해당 symbol 값을 담은 변수는 다른 어떤 값과 비교해도 true가 될 수 없음.

    user === 'user' // false
    user === 0; // false
    user === null; // false
    user === undefined; // false


    symbol의 설명이 같아도 두 값을 비교하면 false가 나옴.

    const symbolA = Symbol('apple');
    const symbolB = Symbol('apple');

     

    BigInt

    매우 큰 연산을 다루거나 정확한 연산이 필요한 상황의 큰 정수를 표현
    자바스크립트의 숫자형(number type) 값에는 9000조 정도의 정수 표현의 한계가 존재
    → 이 숫자 범위를 초과하는 정숫값 사용시에는 연산에 미세한 오류가 발생
    이유 : 배정밀도 부동소수점 형식 숫자체계를 사용하기 때문 (IEEE 754)

    표현방식

    일반 정수 마지막에 'n'을 붙이기 또는 'BigInt' 함수 사용

    console.log(9007199254740993n); // 9007199254740993n
    console.log(BigInt(9007199254740993)); // 9007199254740993


    특징
    소수 표현에는 사용할 수 없어서 소수점 아랫부분이 절삭됨.

    8.3n; // SyntaxError
    6n / 4n; // 1n


    BigInt 타입끼리만 연산 가능함.
    다른 타입끼리 연산하려면 명시적 형변환이 필요함.

    8n * 3; // TypeError
    4n * 5n; // 20n
    Number(5n) * 2; // 10

    typeof 연산자

    사용하는 값이 어떤 데이터타입을 나타내는지 알려주는 연산

    typeof(NaN);  // 괄호로 감싸기
    typeof NaN;  // 한칸 띄우기

    * NaN
    - 연산 과정에서 잘못된 입력을 받았음을 나타내는 기호
    - 특히 부동소수점 연산에서 사용

    typeof 'Codeit'; // string
    typeof Symbol(); // symbol
    typeof {}; // object
    typeof []; // object
    typeof true; // boolean
    typeof(false); // boolean
    typeof(123); // number
    typeof(NaN); // number
    typeof(456n); // bigint
    typeof(undefined); // undefined
    typeof(null)); // object

     

    자바스크립트의 처음 구현단계에서 값은 타입 태그와 값으로 표시되었음.
    객체의 타입 태그가 0이라서 null은 Null pointer(대부분의 플랫폼에서 0x00)로 표시되면서, 타입 태그로 0을 가졌음.
    이후 typeof null === 'null'으로 수정이 제안되었으나 버그 우려로 거절됨.

    // 함수의 데이터타입 : function
    // 자바스크립트의 함수는 객체로 취급하나 데이터타입은 function임.
    function greekyogurt() {
      console.log('i love it');
    }
    console.log(typeof greekyogurt); // function

    Falsy값과 Truthy값

    자바스크립트의 조건문에서는 boolean이 아닌 다른 타입의 값들도 boolean으로 평가됨.

     

    Falsy값
    - false로 평가되는 값
    - false, null, undefined, NaN, 0, ''(빈 문자열)

    Truthy값
    - True로 평가되는 값
    - 나머지 값들
    [](빈배열), {}(빈 객체)

    console.log(Boolean(-123))  // true
    console.log(Boolean([]))  // true
    console.log(Boolean(''))  // false
    console.log(Boolean({}))  // true
    const fruits = ['apple', 'banana', 'orange', 'peach'];
    
    for (let i = 3; i; i = i - 1) {
      console.log(fruits[i]);
    }
    
    /*
    i = 3 --> peach
    i = 2 --> orange
    i = 1 --> banana
    i = 0 --> falsy값으로 평가되어서 반복문 종료됨.
    */

    AND와 OR 연산 방식

    상황에 따라서 어떤 값들을 선택하는 방식으로 동작함.

    console.log('Codeit' && 'JavaScript');  // JavaScript
    // 왼쪽 문자열이 truthy해서 오른쪽 값 반환


    AND 와 OR 연산자 사이에서는 AND 연산자의 우선순위가 더 높음.

    console.log(true || false && false); // true
    console.log((true || false) && false); // false
    
    console.log('Codeit' || NaN && false); // Codeit
    console.log(('Codeit' || NaN) && false); // false

     

    AND 연산자 (&&)
    왼쪽값이 truthy하면 오른쪽 값을 리턴함.
    왼쪽값이 falsy하면 왼쪽값을 리턴함.

    console.log(true && true); // true (오른쪽)
    console.log(true && false);  // false
    console.log(false && true);  // false
    console.log(false && false);  // false (왼쪽)

     

    OR 연산자 (||)
    왼쪽값이 truthy하면 왼쪽 값을 리턴함.
    왼쪽값이 falsy하면 오른쪽 값을 리턴함.

    console.log(true || true); // true (왼쪽)
    console.log(true || false); // true
    console.log(false || true); // true
    console.log(false || false); // false (오른쪽)


    이런 방식을 조건식처럼 활용할 수 있음.

    function print(eat) {
    const message = eat || 'apple';
    console.log(message);
    }
    
    print();  
    print('JavaScript');
    // print()함수에 파라미터를 빈 값으로 두어서 print()함수 안 eat 변수에는 빈 값이 들어감.
    // (falsy값 || truthy값) 이므로 truthy값인 'apple'이 리턴됨.


    https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Operator_precedence

     

    연산자 우선순위 - JavaScript | MDN

    연산자 우선순위는 연산자를 실행하는 순서를 결정합니다. 우선순위가 높은 연산자가 먼저 실행됩니다.

    developer.mozilla.org


    null 병합 연산자??

    null 병합 연산자(Nullish coalescing operator)
    · 왼쪽 피연산자가 null 또는 undefined일 때 오른쪽 피연산자를 반환하고, 그렇지 않으면 왼쪽 피연산자를 반환하는 논리 연산자
    · falsy값인지 여부는 고려하지 않음.

    // 예시 1
    const alternative1 = '' ?? 'Programming';  // ''(빈문자열)
    const alternative2 = 0 ?? 'is';  // 0
    const alternative3 = false ?? 'fun';  // false (boolean)
    
    console.log(alternative1, alternative2, alternative3); 
    // 0 false
    
    // 예시 2
    const alternative4 = undefined ?? 'Programming'; 
    const alternative5 = null ?? 'is';  
    const alternative6 = undefined ?? 'fun';  // false (boolean)
    
    console.log(alternative4, alternative5, alternative6); 
    // Programming is fun

     

    왼쪽이 null 또는 undefined가 아님이 판명되면 오른쪽 표현식은 평가되지 않음. (출처 : mdn)

    function A() {
      console.log("A was called");
      return undefined;
    }
    function B() {
      console.log("B was called");
      return false;
    }
    function C() {
      console.log("C was called");
      return "foo";
    }
    
    console.log(A() ?? C());
    // logs "A was called" then "C was called" and then "foo"
    // as A() returned undefined so both expressions are evaluated
    
    console.log(B() ?? C());
    // logs "B was called" then "false"
    // as B() returned false (and not null or undefined), the right
    // hand side expression was not evaluated

    변수와 스코프

    var 키워드의 문제점 : 호이스팅(선언 전 사용 가능), 중복 선언 가능, 스코프는 함수 단위로 결정됨
    ES2015에서는 Var 키워드가 가진 문제를 해결하기 위해 let, const를 사용함.
    let (재할당 O), const (재할당 X)


    호이스팅(hoisting)

    · 인터프리터가 코드를 실행하기 전에 함수, 변수, 클래스 또는 임포트(import)의 선언문을 해당 범위의 맨 위로 이동시키는 과정
    · 선언 부분만 끌어 올려짐.
    → 선언과 동시에 값을 할당해도, 할당된 값 자체는 그 이후에 접근 가능함.

    console.log(title)  // 변수 선언 전에 사용 가능 (undefined)
    var title = 'apple';  // 변수 선언
    console.log(title)  // apple
    
    console.log(title)
    let title;

     

    중복 선언 가능

    var title = 'apple';
    console.log(title);
    var title = 'banana';
    console.log(title);

     

    실수로 이미 선언한 변수에 재할당하면 이전 변수는 사라짐.

    let title = 'apple';
    console.log(title);
    let title = 'banana';
    console.log(title);

     

    함수 스코프 (function scope) - var 

    변수가 선언된 함수 내에서만 유효한 스코프

    function example() {
      if (true) {
        var x = 10;
        console.log(x); // 10
      }
      console.log(x); // 10
    }
    
    example();
    console.log(x);  // ReferenceError: x is not defined
    function example() {
      for (var i = 0; i < 3; i++) {
        console.log(i); // 0, 1, 2
      }
    
      console.log("반복문 외부에서 i:", i); // 3 - 반복문 외부에서도 접근 가능
    }
    
    example();

     

    블록 스코프 (block scope) - let, const

    변수가 선언된 블록(일반적으로 중괄호 {}로 둘러싸인 부분) 내에서만 유효한 스코프

    function example() {
      if (true) {
        let y = 20;
        console.log(y);
      }
      console.log(y);  // ReferenceError: y is not defined
    }
    
    example();
    console.log(y);  // ReferenceError: y is not defined
    function example() {
      for (let i = 0; i < 3; i++) {
        console.log(i); // 0, 1, 2
      }
    
      console.log("반복문 외부에서 i:", i); // ReferenceError: i is not defined
    }
    
    example();

     

    var과 let, const의 차이점

    var 변수 let과 const 변수
    변수 이름 중복선언 가능 변수 이름 중복선언 불가 (SyntaxError 발생)
    변수 선언 전에 사용 가능(호이스팅) 변수 선언 전에 사용 불가 (ReferenceError 발생)
    함수 스코프 블록 스코프

     

    3. 함수 다루기

    함수를 만드는 방법

    · 함수를 만드는 방법 두 가지 : 함수 선언 , 함수 표현식

    · 함수 선언과 함수 표현식의 가장 큰 차이 : 호이스팅, 스코프

    · 보편적으로는 표현식보다는 선언을 우선으로 사용함.

     

    함수 선언 (Function Declaration)

    · function 키워드를 통해서 함수를 선언하는 일반적인 방식

    · 호이스팅으로 인해서 함수를 선언하기 이전에 함수를 호출해도 정상적으로 동작

    · 함수 스코프를 가짐.

    funcion 함수이름(파라미터) {
    	동작
    	return 리턴값
    }
    function apple() {
    	function banana() {
    		console.log('banana')  
    	} 
    	
    	console.log('apple');  // 실행 O
    	banana();  // 실행 O
    }
    
    apple();  // apple banana
    banana();  // ReferenceError: banana is not defined
    // 함수 선언은 함수 호이스팅이 가능함.
    
    printCodeit();  // Codeit
    
    function printCodeit() {
    	console.log('Codeit')
    }

     

    함수 표현식 (Function Expression)
    · 함수 선언을 변수에 할당하거나 다른 함수의 아규먼트로 활용하면서 마치 함수 선언을 값처럼 활용해서 함수를 만드는 방식

    · 반드시 변수가 선언된 이후에 함수를 호출해야 정상적으로 동작

    · 변수에 할당하는 경우에는 할당된 변수의 특성에 따라 스코프가 결정 (var: 함수, let이나 const: 블록)

    const printCodeit = function () {
    	console.log('Codeit');
    };
    const myBtn = document.querySelector)'#myBtn');
    
    myBtn.addEventListener('click', function () {
    	console.log('button is clicked');
    });
    // 함수 선언 (함수 스코프)
    {
      function sayHi() {
        console.log('Hi!');
      }
    }
    
    sayHi();  // Hi!
    // 함수 표현식 - let 키워드로 선언 (블록 스코프)
    {
      let sayHi = function () {
        console.log('Hi!');
      };
    }
    
    sayHi();  // ReferenceError: sayHi is not defined
    // 함수 표현식 - var 키워드로 선언 (함수 스코프)
    {
      var sayHi = function () {
        console.log('Hi!');
      };
    }
    
    sayHi();  // Hi!

    이름이 있는 함수 표현식

    Named Function Expression (기명 함수 표현식)
    · 함수 표현식으로 할당된 함수에 이름을 붙일 수 있음.
    · 이름이 없는 함수를 변수에 할당할 때는 변수의 name 프로퍼티는 변수 이름 그 자체를 문자열로 가지게 됨.

       하지만 함수에 이름을 붙여주게 되면, name 속성은 함수 이름을 문자열로 가짐.
    · 함수에 이름을 명시적으로 지정할 수 있어 디버깅과 코드 가독성 측면에서 유용함.
    · 함수 내부에서 자신을 참조 가능, 외부에서는 이름으로 참조 불가능함.

     

    var myFunction = function namedFunction() {
      console.log("This is a named function expression.");
    };
    myFunction(); // 함수 호출
    
    // 함수 이름을 통한 참조
    console.log(namedFunction); // undefined
    console.log(myFunction); // 함수의 정의가 출력됨

     

    외부에서 변수 myFunction을 통해 함수에 접근 가능, namedFunction으로 접근 불가능

     

    자기 자신을 재귀적으로 호출하는 예시

    var factorical = function caculateF(n) {
    	if (n <= 1) {
    		return 1;
    	} else {
    	// 함수 내부에서 자신을 참조
    	return n * calculateF(n);
    	}
    };
    
    // 함수 호출
    console.log(factorial(5)); // 5! = 120
    let countdown = function(n) {
      console.log(n);
      if (n === 0) {
        console.log('End!');
      } else {
        countdown(n - 1);
      }
    };
    
    let myFunction = countdown;
    countdown = null;
    
    myFunction(5); // TypeError
    let countdown = function printCountdown(n) {
      console.log(n);
      if (n === 0) {
        console.log('End!');
      } else {
        printCountdown(n - 1);
      }
    };
    
    let myFunction = countdown;
    countdown = null;
    
    myFunction(5); // 정상적으로 동작

    함수 이름을 사용해서 재귀적으로 호출하는 경우 외부에서 함수를 할당한 변수의 이름을 바꾸더라도 영향을 받지 않음.
    함수 이름은 함수를 정의할 때 고정된 값이기 때문에 외부에서 함수를 호출하거나 함수에 대한 참조를 변경해도 영향을 받지 않음.


    즉시 실행 함수 (IIFE)

    즉시 실행함수 (IIFE, Immediately Invoked Function Expression)
    ·  함수 선언과 동시에 즉시 실행되는 함수
    ·  함수 선언부분을 소괄호로 감싸고, 바로 뒤에 실행하는 소괄호 붙이기

    ·  활용 : 프로그램 초기화 기능, 재사용이 필요없는 일회성 동작

    (function (x, y) {
      console.log(x + y);
    })(3, 5);

     

    즉시 실행 함수는 함수에 이름을 지어주더라도 외부에서 재사용할 수 없다.
    내부에서는 재귀적으로 사용할 수 있음.

    (function sayHi() {
      console.log('Hi!');
    })();
    
    sayHi(); // ReferenceError
    (function countdown(n) {
      console.log(n);
      if (n === 0) {
        console.log('End!');
      } else {
        countdown(n - 1);
      }
    })(5);
    
    /*
    5
    4
    3
    2
    1
    0
    End!
    */

    값으로서 함수

    자바스크립트에서 함수는 변수나 다른 데이터 구조 안에 자유롭게 할당
    함수 표현식객체의 프로퍼티로 함수 선언해서 메소드 생성배열의 요소로 생성 가능함.

     

    객체 내 함수 (Object method)

    const myObject = {
        brand: 'Codeit',
        bornYear: 2017,
        isVeryNice: true,
        sayHi: function(name) {
            console.log(`Hi! ${name}`);
        }
    };
    
    myObject.sayHi('JavaScript');
    // 출력: Hi! JavaScript

    객체 myObject 안에 sayHi 메서드를 정의하고, 이를 호출하여 인사 메시지를 출력함.

     

    배열 내 함수 (Function in an array)

    const myArray = [
        'codeit',
        2017,
        true,
        function(name) {
            console.log(`Hi! ${name}`);
        }
    ];
    
    myArray[3]('Codeit');
    // 출력: Hi! Codeit

    배열 myArray 안에 함수가 있고, 해당 함수를 배열 인덱스를 통해 호출하면서 'Codeit'을 인자로 넘김.

     

    이벤트 리스너에 함수 전달 (Passing a function to an event listener)

    const myBtn = document.querySelector('#myBtn');
    
    myBtn.addEventListener('click', function() {
        console.log('button is clicked');
    });

    myBtn 요소를 찾고, 클릭 이벤트가 발생하면 'button is clicked' 메시지를 출력하는 함수를 등록함.

     

    고차 함수 (Higher Order Function)

    함수를 반환하거나 매개변수로 함수를 받는 함수

    // 함수가 다른 함수를 반환하는 경우에는 반환된 함수를 호출하기 위해 추가적인 괄호가 필요
    function getPrintHi() {
        return function() {
            console.log('Hi!?');
        };
    }
    
    // 괄호 1개
    getPrintHi();  // 아무것도 출력되지 않음
    
    // 괄호 2개
    getPrintHi()();  // Hi!?
    
    // 함수를 다른 변수에 할당하여 호출
    const greeting = getPrintHi();
    console.log(greeting); // [Function (anonymous)]
    greeting();  // Hi!?

     

    일급 함수 (First-class Function)
    자바스크립트에서 함수는 일급 함수임.

    이는 함수를 변수에 할당하거나, 다른 함수의 매개변수로 전달하거나, 함수에서 반환할 수 있다는 것을 의미함.

    위의 예시들에서 보여준 것처럼 함수를 값으로 다룰 수 있음.

     

    콜백 함수 (callback function)

    다른 함수의 매개변수로 전달되는 함수

    // 간단한 배열
    const numbers = [1, 2, 3, 4, 5];
    
    // 배열을 순회하면서 각 요소에 대해 콜백 함수를 호출하는 함수
    function forEach(arr, callback) {
        for (let i = 0; i < arr.length; i++) {
            // 각 요소에 대해 콜백 함수 호출
            callback(arr[i]);
        }
    }
    
    // 순회할 때 실행될 콜백 함수
    function squareNumber(num) {
        console.log(num * num);
    }
    
    // forEach 함수를 사용하여 배열을 순회하면서 squareNumber 콜백 함수 호출
    forEach(numbers, squareNumber);

    Parameter

    function greeting(name) {
    	console.log(`Hi! My name is ${name}!`);
    }
    
    greeting('JavaScript');
    greeting('Codeit');
    greeting('World');

     

    파라미터(Parameter) 

    외부로부터 값을 전달받기 위해 함수를 선언할 때 작성하는 것, 함수 안에 작성

    ex. name은 greeting 함수의 파라미터(parameter)

     

    아규먼트(Argument)

    함수를 호출할 때 파라미터로 전달하는 값

    ex, 'JavaScript', 'Codeit', 'World' 등

    function greeting(name) {
    	console.log(`Hi! My name is ${name}!`);
    }
    
    greeting();
    // Hi! My name is undefined!

     

    아규먼트가 파라미터로 전달될 때는 파라미터의 기본값과는 전혀 관계없이 함수를 호출할 때 작성한 순서 그대로 전달됨.
    아규먼트 생략할 가능성이 있어서 기본값이 필요한 파라미터는 가급적 오른편에 작성하는 것이 권장됨.

    function greeting(name = 'Codeit', interest) {
    	console.log(`Hi! My name is ${name}!`);
    	console.log(`I like ${interest}!`);
    }
    
    greeting('JavaScript');
    // Hi! My name is JavaScript!
    // I like undefined!
    function greeting(name = 'Codeit', interest = 'JavaScript') {
    	console.log(`Hi! My name is ${name}!`);
    	console.log(`I like ${interest}!`);
    }
    
    greeting(undefined, 'Python');
    // Hi! My name is Codeit!
    // I like Python!
    function calculate (x, y = x + 2) {
        console.log(`x : ${x}`);
        console.log(`y : ${y}`);
    }
    
    calculate(3)  // x : 3, y : 5
    calculate(3, 4)  // x : 3, y : 4
    calculate(undefined, 4)  // x : undefined, y : 4
    calculate(4, undefined)  // x : 4, y : 6  (기본값이 설정돼 있으면 기본값)
    calculate(null, 4)  // x : null, y : 4  
    calculate(4, null)  // x : 4, y : null  (기본값이 설정돼 있어도 null)

    Arguments

    함수 내에서 사용할 수 있는 특별한 객체
    함수에 전달된 모든 인자를 포함함.
    이 객체는 유사한 배열의 형태를 가지며, 배열처럼 인덱스로 접근 가능함.

    (arguments.length와 arguments[0]과 같이 사용 가능)

    이미 예약된 이름이므로, 함수 내부에서 'arguments'라는 변수나 함수를 만들지 않는 것이 좋음.

    function printArguments(a, b, c) {
    	console.log(a);
    	console.log(b);
    	console.log(c);
    	console.log('------');
    }
    
    printArguments('apple', 'banana', 'orange');   // apple, banana, orange
    printArguments('apple');  // apple, undefined, undefined
    printArguments('apple', 'banana');  // apple, banana, undefined
    printArguments('apple', 'banana', 'orange', 'peach');  // apple, banana, orange
    function exampleFunction() {
      // arguments 객체의 길이를 출력
      console.log("Arguments Length:", arguments.length);
    
      // arguments 객체를 for of 반복문을 통해 순회하여 각 인자를 출력
      for (const arg of arguments) {
        console.log("Current Argument:", arg);
      }
    }
    
    // 함수 호출 시에 다양한 인자를 전달
    exampleFunction('첫 번째', '두 번째', '세 번째');
    
    /*
    출력 결과:
    Arguments Length: 3
    Current Argument: 첫 번째
    Current Argument: 두 번째
    Current Argument: 세 번째
    */

    Rest Parameter

    arguments 객체의 아쉬운 부분
    · arguments 객체가 유사배열이라서 배열의 메소드 사용 불가
    · 항상 함수를 호출할 때 전달한 arguments 전체를 다루기 때문에 마지막 2개 혹은 3개만 다루려면 인덱싱을 통해 세분화하는 과정이 필요함
    → ES2015 이후 Rest Parameter 가 등장함.

     

    rest parameter

    ·  인자들을 배열로 묶어주는 문법으로 가변적인 매개변수를 다를 수 있음.

    ·  일반 파라미터 앞에 마침표 3개 붙인 것
    ·  rest parameter은 배열이므로, 배열의 메소드를 자유롭게 사용할 수 있음.

    function printArguments(...args) {
    	for (const arg of ars) {
    		console.log(arg);
    	}
    	console.log('-----');
    	};
    
    printArguments('apple', 'banana', 'orange');
    printArguments('apple');
    printArguments('apple', 'banana');
    printArguments('apple', 'banana', 'orange', 'peach');
    function printArguments(...args) {
    	console.log(args.splice(0, 2));
    	console.log(arguments.splice(0, 2));
    	console.log('------------');
    	};
    
    printArguments('apple', 'banana', 'orange');
    printArguments('apple');
    printArguments('apple', 'banana');
    printArguments('apple', 'banana', 'orange', 'peach');
    
    
    // arguments.splice is not a function

     

    에러가 발생하는 이유는 'arguments'가 배열이 아닌 배열과 유사한 객체이기 때문임. 

    'splice' 매서드는 배열 메서드이며, 'arguments' 객체에 직접 사용할 수 없음.


    여기서 주의할 점 : (...args)는 실제로 배열을 만드는 것이 아니라 인자들을 배열로 묶어주는 문법이라는 것임.
    'arguments'를 배열로 변환하려면 전개 연산자나 'Array.from()' 매서드를 사용할 수 있음.

    function printArguments(...args) {
      // arguments를 배열로 변환하기 위해 전개 연산자 사용
      const argsArray = [...args];
      console.log(argsArray.splice(0, 2));
    
      // 또는 arguments를 배열로 변환하기 위해 Array.from() 메서드 사용
      const argumentsArray = Array.from(arguments);
      console.log(argumentsArray.splice(0, 2));
    }
    
    printArguments('apple', 'banana', 'orange');

     

    rest 파라미터와 일반 파라미터를 함께 사용할 수 있음

    function ignoreFirst (first, ...args) {
        // 출력할 배열 정의
        let exceptFirst = [];
        
        // 파라미터에 들어간 원소들을 배열의 원소로 집어 넣음
    	for (const thing of args) {
    		exceptFirst.push(thing);
        }
    
        console.log(exceptFirst);
    }
    
    ignoreFirst('곰팡이', '강아지', '고양이');

    일반 파라미터와 함께 사용할 때 rest parameter은 가장 나중에 작성되어야 함.

    명확하게 구분되어야 하는 것은 일반 파라미터를 사용, 유연하게 다룰 수 있는 부분은 rest parameter로 나누기


    Arrow Function 

    · 기존의 함수선언 방식을 보다 간결하게 만들어주는 표현식. (ES2015에 등장)
    · 이름이 없는 익명함수임.
    ·이름을 가진 변수에 할당, 다른 함수의 argument로 변수를 선언
    ·function 키워드를 지우고 '() =>'를 작성

    const getTwice = (number) => {
    	return number * 2;
    };
    console.log(getTwice(6));  // 12
    // 위 코드에서 파라미터의 괄호 생략
    const getTwice = number => {
    	return number * 2;
    };
    console.log(getTwice(6));  // 12

     

    파라미터가 2개 이상이거나 없을 경우 소괄호 반드시 작성

    // 파라미터가 2개 이상이거나 없을 경우 소괄호 반드시 작성
    const sum = (a, b) => a + b;
    console.log(sum(3, 7))  // 10
    
    const sum = (a, b) => (a + b);
    console.log(sum(3, 7))  // 10

     

    리턴값이 객체인 경우

    const getName = () => {
    	return { name: "길동", };
    };
    console.log(getName());  // { name: '길동' }
    const getName = () => { name: "길동", };
    console.log(getName());
    // SyntaxError: Unexpected token '}'
    // 리턴값이 객체인 경우 
    // 함수의 동작 부분을 구분하는 중괄호로 인식함
    const getName = () => { name: "길동", };
    console.log(getName());
    const getName = () => ({ name: "길동", });
    console.log(getName());

    화살표를 쓰고 그 다음에 바로 중괄호를 쓰면 함수의 동작 부분을 구분하는 것으로 인식해서 오류가 남. 

    중괄호 부분을 '소괄호()'로 감싸면 됨.

     

    arrow function에서는 arguments 객체가 없다.

    function normalFunc() {
    	console.log(arguments);
    };
    
    const arrowFunc = () => {
    	console.log(arguments);
    };
    
    normalFunc(1, 2, 3);  // [Arguments] { '0': 1, '1': 2, '2': 3 }
    arrowFunc(1, 2, 3);  // error

     

    rest parameter을 사용하여 인자를 받을 수 있음.

    const arrowFunc = (...args) => {
    	console.log(args);
    };
    
    arrowFunc(1, 2, 3);  // [ 1, 2, 3 ]

    this

    · 함수를 호출한 객체를 가리키는 키워드임
    ·코드를 작성할 때 값이 미리 결정 (X)

    ·함수가 호출될 때 어떤 객체가 함수를 호출했는지에 따라 값이 변함. (O)

     

    브라우저 안에서 자바스크립트가 동작하면 윈도우 객체가 출력됨.
    전역객체인 window객체가 this의 기본값임.
    this는 일반적으로 사용되지 않고 함수 내부에서 주로 사용됨.
    특히 객체 메소드를 만들 때 중요한 역할을 함.

    const myObject = {
        'name' : '길동',
        'age' : 43,
        'introduce_myself' : function () {
            return `내 이름은 ${this.name}이고, 내 나이는 ${this.age}이다.`;  
            // this : 현재 메소드를 호출한 객체 = myObject라는 객체임
        } 
    }
    
    console.log(myObject.introduce_myself())

     

    일반함수와 화살표 함수의 차이점은 this를 다루는 방식임.
    · 일반함수 : 호출한 대상에 따라 상대적으로 변함
    · 화살표함수 : arrow function이 선언되기 직전의 그때 유효한 this값과 똑같이 동작함.
    객체 메소드를 만들 때는 화살표함수보다 일반 함수가 권장됨.

    this에 메소드를 호출한 객체를 가리키고 싶다면 arrow function 보다는 일반 함수를 활용하면 좋음.

    // 일반 함수를 사용하여 객체를 생성하는 예제
    function NormalFunction() {
      // 객체 생성 시 value 속성을 1로 설정
      this.value = 1;
    
      // 1초 후에 실행되는 콜백 함수
      setTimeout(function () {
        // 여기서의 this는 전역 객체를 가리킴
        // 따라서 this.value++는 전역 객체의 value 속성을 증가시키려 함
        // 그러나 전역 객체에 value 속성이 없으므로 NaN(Not a Number)이 출력됨
        this.value++;
        console.log("Normal Function:", this.value);
      }, 1000);
    }
    
    // 화살표 함수를 사용하여 객체를 생성하는 예제
    function ArrowFunction() {
      // 객체 생성 시 value 속성을 1로 설정
      this.value = 1;
    
      // 1초 후에 실행되는 콜백 함수
      setTimeout(() => {
        // 여기서의 this는 ArrowFunction 함수 내에서의 this를 따라감
        // ArrowFunction 객체를 가리키므로 this.value++는 ArrowFunction 객체의 value 속성을 증가시킴
        // 따라서 1에서 시작하여 1초 후에 2가 출력됨
        this.value++;
        console.log("Arrow Function:", this.value);
      }, 1000);
    }
    
    // 객체를 생성하여 NormalFunction 함수 실행
    const obj = new NormalFunction(); // Normal Function: NaN (전역 객체에 value가 없음)
    
    // 객체를 생성하여 ArrowFunction 함수 실행
    const obj2 = new ArrowFunction(); // Arrow Function: 2
    728x90