본문 바로가기
Javascript

5. [JavaScript] 함수

by 뽀롱트옌드 2023. 7. 25.

🏃🏻‍♀️ 함수 function

[ 함수의 정의 ]

- 함수의 구조와 호출

         함수명  매개변수(인수로 들어온 데이터를 매개변수로 받음)
function  add   (a, b) {
           반환값
    return a + b;
}

    인수
add(3, 5); // 함수 호출 5
  • 인수 = Argument / 매개변수 = Parameter
  • 함수호출시 인수로 작성된 데이터가 매개변수에 할당됨 -> 인수가 할당된 매개변수는 함수의 코드블럭{} 안에서만 유효(지역변수)

- 호이스팅

MDN - Hoistiong
자바스크립트는 최상단에서 -> 하단 순서로 코드를 읽고 실행하는데 호이스팅이 발생하면 함수 선언문을 유효범위의 최상단으로 끌어올려 먼저 다 읽음
즉, 호이스팅이 발생하는 함수의 선언문(함수의 로직)이 함수호출 아래에 있어도 함수가 실행됨

- 함수 선언문(기명함수)

  • 함수키워드로 시작해 함수의 이름이 꼭 있어야함
  • 호이스팅 발생: 함수호출이 함수선언문 보다 먼저 있어도 함수가 호출됨
  • 함수 선언문을 =(할당연산자)를 통해 변수에 할당하면 함수표현식이되어 함수 이름으로 호출 불가, 변수명으로 호출가능하고 호이스팅 사용 불가
welcome(); // 호이스팅 발생 -> Welcome to the world of Poppy!

function welcome() {
 console.log('Welcome to the world of Poppy!');
}

welcome(); // Welcome to the world of Poppy!

- 함수 표현식

  • 익명함수, 기명함수를 =(할당연산자)를 사용해 변수에 할당 한 함수
  • 호이스팅 없음: 함수호출이 함수선언문 보다 먼저 있으면 함수 호출 불가(ReferenceError 오류)
welcome(); // 오류 Uncaught ReferenceError: Cannot access 'welcome' before initialization

const welcome = function () {
  console.log('Welcome to the world of Poppy!');
}

welcome(); // Welcome to the world of Poppy!

[ return ]

  • 함수호출시 return키워드 뒤에 작성한 데이터가 반환되고 종료
  • return키워드 뒤에 아무런 데이터를 작성하지 않거나 함수안에 return키워드가 없으면 자바스크립트엔진이 자동으로 undefined(암시적으로 아무것도 없음을 의미)를 할당해 호출하면 undefind반환
  • return 뒤에 작성한 데이터가 반환되고 종료되기때문에 다음줄 코드부터는는 호출할수없음
function plus(num) {
  if (typeof num != 'number') {
    console.log(num);
    return 0;
  }
  return num + 2
  console.log('안뇽안뇽~~나는 뽀삐야!'); // return으로 종료되어 없어짐 
}

console.log(plus(5)); // 7
console.log(plus()); // undefind, 0
console.log(plus); // return 으로 종료되어 함수내부 마지막 콘솔코드 호출안되고 없음

[ 매개변수 ]

- 매개변수 기본값 설정

  • 함수호출시 인수갯수가 매개변수갯수보다 적을경우 함수 오류가 날수있음
    -> 매개변수에서 =(할당연산자)로 기본값 설정할수있음
    * 인수가 있다면 기본값이 설정되어 있어도 인수로들어온 데이터가 매개변수로 할당
function add(a, b) {
    console.log(a + b);
}

add(1, 2); // 3
add(2); // 인수갯수가 매개변수갯수보다 적어 b에 undefind할당 -> 1 + undefind -> NaN

----------------------------------
function add(a, b = 2) { // =로 매개변수 기본값 지정
    console.log(a + b);
}
add(2); // 인수갯수가 부족해도 기본값이 있어 연산실행 4
add(1, 2); // 기본값이있어도 인수가 있으면 안수가 매개변수로 할당 3

- 객체 구조 분해 할당

함수에서도 매개변수에 {속성명}을 넣어 구조 분해 할당가능 (기본값도 지정 가능)

const user = {
  name: 'Poppy',
  age: 33
}

function getName({name}) { 
  return name;
}
console.log(getName(user)); // Poppy

