함수

이보아·2024년 5월 17일
0

모던_자바스크립트

목록 보기
13/18
post-thumbnail

함수

함수란?

일련의 과정을 문(statement)으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것이다.

함수 구성 요소

  • 매개 변수(parameter): 함수 내부로 입력을 전달받는 변수
  • 인수(argument): 입력
  • 출력 (return value): 반환값

KakaoTalk_20240516_192207023_01


// 함수 정의와 호출 예시 
function add(x, y) { // -> 정의
  return x + y;
}

add(2, 5); // 7 -> 호출
function add(x, y) {
  // function: 함수 선언 키워드
  // add: 함수 이름
  // (x, y): 매개 변수 목록
  return x + y;
  // x + y: 함수의 반환값, 이때 `return 반환값` 형태로 사용해주어야함.
}

add(2, 5); // 7
// 2, 5: 함수의 인자

함수를 사용하는 이유?

  • 코드의 재사용 : 필요할 때 여러번 호출 가능하다.
  • 코드의 신뢰성 향상: 중복된 횟수가 많아질수록 코드 수정이 많아지고 신뢰성이 떨어짐 그러나 함수를 사용하면
    중복 횟수를 줄일 수 있다.
  • 코드의 가독성 향상: 적절한 함수 이름은 내부 코드를 이해하지 않고도 함수의 역활을 바로 파악 할 수 있게 도움

함수 리터럴

함수는 객체이다. 함수 리터럴은 function 키워드, 함수 이름, 매게 변수 목록, 함수 몸체로 구성한다.
👉 일반 객체는 호출 할 수 없지만 함수는 호출할 수 있다.

const add = function (x, y) {
  return x + y;
};

add(2, 5); // 7

함수 정의

함수를 호출하기 이전에 인수를 전달받을 매개변수와 실행할 문들, 그리고 반환값을 지정함

  • 함수 선언문
function add = function (x, y) {
  return x + y;
};
  • 함수 표현식
const add = function (x, y) {
  return x + y;
};
  • function 생성자 함수
const add = new Function (x, y), return x + y;};
  • 화살표 함수(ES6)
const add =(x, y) => x + y;

📄 함수 정의 : 함수는 '정의'(definition)한다고 표현 함수 선언문이 평가되면 식별자가 암묵적으로 생성되고 함수 객체가 할당됨

함수 선언문

함수 선언문은 함수 이름을 생략할 수 없다. <-> 함수 리터럴은 함수이름 생략 가능

<function add(x, y) {
  return x + y;
}; // function (x, y) -> 이런식으로 생략할 수 없음

//함수 참조
// console.dir은 console.log와는 달리 함수 객체의 프로퍼티까지 출력함.
console.dir(add)

console.log(add(2,5)); // 7
  • 함수 선언문은 표현식이 아닌문이다.
  • 자바스크립트 엔진은 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의
    식별자를 암묵적으로 생성, 함수 객체를 할당함
  • 함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출한다.

KakaoTalk_20240516_192207023_01


함수 표현식

자바스크립트의 함수는 일급 객체다.

📄 일급객체란? 값처럼 변수에 할당 할 수도 있고, 프로퍼티 값이 될 수도 있고, 배열의 요소도 될수 있다 이처럼 값의 성질을 갖는 객체를 말함

// 가명 함수 표현식 
const add = function add(x, y) {
  return x + y;
};

//함수 객체를 가르키는 식별자로 호출
console.dir(add(2,5)); // 7

console.log(foo(2,5)); // foo is not defined 에러남...

함수 생성 시점과 함수 호이스팅

함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출할 수 없다.

함수 선언문으로 정의한 함수와 함수 표현식으로 정의한 함수의 생성 시점이 다르기 때문이다.

👉 코드가 한 줄씩 순차적으로 실행되는 시점(런타임) 이전에 함수 객체가 먼저 생성되고 자바스크립트
엔진이 함수이름과 동일한 이름의 식별자를 암묵적으로 생성하고 생성된 함수 객체를 할당함
런타임에는 이미 함수 객체 먼저 생성되어 있고 식별자 할당도 완료된 상태가
따라서 함수 선언문 이전에 함수를 참조할 수 있으며 호출할 수도 있다.(호이스팅)

