Frontend 개발자 - hyo.loui

모던 javascript - 함수 본문

Javascript

모던 javascript - 함수

hyo.loui 2023. 2. 1. 17:05

❤️‍🔥TIL : Today I Learned

 

 

함수는 마치 재료를 투입받아 제품을 생산하는 기계와 같다.

 

함수

자바스크립트에서 가장 중요한 핵심 개념

[스코프, 실행 컨텍스트, 클로저, 생성자함수에 의한 객체 생성,메서드, this, 프로토타입, 모듈화] 등이
모두 함수와 깊은 관련이 있다.

 


함수란

 

 

함수는 일련의 과정을 문(statement)으로 구현하고,

코드블록으로 감싸서 하나의 실행단위 로 정의한 것 이다.

여기서 자주 햇갈리는 내용인 매개변수와 인수가 있다.

 

매개변수(parameter)는 함수를 선언(정의)할 때 사용하는 변수를 의미한다.

인수(argument)는 함수를 호출할때, 즉 입력될 때 넣는 값을 인수라고 한다.

 

 

 

  • 함수 정의

함수를 정의는 다양한 방법이 있지만 함수 선언문을 사용하여 정의한 코드이다.

function introduce (name, age) {
  return `Hello, I'm ${name}!, ${age} old`;
}

여기서는 function 이라는 함수 선언 키워드 뒤에 함수명(=식별자)을 적고,

중괄호로 { 코드 } 를 감싸 작성한다.

 

단 함수의 정의만으로 함수가 실행되는 것은 아니다.

 

 

  • 함수 호출

함수 호출이란 미리 정의된 함수를 실행시키기 위해 필요한 입력을 해주는 것이다.

입력한 인수는 매개변수를 통해 함수에 전달하여 함수실행 시키는 명령어 이다.

var intro = intoduceMyself(승효, 27)

console.log(intro) // Hi I'm 승효, 27 old!

 

함수를 호출하면 코드 블록에 담긴 문들이 일괄적으로 실행되고,

실행 결과반환값을 반환한다.

 

+ 매개변수와 인수는 생략이 가능하다.

 


함수를 사용하는 이유

 

가장 중요한 핵심은 함수는 몇 번이든 호출할 수 있어

코드의 재사용이라는 측면에서 매우 유용하다.

 

 


함수 리터럴

 

함수는 객체 타입의 값이다.

{ function 키워드, 함수 이름, 매개변수 목록, 함수 몸체 } 로 구성된다.

 

// 변수에 함수 리터럴을 할당
var add = function (x, y) {
 return x + y;
};
  1. 함수 이름
    • 네이밍 규칙을 준수한 식별자
    • 함수 몸체 내에서만 참조할 수 있는 식별자
    • 함수 이름은 생략 가능
      • 기명 함수(named function): 이름이 있는 함수
      • 익명 함수(anonymous function): 이름이 없는 함수
  2. 매개변수 목록
    • 0개 이상의 매개변수를 괄호로 감싸고 쉼표로 구분 (a, b)
    • 매개변수에 인수 할당
    • 매개변수는 함수 몸체 내에서 변수와 동일하게 취급되기 때문에 식별자 네이밍 규칙 준수
  3. 함수 몸체
    • 함수가 호출되었을 때 일괄적으로 실행될 문들을 하나의 실행 단위로 정의한 코드 블록
    • 함수 호출에 의해 실행됨

 

 

함수 리터럴과 함수 선언문의 차이

그룹 연산자 ( )안에 들어오는 것은 피연산자이다.

피연산자로 들어오는 것은 리터럴 , 값이어야만 한다.

결국, ( function foo( ) { } )는 리터럴 및 값이 되는것이다.

 

함수 리터럴은 이름을 가질수도 있고, 안가질수도 있다.
함수 리터럴의 식별자는 자신의 몸체 내부에서만 유효 하다.

 

그룹 연산자 ( ) 내에 있는 것은 함수 선언문이 아니다.
다시 말해, 자바스크립트 엔진은 그룹 연산자 () 내에 있는 문을 함수 선언문이 아닌 함수 리터럴로 해석한다.


그룹 연산자의 피연산자는 값으로 평가할 수 있는 표현식이다.
따라서 표현식이 아닌 문인 함수 선언문은 피연산자로 사용할 수 없다.


함수 정의

 

함수를 정의 하는 방법에는 4가지가 있다.

 

 

 

1. 함수 선언문

function introduce (name, age) {
  return `Hello, I'm ${name}!, ${age} old`;
}

함수 선언문은 함수이름을 생략할 수 없다. 표현식이 아닌 문 이다.

 

 

 

