[JavaScript] Function

aseol·2023년 10월 18일
0

JavaScript

목록 보기
7/15

Function

  • 자바스크립트 함수는 익명함수와 일반함수가 있다.
    ( 일반함수는 호이스팅 ⭕ 익명함수는 호이스팅 ❌ )

익명함수
Anonymous Function
이름이 없기 때문에 그 자체로는 호출되지 않고 사용되지 않는다. ➡️ 함수를 활용하려면 변수에 할당하여 사용해야 한다.
(이렇게 변수에 할당된 함수를 함수 표현식이라고 한다. )

const fn1 = function () {
	console.log('This is an anonymous function.');
    };
   
   익명함수를 변수 fn1에 할당하여 선언 

일반함수
Named Function
함수에 이름을 지정하여 함수를 선언한다.
(이를 함수 선언식이라 한다.)
일반함수도 변수에 할당하여 사용할 수 있다.

const fn2 = function fn3 () {
	console.log('일반함수 fn3을 변수 fn2에 할당 후 호출');

fn2(); 

❗변수에 할당했으므로
변수명으로 호출이 가능하다 ( 함수명 X )
위에서 호출 X ( ∵ 함수 표현식이므로 호이스팅 X )

  • 하나의 함수는 한 가지의 일만 하도록 만들어야 한다.
  • 함수는 어떤 동작을 수행하는 것이므로 함수의 이름은 command, verb, doSomething 형태로 짓는 것이 좋다.
  • 자바스크립트에서 함수는 object로 간주
    ➡ 함수를 변수에 할당, 함수를 파라미터로 전달, 함수를 리턴하는 것이 가능하다.

선언

function이라는 키워드로 선언하여 코드를 저장한다.

return

  • 함수 내에서 쓰일 수 있는 키워드
  • 함수를 호출하는 곳에 값을 전달할 수 있다.
  • 함수를 강제 종료한다.
function ex () {
if ( 조건에 맞지 않는다면 ){
 	// 조건에 맞지 않는다면 빨리 함수를 종료하도록 early return!
     return;
    }
    // 조건에 맞는다면 실행할 긴 로직들 작성 ···
 }   
  • 함수 return이 가능하다 ➡️ ( 고차함수: 함수를 반환하거나 다른 함수들을 전달인자로서 사용하는 함수 )
  • 리턴이 없는 함수들은 return undefined가 쓰여 있는 것과 같다. ( 생략 가능 )

내부함수

함수 내의 함수

외부 함수 내에서 선언되었기 때문에, 외부 함수의 스코프에서만 접근할 수 있다.

let globalMessage = 'global hello'; // 전역변수
function printMessage() {
    let message = 'Hello'; // 지역변수 
    console.log(message); 
    console.log(globalMessage); 
        // 자식함수
    function printAnother() {
        console.log(message); // 부모함수에서 정의된 변수에 접근 가능
        let childMessage = 'hello';
    }
    // 자식함수 내부에 정의된 변수에 접근하려 하니 에러 발생 
    console.log(childMessage); 
}

printMessage(); 
// printAnother(); // 에러 발생 

호출

  • 함수를 호출하려면 먼저 선언이 되어 있어야 한다.
  • 함수 내부에서 인자 값을 받을때 매개변수로 받는다.
  • 함수 호출시 함수를 인수로 받아 매개변수에 할당된 함수를 호출할 수 있다.
  • let, const, var를 작성하지 않아도 된다.

함수명 혹은 참조변수 ( ) ; ➡️ 함수 실행
함수 호출시 인수를 삽입하여 호출할 수 있다.

parameter

premitive parameter

premitive 타입은 메모리에 value가 그대로 저장되어 있기 때문에 value가 전달된다.

object parameter

object는 메모리에 reference가 저장되어 있기 때문에 reference가 전달된다.

changeName은 전달된 object의 name을 영희로 바꾸는 함수이다. 
즉 kid.name의 값을 영희로 바꾼다.

default parameter

JavaScript 함수 정의 시 매개변수의 기본 값을 설정하는 기능.
이를 통해 함수가 호출될 때 특정 매개변수가 제공되지 않으면, 그 매개변수는 기본 값을 가지게 된다.

default parameter 사용 X ⬇️

default parameter 사용 O ⬇️

rest parameter

나머지 매개변수

나머지 매개변수 사용시, 함수가 정해지지 않은 수의 매개변수를 배열로 받을 수 있다.
함수의 마지막 매개변수 앞에 ... 를 붙이면 (사용자가 제공한) 모든 후속 매개변수를 표준 JavaScript 배열에 넣도록 지정한다. 마지막 매개변수만 나머지 매개변수로 설정할 수 있다.

function test (a, b, ...manyMoreArgs){
    console.log(a);
    console.log(manyMoreArgs);

}

test('blue', 'red', 'black', 'yellow', 'wihte');
test('apple', 'pear', 'pitch');
test('tomato', 'banana'); 

⬇️

첫 번째 인수는 a, 두 번째 인수는 b로 맵핑된다.
➡️ 매개변수를 두 개만 제공하면 manyMoreArgs는 빈 배열

arguments

파라미터는 함수 정의 시에 사용되는 변수들을 나타내고,
인수는 함수 호출 시에 파라미터에 전달되는 실제 값들을 나타낸다.

💡arguments 객체

함수에 전달된 인수에 해당하는 Array 형태의 객체.
arguments 객체를 사용하여 함수 내에서 모든 인수를 참조할 수 있으며, 호출할 때 제공한 인수 각각에 대한 항목을 갖고 있다. 항목의 인덱스는 0부터 시작한다.

예시 1>

function func1(a, b, c){
	console.log(arguments[0] + arguments[1]);
    console.log(c);
}

func1(100, 7, 3);

예시 2>

⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

완전 기본적인 개념도 잘 모르는 상태에서 이러한 코드를 처음에 봤을 때 
함수를 선언할 때 파라미터를 작성하지 않았는데 어떻게 인수를 받아서 
함수를 호출할 수가 있는지 의아했다. 
알고 보니 JS의 함수는 파라미터를 명시적으로 선언하지 않아도
내부에서 arguments 객체를 사용하여 인수를 받을 수 있고, 
전달된 모든 인수들에 접근할 수 있다고 한다.

RESTparameterarguments 객체의 차이

  • arguments 객체는 유사 배열이지 실제 배열이 아니다. 그러나 나머지 매개변수는 Array 인스턴스이므로 sort, map, forEach, pop 등의 메서드를 직접 적용할 수 있다.
  • ...restParam은 후속 매개변수만 배열에 포함하므로 ...restParam 이전에 직접 정의한 매개변수는 포함하지 않는다. 그러나 arguments 객체는, ...restParam의 각 항목까지 더해 모든 매개변수를 포함한다.

💫 callback function

다른 함수에 전달인자로 전달하는 함수

🏹 arrow function

화살표 함수 표현은 전통적인 함수표현의 간편한 대안이다.

작성방식
( ) => { }
소괄호 안에 parameter 작성하고 중괄호 안에 함수 내용 작성 🔽
🔹 parameter가 하나인 경우 ➡️ 괄호 생략 가능

const fn1 = a => {
	return a;
}

🔹 함수 내용이 한 줄인 경우 ➡️ 중괄호 생략 가능 & return 키워드 생략 가능

const fn1 = (a, b) => a + b;

위처럼만 작성해도 a + b가  리턴된다 

❗ 화살표 함수는 this, arguments나 super에 대한 자체 바인딩 ❌

this

const obj = {
    value: 42,
    getValue: function() {
      console.log(this.value); // 일반 함수에서의 this 바인딩
    },
    
    getArrowValue: () => {
        console.log(this.value); // 화살표 함수에서의 this 바인딩
      }
    };

obj.getValue();         
obj.getArrowValue();

다른 함수 선언 방식에서는 함수를 호출하는 시점에 따라 
this가 동적으로 결정된다.
하지만 화살표 함수에서는 그런 동적인 바인딩이 없고, 
⚡(즉 화살표 함수는 자신만의 this가 없다) 
lexical scope(상위 스코프)의 this가 사용된다.
즉 화살표 함수의 this의 동작은 화살표 함수가 정의된 시점에서 결정되며 
후에 어떤 위치에서 어떤 방식으로 호출되더라도 이에 영향을 받지 않는다. 
어떻게 보면 참 뚝심 있는 애 같다.

이러한 동작으로 인해 화살표 함수는 주로 콜백 함수나 다른 함수 내에서 
this 바인딩 문제를 해결하는 데 유용하다.


setTimeout과 같은 일부 브라우저 내장 함수들은 실행 컨텍스트(context) 내에서의 this 값을 웹 브라우저 환경에서 전역 객체에 해당하는 window 객체로 설정한다.
이러한 동작은 초기 JavaScript의 설계 원칙 중 하나이다.

화살표 함수를 이용하면 this가 Timer 객체를 가리키게 할 수 있다

arguments

const regularFunction = function() {
    console.log(arguments); // 일반 함수에서의 arguments 바인딩
  };
  
  const arrowFunction = () => {
    console.log(arguments); 
    // 화살표 함수에서의 arguments 바인딩 --> 오류 발생
  };
  
regularFunction(1, 2, 3); 
arrowFunction(1, 2, 3);   

⬇️

이렇게 오류가 나기 때문에 화살표 함수 내에서 인수들을 다룰 때는 
REST parameter를 사용하는 것이 대안이 될 수 있다.

⬇️

const arrowFunction = (...args) => {
    console.log(args); 
  };

methods로 사용 ❌

생성자(Constructor)로 사용 ❌

➡️ new와 함께 사용하면 오류 발생


IIFE

Immediately Invoked Function Expression (즉시 호출 함수 표현)
: 정의되자마자 즉시 실행되는 함수

전역 스코프에 불필요한 변수를 추가해서 오염시키는 것을 방지할 수 있을 뿐 아니라 IIFE 내부안으로 다른 변수들이 접근하는 것을 막을 수 있는 방법이다.

  • IIFE를 변수에 할당하면 IIFE 자체는 저장되지 않고, 함수가 실행된 결과만 저장된다.
  • IIFE는 일반 함수나 익명 함수 모두 사용할 수 있지만 일반적으로 익명 함수로 사용되는 경우가 더 많다 ( ∵ 익명 함수로 IIFE를 사용하는 경우에는 함수 이름이 없기 때문에 전역 스코프에 추가적인 이름 충돌을 일으키지 않는다 ).

작성 방식 🔽

( function( ) { ··· } ) ➡️ 함수 표현식 전체를 괄호로 감싸고
( ) ; ➡️ 함수를 호출하는 형태

(function hello(){	
	console.log('IIFE');
    })();

Recursive function

재귀 함수

함수는 자신을 호출할 수 있다.


콘솔에 10부터 1까지 출력해 보기 

function recurFn(number){
    console.log(number);
    if(number <= 1) return; //함수 종료
    return recurFn(number-1); // 재귀 호출
}

recurFn(10);

⬇️

🆙 10!를 구해서 출력해 보자

내가 쓴 코드 ⬇️
function factorial(number){
    if(number <= 1) return;
    return number * factorial(number-1);
}

console.log(factorial(10)); // NaN

NaN이 나오는 이유는 1 이하일 경우에 어떠한 값도 누적시키지 않고
undefined가 반환되기 때문이다

console.log(factorial(1)); //  undefinedfactorial(10)을 호출하면 10*9* ··· *2*1이 아니라 
10*9* ··· *2*undefined가 되어서 NaN이 반환된 것이다.

수정 ⬇️

function factorial(number){
	if(number <= 1) return 1; 
    
    return number * factorial(number-1);
}

console.log(factorial(10));

0개의 댓글