JavaScript(4)

Minji Lee·2023년 10월 11일
0

javascript

목록 보기
4/11
post-thumbnail

Ch04 함수

함수 선언과 호출, 호이스팅

함수 사용법

  1. 함수 선언문(Declaration)

    function hello() {}
  2. 함수 표현식(Expression)

    const hello = function () {};

함수 호이스팅(Hoisting)

  • 보통, 코드 순서는 위에서부터 아래로 순차적으로 실행됨
    function hello() {
      console.log("hello");
    }
    
    hello();
  • 함수 호이스팅을 통해 정의되지 않은 함수 호출 → 함수가 선언되어져 있는 유효한 범위의 맨 위로 올라가 호출됨
    ❗️ 함수 호이스팅은 함수 선언문에서만 작동함, 함수 표현식에서는 작동 안함
    hello(); 
    
    function hello() {
      console.log("hello");
    }
  • 함수 구현 코드가 복잡할 때 함수 호이스팅 사용 → 함수 호출문(즉, 함수 이름)을 보며 함수 로직에 대해 추측한 후 함수 구현문으로 이동하여 로직을 파악할 수 있음
  • 기명 함수를 사용하면 호이스팅 사용 못함(함수 이름이 변경됨)
    const world = function hello() {
      console.log("Hello");
    };

반환 및 종료

  • return: 반환할 데이터를 제공하고 함수를 종료return 이후의 코드는 실행되지 않음 → 반환할 데이터가 없는 경우 undefined 반환 return;
    function hello() {
      return "Hello!";
      console.log("Wow");
    }
    
    console.log(hello()); // Hello!

ex)

function plus(num) {
  if (num === undefined) {
    // num이 undefined면 return
    console.log("숫자를 입력해주세요!");
    return 0;
  }
  return num + 1;
}

console.log(plus(2));
console.log(plus(7));
console.log(plus()); // undefined+1 = NaN

매개변수 패턴(Parameter pattern)

기본값(Default value)

// 매개변수
// b에 기본 값 지정(인수로 받아온 값이 없는 경우 대신 사용)
function sum(a, b = 1) {
  return a + b;
}

console.log(sum(1, 2)); // 인수(argument)
console.log(sum(7));

구조 분해 할당(Destructuring assignment)

매개변수 객체 구조 분해 할당

  1. 객체 문법 이용

    const user = {
      name: "HEROPY",
      age: 85,
    };
    
    function getName(user) {
      return user.name; // 혹은 user.name;
    }
    
    console.log(getName(user));
  2. 구조 분해 할당(1)

    const user = {
      name: "HEROPY",
      age: 85,
    };
    
    function getName(user) {
      const { name } = user;
      return name;
    }
    
    console.log(getName(user));
  3. 구조 분해 할당(2)

    const user = {
      name: "HEROPY",
      age: 85,
    };
    
    function getName({ name }) {
      return name;
    }
    
    console.log(getName(user));
  • 기본값 설정
    const user = {
      name: "HEROPY",
      age: 85,
    };
    
    // 이메일 속성이 없는 경우를 대비하여 기본값 설정
    function getEmail({ email = "이메일이 없습니다." }) {
      return user.email;
    }
    
    console.log(getEmail(user));

매개변수 배열 구조 분해할당

  1. 배열 인덱스 이용

    const fruits = ["Apple", "Banana", "Cherry"];
    
    function getSecondItem(array) {
      return array[1];
    }
    
    console.log(getSecondItem(fruits));
  2. 배열 구조 분해 할당 → 쉼표로 구분

    const numbers = [1, 2, 3, 4, 5, 6, 7];
    
    function getSecondItem([, b]) {
      return b;
    }
    
    console.log(getSecondItem(numbers));

나머지 매개변수(Rest parameters) → 전개 연산자 이용

function sum(...rest) {
  console.log(rest);
  return rest.reduce((acc, current) => {
    return acc + current;
  }, 0);
}

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, 9, 10)); // 55

화살표 함수(Arrow function)

💡 함수 표현 방식

  • 함수 선언: function sum() {};
  • 함수 표현: const sum = function () {};
  • 화살표 함수(일종의 함수 표현식): const sum = () => {};

함수 선언과 화살표 함수

  • 함수 선언
    function sum(a, b) {
      return a + b;
    }
  • 화살표 함수
    const sum = (a, b) => a + b;

화살표 함수의 다양한 패턴

  • 화살표 함수 기본 형태
    const a = () => {};
  • 매개 변수 개수
    • 매개변수가 하나인 경우 소괄호 생략 가능
      const b = (x) => {};
      const b = x => {};
    • 매개 변수가 2개 이상 혹은 없는 경우 소괄호 반드시 사용
      const c = (x, y) => {};
  • 함수 로직 구현부
    • 기본 형태
      const d = (x) => {
        return x * x;
      };
    • 코드가 한 줄인 경우 return과 중괄호 생략 가능
      const e = (x) => x * x;
    • 코드가 두 줄 이상인 경우 중괄호 생략 불가
      const f = (x) => {
        console.log(x);
        return x * x;
      };
  • 객체 데이터 반환
    const g = () => {
      return { a: 1 };
    };
    • 중괄호와 return 생략시, 소괄호로 묶어 데이터라는 것을 명시
      const h = () => ({ a: 1 });
  • 배열 데이터 반환
    const i = () => {
      return [1, 2, 3];
    };
    • 중괄호 생략 가능
      const j = () => [1, 2, 3];

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

