language/javaScript

5. JS 핵심 - 함수

wooweee 2023. 4. 19. 12:15
728x90

1. 함수의 선언과 함수 표현식

  1. 함수는 항상 값을 반환한다. return 값이 없더라도 undefiend를 반환한다.
  2. 함수 표현식 : 함수 앞에 변수 붙여주는 것
  3. 람다식
  4. IIFE : 즉시 호출 함수 표현식 - 람다식과 유사, 일회용
// 1. 함수 선언
function add1(a, b) {
  return a + b;
}
console.log(add1(1, 2));

// 2. 함수 표현식
var add2 = function (a, b) {
  return a + b;
};
console.log(add2(3, 4));

// 3.lambda식
// sort() comparator 했던 것

// 4. IIFE
console.log(
  (function (a, b) {
    return a + b;
  })(5, 6)
);

 

2. 호출과 arguments 객체

  • arguments 객체
    • 배열같은 객체 : lenth를 제외하곤 배열 property 존재하지 않는다.
    • 함수 호출시 params의 개수 및 값을 알 수 있다.
    • arguments를 이용한 function은 params가 무제한으로 들어가진다.
      == 가변인자와 유사한 역할 수행
function findMax() {
  var i;
  var max = -Infinity;

  console.log(arguments);
  console.log(arguments.length);

  for (i = 0; i < arguments.length; i++) {
    if (arguments[i] > max) max = arguments[i];
  }
  return max;
}

console.log(findMax(1, 23, 44, 2)); // arguments를 이용한 function은 params가 가변인자 처럼 작동한다.

 

3. 함수의 오버로딩

  • JS는 실질적으로 params에 들어가는 type이란게 없어서 오버로딩 개념이 없다.
  • 하지만 굳이 만들려면 if문을 통해서 만들 수 있다.

 

4. 유효성검사와 매개변수 초기화

  • function 호출시 params의 개수가 빠져있을 경우 기본값을 넣어둔다.
  • es6 이후 params에 (a=0, b=0) 이렇게 실제 기본값을 넣어 둘 수 있다.

 

 

5. 클로저

  • 전역변수의 선언으로 인한 변수이름 충돌 문제 해결 과정
  •  

 

  • 문제코드
var cnt = 0;  // 전역변수 변수이름 충돌가능성 존재
function increaseCnt() {
  cnt++;
}

increaseCnt();
increaseCnt();
increaseCnt();
console.log(cnt);

 

  • 해결1
  • 문제점 : 지역변수 scope를 줄였지만 매번 0으로 초기화. 외부에서 사용 못함
function increaseCnt() {
  var cnt = 0; // 지역변수 scope를 줄였지만 매번 0으로 초기화. 외부에서 사용 못함
  cnt++;
}

increaseCnt();
increaseCnt();
increaseCnt();
console.log(cnt); // is not defined error

 

  • 해결2
  • 문제점: 내부에서만 사용가능
function closure() {
  var cnt = 0; // 지역변수 scope를 줄였지만 매번 0으로 초기화. 외부에서 사용 못함
  function increaseCnt() {
    cnt++;
    console.log(cnt);
  }
  increaseCnt();
  increaseCnt();
  increaseCnt();
}

console.log(closure());
console.log(increaseCnt()); // not defined error

 

  • 해결3
  • return으로 내부값 반환
function closure() {
  var cnt = 0; // 지역변수 scope를 줄였지만 매번 0으로 초기화. 외부에서 사용 못함
  return function () {
    // 이름 생략가능
    cnt++;
    console.log(cnt);
  };
}
var increaseCnt = closure(); // 함수 표현식
increaseCnt();

// increaseCnt = function(){ var cnt = 0; return function(){} }

 

  • 활용

 

  • 비동기함수 와 콜백 문제점 및 해결
    • 비동기함수들이 대부분 내부에 콜백 함수를 가지고 있다.
    • 비동기 함수는 해당 함수가 호출되고 비동기 함수내부의 콜백함수로 부터 return되어야되는 값을 당장 호출하지 않고 외부에서 처리해야하는 값을 다 수행한 후에 다 수행한 결과를 토대로, 콜백함수가 외부에서 다 수행한 결과값을 요리해서 반환을 한다.
  • 비동기함수와 콜백 함수 <-> closure 구분할 줄 알아야한다.
    • 비동기함수는 내부에 변수값 이런게 중요하지 않다. 호출하면 사용한 변수 값의 최종 처리값을 이용
    • closure은 outter function 변수를 이용해서 inner function이 값을 호출한다.
// 클로저 함수