2. 함수 표현식

// 함수 표현식
var add = function plus (x, y) {
    return x + y;
};

 위에 함수 리터럴에서 설명한 것과 같은 맥락으로

plus() 를 직접 호출할 수 없고, add() 호출을 해야 실행이 가능하다.

왜냐하면, 함수는 함수이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출한다.

 

여기서 무명함수라고 한다면,

자바스크립트 엔진은 함수를 호출하기 위해 함수 이름과

동일한 이름의 식별자를 암묵적으로 생성하고, 거기에 함수 객체를 할당한다.

 

 

3. function 생성자 함수

 

생성자 함수란 ? 객체를 생성하는 함수

따라서 Function 생성자 함수 는 함수라는 객체를 생성하는 함수다.

 

// 첫번째 인수, 두번째 인수, 마지막 인수는 반환값
var add = new Function('x', 'y', 'return x + y');

console.log(add(2, 5)); // 7
  • 생성된 함수는 클로저를 생성하지 않음
  • 함수 선언문이나 함수 표현식으로 생성한 함수와 생성자 함수는 동일하게 동작X

 

4. 화살표 함수 (ES6)

 

생성자 함수란 ? 객체를 생성하는 함수

따라서 Function 생성자 함수 는 함수라는 객체를 생성하는 함수다.(항상 익명 함수)

 

+ 축약형으로 간략하게 사용하기에 유리하다

 

/ 화살표 함수
const add = (x, y) => x + y;

console.log(add(2, 5)); // 7

 

화살표 함수는 대부분을고차함수 콜백 함수에 이용한다.

  • 기존의 함수와 this 바인딩 방식이 다름
  • prototype 프로퍼티 없음
  • arguments 객체를 생성하지 않음

위 부분에서는 생성자 함수, this, 프로토타입, arguments 객체의

배경지식이 필요하기에 26장 3절 '화살표 함수' 에서 자세히 다룬다.

 


함수 호출시 유의 사항

 

함수를 실행하기 위해 필요한 값을 함수 외부에서 내부로 전달할 필요가 있는 경우,

매개변수를 통해 인수를 전달한다.

 

인수는 값으로 평가될 수 있는 표현식이어야 한다.

인수는 함수를 호출할 때 지정하며, 개수와 타입에 제한이 없다. 

또한 배열 처럼 순서에 의존하기 때문에

호출 시점의 인수의 순서대로 매개변수에 대입된다.

 

또한 제한이 없다고 해도,

이상적인 함수는 한가지 일만 해야 하며 가급적 작게 만들어야 한다.

 

 


다양한 함수의 형태

  1. 즉시 실행 함수
  2. 재귀함수
  3. 중접함수
  4. 콜백함수 ** 중요
  5. 순수함수와 비순수 함수

 

즉시 실행 함수 ( IIFE )

단 한번만 호출되며 다시는 호출 할 수 없다. (리액트 useState 개념과 비슷하다)

 

즉시 실행 함수는 익명 즉시 실행 함수를 사용하는 것이 일반적이다.

클로저를 쓸 때 사용된다.

의외로 많이 사용되고, 내부 변수는 지역변수가 되어 충돌을 방지할 수 있다.

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

 

재귀함수

자기 자신을 호출하는 함수

재귀 함수는 무한 호출되며 stack overflow에러를 유발할 위험이 다분하다.

따라서 최대한 적게 이용하고 대부분은 재귀함수는 while, for( + if )등으로 대체가 가능하다.

 

직접 코드에 사용하는 일은 드물지만 알고리즘 문제에 간혹 등장한다.

// 팩토리얼(계승)은 1부터 자신까지의 모든 양의 정수의 곱이다.
// n! = 1 * 2 * ... * (n-1) * n
function factorial(n) {
  // 탈출 조건: n이 1 이하일 때 재귀 호출을 멈춘다.
  if (n <= 1) return 1;
  return factorial(n - 1) * n;
}

console.log(factorial(0)); // 0! = 1
console.log(factorial(1)); // 1! = 1
console.log(factorial(2)); // 2! = 1 * 2 = 2
console.log(factorial(3)); // 3! = 1 * 2 * 3 = 6
console.log(factorial(4)); // 4! = 1 * 2 * 3 * 4 = 24
console.log(factorial(5)); // 5! = 1 * 2 * 3 * 4 * 5 = 120

 

 

중첩함수 *

함수 내부에 함수가 있을 수 있다.

이를 중첩 함수(nested function) 또는 내부 함수(Inner function)라 한다.