function getCity({city = 'Seoul'}) { // user객체에 없는 속성을 만들고 기본값 지정
  return city
}
console.log(getCity(user)); // Seoul

- 배열 구조 분해 할당

함수에서도 매개변수에 []넣어 구조 분해 할당가능 (,로 필요없는 순서의 배열아이템 변수명 비워두기, ...전개연산자로 나머지 아이템 한번에 할당가능)

const colors = ['Pink', 'Yellow', 'White'];
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

function getItem([a, , c, , , f, ...rest]){
    return `${a}, ${c}, ${f}, ${rest}`
}


console.log(getItem(colors)); // Pink, White, undefined, 
console.log(getItem(numbers)) // 1, 3, 6, 7,8,9,10

- 나머지 매개변수

MDN - 나머지 매개변수
...전개연산자로 매개변수를 지정하면 함수로 들어오는 모든 인수 데이터를 배열데이터로 받음

function numbers(...rest){
  console.log(rest);
}

numbers(1, 2); // (2) [1, 2]
numbers(1, 2, 3, 4); // (4) [1, 2, 3, 4]
numbers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // (10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • arguments:
    MDN - arguments
    함수로 들어오는 모든 인수의 정보를 가지고 있는 지역변수
    유사배열(Like Array)형태를 가진 객체데이터

[ 화살표 함수 ]

  • ECMA6(2015년도 ver)에서 나옴
  • 선언적함수, 표현식함수보다 간소화하여 코드작성가능
  • 함수 표현식처럼 변수에 할당하여 사용
  • this키워드 해석방식이 function키워드를 사용하는 일반함수와 다름

const fn = function () {}; -> const arrowFn = () => {};


1. 기본 화살표 함수 문법

const a = () => {};


2. 매개변수가 하나뿐일땐 () 생략가능

const b = (x) => {};
const b = x => {};

// 매개변수가 없거나 두개일땐 생략안됨
const c = (x, y) => {};


3. 로직이 return 키워드로 시작하면 {}, return 생략가능

const d = x => { retrun x + x };
const d = x => x + x;

// 다른 로직이 나오면 생략하면 안됨
const e = x => {
  console.log(x + x);
  return x + x;
}


4. 객체의 기호 {}와 코드블럭 기호{}가 같아 정확도를위해 객체데이터를 사용할땐 ()안에 사용

const f = () => { return { a: 1 } };
const f = () => ({ a: 1 });

// 배열데이터는 기호가 같지 않아서 그대로 사용해도됨
const g = () => { return [1, 2, 3]};
const g = () => [1, 2, 3];

[ 즉시실행함수 ]

IIFE, Immediately-Invoked Function Expression

  • 함수 호출이 없어도 실행됨
  • window, document등 긴이름의 전역변수를 간소화시켜 사용 가능
  • 두번째 ()에 인수를 넣으면 매개변수로 받아 사용가능
// 화살표함수의 즉시실행함수
(() => {})(); // (F)();

// function키워드를 사용한 일반함수의 즉시실행함수 패턴
(function () {})(); // (F)();
(function () {} ()); // (F());
!function () {} (); // !F();
+function () {} (); // +F();

// e.g.
((a, b) => {
  console.log(a + b); // 5
})(2, 3); // 두번째 () 인수를 넣으면 매개변수로 받아 사용 

[ 콜백함수 ]

CallBack Function

  • 함수를 호출할때 다른 함수데이터(호출이 아닌 데이터)를 인수로 전달해 매개변수로 받는 함수(함수데이터)를 콜백함수이라고함
  • 매개변수로 받은 함수데이터를 호출된 함수 내부에서 사용가능해 필요한 위치에서 정확하게 사용가능


1. 표현식 함수데이터를 를 인수로 넣는 콜백

const a = bCall => {
  bCall(); // 매개변수 bCall 로 받은 b함수 호출
  console.log('A');
}
const b = () => {
  console.log('B');
}

// a함수를 호출();할때 b함수 데이터를 인수로 넣는데 이때 b를 callback함수라고함
// a함수가 매개변수 bCall로 b함수데이터를 받아 a함수안에서 원하는 시점에 b함수를 호출
a(b); // B, A 한줄씩 콘솔에 출력