변수 호이스팅 vs 함수 호이스팅 차이

  • 변수 호이스팅: var 키워드를 사용하면 선언된 변수는 undefined로 초기화됨 var 키워드를 사용한 변수 선언문 이전 변수를 참조하면 변수 호이스팅에 의해 undefined로 평가됨

  • 함수 호이스팅: 함수 선언문으로 정의한 함수를 함수 선언문 이전에 호출하면 함수 호이스팅에 의해 호출이 가능하다
    👉 함수 표현식으로 함수를 정의하면 함수 호이스팅이 발생하는 것이 아니라 변수 호이스팅이 발생한다.


📄호이스팅이란? 함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징


// 함수 참조
console.dir(add); // f add(x,y)
console.dir(sub); // undefined

// 함수 호출
console.log(add(2, 5)); // 7
console.log(sub(2, 5)); // TypeError: sub is not a function

// 함수 선언문
function add(x, y) {
  return x + y;
}

// 함수 표현식
const sub = function (x, y) {
  return x - y;
};

Function 생성자 함수

자바스크립트 기본 제공 빌트인 함수 Function 생성자 함수에 매개변수 목록, 함수 몸체, 문자열 전달하면서 new 연산자와 함께 호출하고 객체를 생성 반환함

var add = new Function("x", "y", "return x + y");
console.log(add(2,5));//7

화살표 함수

ES6에서 도입된 화살표(arrow function)은 function 키워드 대신 화살표 ( => ) 를 사용해 더 간략한 방법으로 함수를 선언함.
👉 중괄호( {} )를 사용하지 않으면 return 작성하지않아도 됨, 만약 중괄호( {} )을 사용하면 return 을 명시하는 것이 좋다.

var add = (x, y) => x + y;

함수 호출

매개변수와 인수

함수의 외부에서 내부로 전달할 필요가 있는 경우 매개 변수(인자)를 통해 인수를 전달한다.

  • 인수 : 값으로 평가 될 수 있는 표현식, 함수 호출시 지정, 개수,타입 제한 없음
function add(x, y) {
  console.log(x, y); // 2, 5
  return x + y;
}
// 함수 호출 
var result = add(1, 2); // 인수 1,2 매개변수 x,y 순서대로 할당 함수 몸체 문들이 실행됨

console.log(x, y); // Uncaught ReferenceError: x is not defined 

👉 매개변수의 스코프는 함수 스코프로, 함수 바깥에서 x, y 에 접근하면 Uncaught ReferenceError 에러가 발생한다.
매개변수는 함수 외부에서 접근이 불가능함 연산 결과를 return해서 전달해야 함수 외부에서 변수에 결과를 저장할 수 있다.

function add(x, y) {
  return x + y; 
}

let result = add(2); // NaN
let result = add(1, 2); // 3
let result = add(1, 2, 3); // 3
  • 매개변수 > 인수개수 -> undefined 가 된다.
  • 인수 개수 > 매개변수 -> 나머지는 무시가 된다.

👉 초과된 인수는 버려지는것이 X, 모든 인수는 암묵적으로 arguments 객체의 프로퍼티로 보관됨.

인수 확인

  • 자바스크립트 함수는 매개변수와 인수의 개수가 일치하는지 확인하지 않는다.
  • 자바스크립트는 동적 타입 언어다. 따라서 자바스크립트 함수는 매개변수 타입을 사전에 지정 X
function add(x, y) {
  return x + y; 
}

// 문법상의 문제 없으므로 실행된다. 
console.log(add(2)) //NaN
console.log(add("a", "b")); // "ab"

👉 따라서, 자바스크립트의 경우 함수를 정의할 때 적절한 인수가 전달 되었는지 확인이 필요함

function add(x, y) {
  if (typeof x !== "number" || typeof y !== "number")
    throw new TypeError("인수는 모두 숫자 값이어야 합니다.");
}

  return x + y; // 1 + undefined

}