function outer() {
  const name = 'John';

  function inner() {
    console.log(`My name is ${name}`);
  }

  return inner;
}

const innerFunc = outer();
innerFunc(); // My name is John

// 비동기 함수
for (var i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i);
  }, 0);
}

 

for (var i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i);
  }, 0);
}
// 3,3,3 결과가 나온다. - 이유 설명

// 위의 코드의 var은 함수스코프를 가지므로 아래와 같이 분리 가능

var i;
for (i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i);
  });
}

// 콜백함수를 가지고 있는 것이 비동기 함수라고 했는데 별거 없다.
// 함수 내부에 함수가 존재하고 내부 함수가 외부 변수를 사용하면 그게 비동기 함수이다.

// 설명
//1. setTimeout()이라는 비동기 함수가 호출 
//2. 즉시 수행이 되지 않고 for문의 i를 먼저 수행 
//3. 수행 다되면 setTimeout() 콜백함수 호출
//결론 : 그래서 3 만 나오게 됨

var i;
for (i = 0; i < 3; i++) {
  console.log("비동기 i 증가 수행: " + i);
  setTimeout(function () {
    console.log(i);
  });
}
// 결과
// 0,1,2,3 -> setTimeout() = 3
// 3 -> setTimeout() = 3 // var i가 최초에 3으로 설정된 후 이게 for문이 끝날때 까지 유지
// 3 -> setTimeout() = 3

// 해결방안
// 1. let을 통해서 loop 걸어주기
// 2. closure 사용

let i; // 전역scope에 위치하므로 3,3,3 나옴
for (i = 0; i < 3; i++) {
  console.log("비동기 i 증가 수행: " + i);
  setTimeout(function () {
    console.log(i);
  });
}
// 지역 scope로 걸어서 block이 다 수행된 후 다음 for문 loop 돌도록
for (let i = 0; i < 3; i++) {
  console.log("비동기 i 증가 수행: " + i);
  setTimeout(function () {
    console.log(i);
  });
}

// closure
var i;
for (i = 0; i < 3; i++) {
  // 제일 외부 function은 비동기 함수가 아니므로 동기함수로 수행
  // 내부 setTimeout 비동기함수는 외부function으로 부터 받은 값이 최종값이라고 인식
  (function (i) {
    setTimeout(function () {
      console.log(i);
    });
  })(i);
}

 

 

6. JS와 비동기

 

  • JavaScript에서 비동기 함수가 존재하는 이유는 크게 두 가지
    1. JavaScript가 싱글 스레드로 동작
      • JavaScript는 한 번에 하나의 작업만 처리가능
      • 만약 JavaScript에서 오랜 시간이 걸리는 동기 함수를 호출하면 해당 함수가 끝날 때까지 다른 작업을 수행하지 못하고 대기 -> 웹 애플리케이션에서 사용자 경험을 저하시키는 요인
      • JavaScript에서는 비동기 함수를 통해 이러한 문제를 해결
        -> 비동기 함수를 호출하면 해당 함수는 백그라운드에서 실행되며, JavaScript는 다른 작업을 수행

    2. JavaScript가 네트워크와 같은 외부 리소스와 상호작용하는 일이 많기 때문
      • 네트워크 작업은 일반적으로 시간이 많이 걸리는 작업
      • JavaScript에서 네트워크 작업을 동기적으로 처리하면 애플리케이션이 멈춰보일 수 있습니다.
      • JavaScript에서는 비동기 함수를 통해 네트워크와 같은 외부 리소스와 상호작용하는 작업을 처리

 

  • 비동기 함수 설정 기준
    • 특정 메서드가 오래 걸리는지를 판단하기 위해서는 그 메서드가 처리하는 작업의 양과 복잡도, 그리고 실행 환경의 상황 등을 고려 일반적으로 I/O 작업이나 네트워크 요청 등은 시간이 많이 소요되기 때문에 이러한 작업들은 비동기 함수로 처리하는 것이 좋다.

    • 개발자가 직접 코드를 실행해보고 시간 측정 도구를 사용해서 해당 메서드의 실행 시간을 측정
    • 이를 통해 어느 정도 시간이 걸리는지를 확인하고 최적화를 시도

 

  • 비동기 생성
    •  자바스크립트에서는 비동기 함수를 생성하는 방법으로 콜백 함수, Promise, async/await 등을 제공
    • 개인이 직접 함수를 만들어 비동기 처리를 할 수도 있으며, 이는 자바스크립트의 유연성과 확장성에 기인
    • 하지만 이러한 직접 구현하는 것보다 이미 제공되는 비동기 함수를 사용하는 것이 안전하고 효율적