2. 익명함수데이터를 인수로 넣는 콜백

const sum = (a, b, c) => { // ⑵ 매개변수가 value인 익명함수데이터를 sum의 매개변수 c로 받음
    c(a + b); // ⑶ c(매개변수가 value인 익명함수)는 함수데이터, c함수를 호출() 하면서 
              //    sum의 매개변수 a=3 + b=7 를 인수로 넣어 c함수의 매개변수 value로 받음
}
sum(3, 7, value => { // ⑴ sum 함수를 호출하면서 인수로 매개변수가 value인 익명함수데이터를 콜백함수로 넣음
  console.log(value); // ★최종 10 ⑷ 콜백으로 들어간 익명함수의 매개변수 value로 
                      // ⑶의 c(인수 a + b) -> 3+7 를 받아 10이 콘솔에 찍힘 
});


3. 이미지 주소를 받아 콜백함수로 실행

const loadImage = (url, callback) => { // ⑵ 이미지주소와 매개변수가 imgEl 인 익명함수데이터를
                                       //    매개변수 url과 callback으로 받음
  const imgEl = document.createElement('img'); // ⑶ loadImage함수가 호출되면 html문서에 
                                               //    img태그를 생성해 imgEl 상수에 할당
  imgEl.src = url; // ⑷ img 태그의 주소or경로를 매개변수로 url받은 데이터로 지정 
  imgEl.style.display = 'block'; // ⑸ img css 설정
  imgEl.addEventListener('load', () => { // ⑹ img주소or경로가 로드완료되면 실행
    setTimeout(()=>{
      callback(imgEl); // ⑺ 매개변수 callback으로 받은 인수imgEl(img태그)를 
                       //    매개변수가 imgEl로 받은 익명함수데이터(callbakck) 호출
    }, 1500); // ★ 최종 1.5초뒤 callback(imgEl); 실행 
  });
}

const containerEl = document.querySelector('.container'); 
// ⑴ loadImage를 호출하면서 인수로 이미지 주소와 매개변수가 imgEl인 익명함수 데이터를 넣음 
loadImage('이미지주소or경로', imgEl => { 
  containerEl.innerHTML = '<h2>flowerPoppy</h2>'; // ⑻ h2요소를 .container에 넣음 
  containerEl.append(imgEl); // ⑼ 주소가 있는 img태그를 .container에 삽입
});


e.g. 코드 결과

[ 재귀함수 ]

  • 함수안에서 자기 자신을 다시 호출하는 함수
  • 계속 자기자신을 호출해 무한반복되기때문에 멈추는 시점을 명시해줘야함
const a = () => {
  a();
}

a();
// e.g.
const colorZero = { name: 'Black', more: null }
const colorOne = { name: 'Pink', more: colorZero }
const colorTwo = { name: 'Yellow', more: colorOne }
const colorThree = { name: 'White', more: colorTwo }
const colorFour = { name: 'Blue', more: colorThree }