console.log(add(2)); // TypeError : 인수는 모두 숫자 값이어야 합니다.
console.log(add('a', 'b'); // TypeError : 인수는 모두 숫자 값이어야 합니다.

👉 또한, 함수 호출 시 매개변수 개수를 부족하게 전달할 시 단축 평가를 활용해 기본 값을 할당할 수 있다.

function add(a, b, c) {
  a == a || 0; // a 가 truthy 값이면 바로 a 할당.
  b == b || 0;
  c == c || 0;

  return a + b + c;
}
console.log(add(1, 2, 3)); //6
console.log(add(1, 2);//3
console.log(add(1)); //1
console.log(add()); //0

매개변수의 최대 개수

함수는 한 가지 일만 해야하며 가급적 작게 만들어야 한다. ( 많으면 유지 보수 차원에서 힘들다.)

반환문

반환문을 사용해 실행 결과를 함수 외부로 반환 할 수 있다.

function multiply(x, y) {
  return x * y; // 반환문
}

let result = multiply(3,5);
console.log(result); // 15

반환문의 역활

  • 반환문은 함수의 실행을 중단하고 함수 몸체를 빠져나옴.
  • 반환문 이후 다른 문이 존재하면 그 문은 실행되지 X

참조에 의한 전달과 외부 상태의 변경

함수 호출 시 인수가 매개변수에 전달 되는 과정을 말한다.

function changeVal(primitive, obj) {
  primitive += 100;
  obj.name = "Kim";
}

var num = 100;
var person = { name: "Lee" };

console.log(num); // 100
console.log(num); // {name: "Lee"};

// 원시 값은 값 자체가 복사되어 전달됨 객체는 참조 값이 복사되어 전달 
changeVal(num, person);

console.log(num); // 100
console.log(person); // {name:"Kim"};

// 원시 값은 원본이 회손되지 않는다. 
console.log(person); // {num}; //100

console.log(person); // {person}; // {name : "kim"}

❗하지만 객체가 변경할 수 있는 값이며, 참조에 의한 전달 방식으로 동작하기 때문에 부작용이 있다.

부작용 방지 방법

  • 객체의 불변성이 깨지는 것을 막고 싶다면 앞서 매개변수의 타입을 확인하는 기능을 추가하자.
  • 깊은 복사를 수행하도록 만들면 불변성을 지킬 수 있다.

다양한 함수의 형태

즉시 실행 함수

// 함수 정의와 동시에 호출 되는 함수를 의미함

// 익명 즉시 실행 함수
(function foo() {
  let a = 3;
  let b = 5;
  return a * b;
}());

(function foo() {
  let a = 3;
  let b = 5;
  return a * b;
}());

foo(); // ReferenceError : foo is not defined 

  • 즉시 실행함수는 정의된 직후 실행되며, 이후 다시 호출할 수 없다.
  • 즉시 실행함수는, 그룹 연산자로 감싸서 함수 리터럴로 평가되도록 만들어 함수 객체를 생성하는 방식이다.
let result = (function foo() {
  let a = 3;
  let b = 5;
  return a * b;
}());

console.log(result); // 15

즉시 실행 함수도 일반 함수처럼 값을 반환할 수 있다. 함수 스코프 내에서만 변수가 활용되기 때문에 전역변수와의 이름 중복을 해결할 수 있다.
또한 익명함수기 때문에 함수 이름 중복을 해결할 수 있다.

재귀 함수

함수가 자기 자신을 다시 호출하는 함수를 말한다.

function countDown(n) {
  for (let i = n; i >= 0; i--) console.log(i);
}

countDown(10);

function countdown(n) {
  if (n < 0) return;
  console.log(n);
  return countdown(n - 1); //재귀 호출 
}

countDown(10);

위 예시에서, 반복문을 사용한 countDown() 과 재귀함수 countdown() 은 동일한 기능을 수행한다.
이렇게 반복적인 작업을 대체하는 역할을 수행할 수 있다.

재귀 함수의 대표적인 예시가 팩토리얼을 구하는 함수다.

function factorial(n) {
  if (n <= 1) return 1;

 // 재귀 호출
  return n * factorial(n - 1);

  console.log(factorial(0)) // 0! = 1
  console.log(factorial(1)) // 1! = 1
  console.log(factorial(2)) // 2! = 2 * 1 =2
  console.log(factorial(2)) // 3! = 3* 2 * 1 = 6
// n! = 1 * 2 ..... * (n-1) *n -> 탈출 조건: n이 1이하 일때 재귀 호출을 멈춤 
}

❗ 재귀함수 사용 주의점

  • 재귀함수를 사용할 때, 탈출 조건을 반드시 구현해두어야 한다. -> 탈출 조건이 없을시 무한 반복문이 반복됨
  • 재귀함수는 대부분 반복문으로 대체가 가능하니, 재귀함수 사용시 함수 콜스택이 쌓이다 보니 스택 오버플로우 발생 위험이 있기 때문에 필요할때 사용하는게 좋다.

중첩 함수

함수 내부에 정의한 함수를 칭한다. 중첩 함수 또는 내부 함수라고 한다. -> 자신을 포함하는 외부 함수를 돕는 헬퍼 함수이다.

function outer() {
  let x = 1;

  function inner() {
    let y = 2;

    console.log(x + y);
  }

  inner();
}

outer();
// `inner()` 에서는 `outer()` 의 변수에 접근이 가능

콜백 함수

함수의 매개변수로 전달되는 함수를 말한다.

function repeat(n) {
  for (let i = 0; i < n; i++) {
     console.log(i) -> 이때 repeat 함수는 console.log(i)에 강하게 의존하여 다른일을 할수 없다. 
  }
}
repeat(5); // 0 1 2 3 4

// 다른일을 하도록 함수를 새롭게 정의
function repeat(n, f) {
  for (var i = 0; i < n; i++) {
    f(i); // i를 전달하면서 f를 호출 
  }
}

var logAll = function (i) {
  console.log(i);
};

repeat(5, logAll);

repeat 는 함수 logAll 을 전달 받아 수행한다.

logAll -> 콜백함수 repeat -> 고차함수 라고 한다. repeat로 전달된 logAll repeat내에서 스스로 실행시점을 결정하지 못하고 고차 함수에서 정해진 순서에 따라 실행된다.
콜백함수가 여러 곳에서 호출된다면, 전역 공간에 선언하거나 익명함수로 선언해 다른 곳에 사용되지 않도록 하는게 좋다.

순수 함수와 비순수 함수

순수 함수는 어떤 외부 상태에 의존하지 않고, 변경하지도 않는 함수를 말한다. 즉, 부수 효과가 없는 함수를 순수 합수라 한다.
비순수 함수는 그와 반대로 외부 상태에 의존하며, 변경하는 함수를 말한다. -> 부수 효과가 있음

👉 순수 함수는 매개변수를 통해 함수 내부로 전달된 인수만 사용해 값을 생성 후 반환한다.

📄 부수 효과란? 함수가 수행해야 하는 본연의 일 이외에 부수적으로 수행하는 일을 의미함.

let  countn = 0; // 현재 카운트를 나타내는 상태

// 순수 함수 increase는 동일한 인수가 전달되면 언제나 동일 값을 반환
increase(n){
  return ++n;
}

// 순수 함수가 반환한 결과값을 변수에 재할당해서 상태를 변경 
counst = increase(count);
console.log(counst); // 1 

counst = increase(count);
console.log(counst); // 2
let  countn = 0; // 현재 카운트를 나타내는 상태

// 비순수 함수 
increase(){
  return ++countn; // 외부 상태에 의존, 외부 상태 변경 시킴 
}

// 비순수 함수는 외부 상태(count)를 변경하므로 상태 변화를 추적하기 어려워진다. 
increase();
console.log(countn); // 1 

increase();
console.log(countn); // 2
profile
매일매일 틀깨기

0개의 댓글