(리액트를 사용해 보았다면, 함수형 컴포넌트 내부에 함수를 만드는 것과 비슷하다)

function outer() { //1. outer의 네이밍 값을 변수 선언문에 변수로 저장하여 호이스팅됨 (함수가 다 저장됨)
  var x = 1; 			//3. x = undefined값으로 초기화됨 
									//5. x에 1을 할당
  
  function inner() { // 3-1. 호이스팅되서 런타임전에 메모리 값이 잡힘 7. inner 함수 들어감
    var y = 2; //8. y값 undefined 할당 -> 9. 런타임 실행 -> 10. y에 2할당 
    
    console.log(x + y);  //11. x+y값 평가 후 출력
      //12 return문이 없으면 undefined가 할당되서 함수를 빠져나옴
  } //4. undefined로 잡힘 -> 런타임실행

  inner(); //6. inner 함수 실행
  
  console.log(x + y);  //13. 실행
    //변수는 하위변수을 참조할 수 없어서 y값에 할당될 값이 없어서 1 + y 가 되지만 y값이 선언조차 안되서 referenceerror가뜸 
    // return undefined 생략되있음 
}

outer();//2. 실행

 

 

 

콜백함수 ** 중요

 

콜백함수는 고차함수에 인수(Argument) 로써 사용되는 함수를 뜻한다.

고차함수는 매개변수를 함수로 받는 함수를 말한다.

// outer는 고차함수다. - 이유는 매개변수를 함수로 받고 있다.
function outer(fn) {
  var x = 1;
  var y = 2;
  return fn(x, y);// 3
} 

// 일반함수
function inner(x, y) {
  var dd = x + y;
  return dd;
}

console.log(
  // outer라는 고차함수에 inner을 넣음으로 inner는 콜백함수가 되었다.
  outer(inner)
);

기본적으로 콜백함수는 고차함수를 사용할 때 사용하며, 가능한 이 함수들은 루프를 도는 형식이기에 사용을 하지 않도록 최대한 노력을 해야한다.

고차함수들로는 map,filter,reduce,find 등등이 있다.

map, filter의 예

 

// 콜백 함수를 사용하는 고차 함수 map
var res = [1, 2, 3].map(function (item) {
  return item * 2;
}); //내부에서는 for문이 돈다
//배열[1,2,3]객체가 가지고 있는 메서드(map)

console.log(res); // [ 2, 4, 6 ]

// 콜백 함수를 사용하는 고차 함수 filter
res = [1, 2, 3].filter(function (item) {
  return item % 2;
});

console.log(res); // [ 1, 3 ]

 

 

순수 함수와 비순수 함수

 

아주 간단하다

 

순수 함수 = 외부 상태에 의존하지 않고, 외부상태를 변경하지도 않는 함수

비순수 함수 = 외부 상태에 의존하거나, 외부상태를 변경하는 함수

 

// 순수 함수
var count = 0;

function increase(n) {
 return ++n;
}

위 순수 함수에서는 count에 연결된 어떤 것도 없다.

 

// 비순수 함수
var count = 0;

function increase() {
 return ++count;
}

위 비순수 함수는 count 변수가 없다면 에러가 발생할 것이고,

count 라는 변수를 증가연산하므로 호출시 매번 변수의 상태를 변화시키기 때문에

비순수 함수라고 한다.

 


 

 최종 정리

  1. 함수를 정의하고, 호출 함으로써 정의한 코드블럭을 실행할 수 있다.
  2. 함수를 사용하는 이유중 가장 핵심은 코드의 재사용 이다. (반복을 줄임)
  3. 함수는 객체 타입의 값이다. 함수 리터럴은 function 키워드, 함수이름, 매개변수 목록, 함수몸체로 구성된다.
  4. 함수는 함수 선언문, 함수 표현식, function 키워드 생성자 함수, 화살표 함수 4가지로 정의한다.
  5. 이상적인 함수는 한가지 일만 해야 하며 가급적 작게 만들어야 한다
  6. 함수의 형태는 6가지가 있다.
    1. 즉시 실행 함수 (function(){})
    2. 재귀함수 function oo(){oo()}
    3. 중접함수 function (){function(){}}
    4. 콜백함수 ** 중요 function(function(){}){}
    5. 순수함수와 비순수 함수

 

'Javascript' 카테고리의 다른 글

모던 javascript - strict mode  (0) 2023.02.03
모던 javascript - 프로퍼티 어트리뷰트  (0) 2023.02.02
모던 javascript - 제어문  (0) 2023.01.31
모던 javascript - 변수  (1) 2023.01.30
자바스크립트 - 모듈  (0) 2022.12.12