const getRootColor = color => {
  if (color.more) { // 매개변수의 color로 받은 객체의 more속성 값이 참이면 실행
    return getRootColor(color.more); // 재귀함수를 실행히면서 객체의 more속성값을 반환 
                                     // 객체는 참데이터 -> more속성값이 colorZero일때까지 
                                     // 재귀함수 반복호출
  return color; // colorZero객체의 more속성값이 거짓테이터 null이기 때문에 
                // if문의 재귀함수는 호출되지않고 colorZero객체데이터가 반환
}

console.log(getRootColor(colorFour)); // {name: 'Black', more: null}

[ 호출 스케줄링 ]

  • 함수를 원하는 시간을 지정해 지정 스케줄대로 호출

- setTimeout

setTimeout(함수데이터or익명함수, 밀리세컨단위===1000===1초);
지정한시간(위코드에선1초)이 지나면 함수호출이 되게 스케줄링

- setInterval

setInterval(함수데이더or익명함수, 밀리세컨단위);
지정한시간마다 반복적으로 함수호출

  • 호출스케줄링 함수는은 변수에담아도 지정한 스케줄대로 실행됨

- clearTimeout

calerTimeout(호출스케줄링함수가담긴변수);
호출 스케줄링 함수를 변수에담아 어느 시점에 호출 스케줄링을 멈출것인지, 어느 조건에선 실행시키지 않을지 지정가능

const toDo = () => {
  console.log('3초뒤 짜잔!');
}

// 변수에 담아도 스케줄대로 실행됨
const timeout0 = setTimeout(toDo, 3000); // 3초뒤 toDo함수 실행
const timeout1 = setInterval(toDo, 3000); // 3초마다 toDo함수 반복 실행

const containerEl = document.querySelector('.container');
containerEl.addEventListener('click', () => { // .container를 클릭하면 
  clearTimeout(timeout0); // 3초전에 클릭하면 timeout0 변수에담은 setTimeout 실행안됨
  clearTimeout(timeout1;// 클릭하는순간부터 timeout1 변수에담은 setIneterval 3초반복실행 멈춤 
});

[ this ]

this 키워드
fontyend - 객체데이터

- 일반함수 메서드

  • function키워드를 사용한 일반함수메서드의 this는 함수가 호출될때 위치에서 점표기법으로 연결되어있는 데이터를 참조
  • 호출될때 참조하는 데이터가 정의 되기때문에 메서드를 다른 객체에 불러와 사용가능
const user = {
  firstName: 'Poppy',
  lastName: 'Lee',
  getFullName() { // function 키워드를 사용한 일반함수 메서드는 : function 생략가능
    return `${this.firstName}, ${this.lastName}`
  }
  getLastName: () => { // 화살표함수 메서드
      return `${this.lastName}!`
  }
}

console.log(user.getFullName()); // Poppy, Lee
                                 // this가있는 일반함수 메서드가 호출될때 연결되어있는 user객체가 this
console.log(user.getFirstName()); // undefind!
                                  // 화살표 함수를 감싸는 다른 함수가 없기때문에
                                  // 참조 데이터가 없어 값이 없다는 암시적 undfind가 반환됨

const userDalls = {
  firstName: 'Gguggu',
  lastName: '💖'
}
console.log(user.getFullName.call(userDalls)); // Gguggu, 💖
// 일반함수메서드인 getFullName은 호출될때 참조데이터가 정의
// user객체에있는 getFullName함수데이터를 call메소드로 userDalls객체로 불러와 사용

- 화살표 함수 메서드

  • 화살표 함수 메서드의 this는 화살표 함수를 감싸고있는 또다른 외부함수의 데이터를 참조함
  • 일반함수메서드 안에 this와 스케줄링 함수 setTimeout이 같은 데이터를 참조해야한다면 setTimeout의 콜백함수로 화살표함수안에 this 쓰면 일반함수의메서드의 this를 참조하기때문에 같은데이터 참조가능
function family() {
  this.firstName = 'Gguggu'
  this.lastName = '💖'

  return {
    firstName: 'Poppy',
    lastName: 'Lee',
    getFullname() { 
      return `${this.firstName}, ${this.lastName}`
    },
    getLastname: () => {
      return `${this.lastName}`
    }
  }
}

const userFamily = family(); // family함수를 호출해 return의 객체가 반환되서 변수에 할당

console.log(userFamily.getFullname()); // Poppy, Lee
// 일반함수메서드의 this: getFullname 메서드가 호출되면서 userFamily할당된 객체를 참조 
console.log(userFamily.gerLastname()); // 💖
// 화살표함수메서드의 this: gerLastname메서드가 만들어질때 본인을 감싸고있는 외부함수 family의 데이터를 참조

const book = {
  title: 'The Little Mermaid',
  readTitle() {
    console.log(this.title); // ⑴ The Little Mermaid
    setTimeout(function(){
      console.log(this.title); // ⑵ 1초뒤 undefined
    }, 1000);
    setTimeout(() => {
      console.log(this.title); // ⑶ 1초뒤 The Little Mermaid
    }, 2000);
  }
}

book.readTitle(); 
// ⑴ 일반함수메소드라 호출되면서 연결된 book참조 book객체의 title속성값인 'The Little Mermaid' 콘솔출력
// ⑵ this를 가진 익명함수메소드(일반Fn)를 setTimeout의 콜백함수넣로음 setTimeout함수가 호출되면서 콜백함수 실행 -> setTimeout를 참조
// ⑶ this를 가진 화살표함수메소드를 콜백으로 넣어 setTimeou를 감싸고있는 readTitle함수를 참조