익명함수를 통해 즉시 실행

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

즉시실행함수 표현방법

  1. (F)()(() => {})();
  2. (F)()(function () {})();
  3. (F())(function () {}());
  4. !F()!(function () {})();
  5. +F()+(function () {})();

두번째 소괄호의 역할 → 매개변수 전달

  • 외부의 변수를 내부에서 사용가능
((a,b)=>{console.log(a); console.log(b)})(1,2);

콜백(Callback)

콜백: 함수가 실행될 때 인수로 들어가는 또 하나의 함수

const a = (callback) => {
  console.log("A");
  callback();
};
const b = () => {
  console.log("B");
};

a(b);
// A
// B

ex) setTimeout() 사용

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

sum(1, 2, (value) => {
  console.log(value);
});

ex) 이미지 업로드

const loadImage = (url, cb) => {
  const imgEl = document.createElement("img");
  imgEl.src = url;
  imgEl.addEventListener("load", () => {
    cb(imgEl);
  });
};

const containerEl = document.querySelector(".container");
loadImage("https://picsum.photos/200", (imgEl) => {
  containerEl.innerHTML = "";
  containerEl.append(imgEl);
});

재귀(Recursive)

자신의 함수를 함수 코드 내에서 다시 호출 하는 것

무한으로 반복하며 특정 조건 찾을 수 있음

❗️무한으로 반복되기 때문에 종료 조건이 필요하다.

const a = () => {
  console.log("A");
  a(); // 무한호출
};

a();

[종료조건 추가]

let i = 0;
const b = () => {
  console.log("A");
  i += 1;
  // i가 자신보다 작을 때만 재귀함수 호출
  if (i < 4) {
    b();
  }
};

b();

ex) 최상위 부모 찾기

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) => {
  // parent가 있으면 해당 user의 부모를 다시 인자로 넘겨줌
  if (user.parent) {
    return getRootUser(user.parent);
  }
  return user;
};

console.log(getRootUser(userD)); // { name: 'A', parent: null}
  • userD의 parent인 userC를 넘김 → userC의 parent인 userB를 넘김 → userB의 parent인 userA를 넘김 → userA는 부모가 없으므로 자기 자신 리턴

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

setTimeout(F(), 시간);

: 해당 시간 후에 함수 실행

const hello = () => {
  console.log("Hello~!");
};

setTimeout(hello, 2000); // 2초 후 실행

const timeout = setTimeout(hello, 2000);
const h1El = document.querySelector("h1");
h1El.addEventListener("click", () => {
  // h1을 클릭하면 타이머 취소
  clearTimeout(timeout);
});

setInterval(F(), 시간);

: 해당 시간마다 함수 실행

const timeout2 = setInterval(hello, 2000); // 2초마다 실행
h1El.addEventListener("click", () => {
  // h1을 클릭하면 타이머 취소
  clearInterval(timeout);
});

this

일반함수에서의 this

호출 위치에서 정의

const user = {
  firstName: "Heropy",
  lastName: "Park",
  age: 85,
  getFullName: function () {
    // 현재 getFullName이 들어있는 객체 데이터 참조
    return `${this.firstName} ${this.lastName}`;
  },
};

console.log(user.getFullName());

어떤 객체가 가지고 있는 메서드를 다른 객체에서 가져다 사용 가능

const user4 = {
  firstName: "Heropy",
  lastName: "Park",
  age: 85,
  getFullName() {
    return `${this.firstName} ${this.lastName}`; // Lewis Yang
  },
};

const lewis = {
  firstName: "Lewis",
  lastName: "Yang",
};
console.log(u.getFullName.call(lewis)); // u의 getFullName메소드 빌려서 실행

화살표 함수에서의 this

자신이 선언한 함수(렉시컬) 범위에서의 정의

💡 렉시컬(Lexical): 함수가 동작할 수 있는 유효한 범위

const user2 = {
  firstName: "Heropy",
  lastName: "Park",
  age: 85,
  getFullName: () => {
    // 화살표 함수 범위 밖의 데이터는 참조 불가능
    return `${this.firstName} ${this.lastName}`; // undefined undefined
  },
};

console.log(user2.getFullName());
function user3() {
  this.firstName = "Neo";
  this.lastName = "Anderson";
  return {
    firstName: "Heropy",
    lastName: "Park",
    age: 85,
    getFullName: () => {
      //자신을 호출 하고 있는 함수 범위를 참조(밖)
      return `${this.firstName} ${this.lastName}`; // Neo Anderson
    },
  };
}

const u = user3();
console.log(u.getFullName());

0개의 댓글