함수
12.1 함수란?
- 프로그래밍 언어의 함수는 일련과정을 문으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것이다
- 함수는 값이며, 식별자인 함수 이름을 사용할 수 있다
- 함수는 함수 정의를 통해 생성한다
- 인수를 매개변수를 통해 함수에 전달하면서 함수의 실행을 명시적으로 지시해야 한다. 이를 함수 호출이라 한다.
12.2 함수를 사용하는 이유
- 함수는 객체 타입의 값이다. 따라서 이름을 붙일 수 있다.
12.3 함수 리터럴
- js의 함수는 객체 타입의 값이다
- 함수도 식별자 네이밍 규칙을 준수해야 한다
- 매개변수도 변수와 마찬가지로 식별자 네이밍 규칙을 준수해야한다
- 함수 리터럴도 평가되어 값을 생성하며, 이 값은 객체이다. 즉 함수는 객체이다.
- 일반 객체는 호출할 수 없지만 함수는 호출할 수 있다
- 그리고 일반 객체에는 없는 함수 객체만의 고유한 프로퍼티를 갖는다
12.4 함수 정의
- 정의된 함수는 자바스크립트 엔진에 의해 평가되어 함수 객체가 된다.
변수 선언과 함수 정의
- 함수 선언문이 평가되면 식별자가 암묵적으로 생성되고 함수 객체가 할당된다
- 변수에는 선언, 함수에는 정의라고 표현한다.
12.4.1 함수 선언문
- 함수 선언문은 함수 리터럴과 형태가 동일하다
- 함수 리터럴은 함수 이름을 생략할 수 있으나 함수 선언문은 함수 이름을 생략할 수 없다
- 함수 선언문은 표현식이 아닌 문이다.
- 표현식이 아닌 문은 변수에 할당할 수 없다
- 함수선언문도 표현식이 아닌 문이므로 변수에 할당할 수 없다
- 하지만 함수 선언문은 함수 이름을 생략할 수 없다는 점을 제외하면 함수 리터럴과 형태가 동일하다.
이는 기명 함수 리터럴은 함수 선언문 또는 함수 리터럴 표현식으로 해석될 가능성이 있다는 의미이다.
- 가명 함수 리터럴은 중의적인 코드이다.
- 함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석하고
- 함수 리터럴을 변수에 할당하거나 피연산자로 사용하면 함수 리터럴 표현식으로 해석한다
- 함수는 함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출한다
12.4.2 함수 표현식
- 값의 성질을 갖는 객체를 일급 객체라 한다
- Js의 함수는 일급 객체이다.
- 함수를 값처럼 자유롭게 사용할 수 있다는 의미이다
- 함수 선언문은 '표현식이 아닌 문'이고, 함수 표현식은 '표현식인문'이다
12.4.3 함수 생성 시점과 함수 호이스팅
- 함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 함수 호이스팅이라 할 수 있다
- 런타임 이전의 자바스트립트 엔진에 의해 먼저 실행되어 식별자를 생성한다는 점에서 동일하다
- var 키워드로 선언된 변수는 undefined로 초기화되고, 함수 선언문을 통해 암묵적으로 생성된 식별자는 함수 객체로 초기화된다
12.4.4 Function 생성자 함수
- 생성자 함수는 객체를 생성하는 함수를 말한다
- 생성자 함수로 함수를 생성하는 방식은 일반적이지 않으며 바람직하지도 않다
- 생성자 함수는 클로저를 생성하지 않는 등... 함수 선언문이나 함수 표현식으로 생성한 함수와 다르게 동작한다
12.4.5 화살표 함수
- 화살표 함수는 항상 익명 함수로 정의한다
- 화살표 함수는 기존의 함수보다 표현만 간략한 것이 아니라 내부 동작 또한 간략화되어 있다
12.5 함수 호출
- 기존 함수와 this 바인딩 방식이 다르고 prototype 프로퍼티가 없으며 argumetns 객체를 생성하지 않는다
12.5.1 매개변수와 인수
- 함수를 실행하기 위해 필요한 값을 함수 외부에서 함수 내부로 전달할 필요가 있는 경우, 매개변수를 통해 인수를 전달한다
- 인수는 값으로 평가될 수 있는 표현식이어야 한다
- 매개변수는 함수 몸체 내부에서 변수와 동일하게 취급된다
- 매개변수의 스코프는(유효 범위)는 함수 내부다
- 함수를 호출할 때 매개변수의 개수만큼 인수를 전달하는 것이 일반적이지만 그렇지 않은 경우에도 에러가 발생하지는 않는다
- 인수가 할당되지 않은 매개변수의 값은 undefined이다
- 매개변수보다 인수가 더 많은 경우 초과된 인수는 무시된다
12.5.2 인수 확인
- 자바스크립트의 경우 함수를 정의할 때 적절한 인수가 전달되었는지 확인할 필요가 있다
- 타입스크립트와 같은 정적 타입을 선언할 수 있는 자바스크립트의 상위 확장을 도입해서 컴파일 시점에 부적절한 호출을 방지할 수 있게 하는 것도 하나의 방법이다
rest parameter
- ES6에서 도입된 매개변수 기본값을 사용하면 함수 내에서 수행하던 인수 체크 및 초기화를 간소화 할 수 있다.
- 매개변수 기본값은 매개변수에 인수를 전달하지 않았을 경우와 Undefined 를 전달한 경우에만 유효하다
12.5.3 매개변수의 최대 개수
- 이상적인 함수는 한 가지 일만 해야 하며 가급적 작게 만들어야 한다
12.5.4 반환문
- 함수는 retrun 키워드를 사용해 js에서 사용 가능한 모든 값을 반환할 수 있다
- 함수 호출은 표현식이다 (값이 아닌 표현식)
- 함수 호출 표현식은 return 키워드가 반환한 표현식의 평가 결과, 즉 반환값으로 평가된다
- return 키워드 뒤에 반환값으로 사용할 표현식을 명시적으로 지정하지 않으면 undifined 가 반환된다
- 반환문은 생략할 수 있다. 이때 함수는 함수 몸체의 마지막 문까지 실행한 후 암묵적으로 undefined를 반환한다
12.6 참조에 의한 전달과 외부 상태의 변경
- 객체를 불변 객체로 만들기 위해 객체의 복사본을 새롭게 생성하여 객체를 마치 원시값처럼 변경 불가능한 값으로 동작하게 만들 수 있다.
- 이를 통해 객체의 상태 변경을 원천봉쇄하고 객체의 상태 변경이 필요한 경우에는 객체의 방어적 복사를 통해 원본 객체를 완전히 복제, 즉 깊은 복사를 통해 새로운 객체를 생성하고 재할당을 통해 교체한다. 이를 통해 외부 상태가 변경되는 부수 효과를 없앨 수 있다
- 외부 상태를 변경하지 않고 외부 상태에 의존하지도 않는 함수를 순수 함수라 한다
- 순수 함수를 통해 프로그램의 안정성을 높히려는 프로그램밍 패러다임을 함수형 프로그래밍이라 한다
12.7 다양한 함수의 형태
12.7.1 즉시 실행 함수
- 함수 정의와 동시에 즉시 호출되는 함수
- 즉시 실행 함수 내에 코드를 모아두면 혹시 있을 수도 있는 변수나 함수 이름의 충돌을 방지할 수 있다
12.7.2 재귀 함수
- 함수가 자기 자신을 호출하는 것을 재귀 호출이라 한다
- 재귀 호출한 함수는 자신을 무한 재귀 호출한다. 따라서 재귀함수 내에는 재귀 호출을 멈출 수 있는 탈출 조건을 반드시 만들어야 한다
- 대부분의 재귀 함수는 for문이나 while문으로 구현 가능하다
- 재귀 함수는 반복문을 사용하는 것보다 재귀함수를 사용하는 편이 더 직관적으로 이해하기 쉬울 때만 한정적으로 사용하는 것이 바람직하다
12.7.3 중첩 함수
- 함수 내부에 정의된 함수를 중찹 함수 또는 내부 함수라 한다
- 중첩 함수는 스코프와 클로저에 깊은 관련이 있다
12.7.4 콜백 함수
- 함수의 변하지 않는 공통 로직은 미리 정의해 두고, 경우에 따라 변경되는 로직은 추상화해서 함수 외부에서 함수 내부로 전달할 수 있다
- 이를 통해 함수는 내부 구조에 강력히 의존하지 않고 외부에서 로직의 일부분을 함수로 전달받아 수행하므로 더욱 유연한 구조를 갖는다
- 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백함수라고 하며, 매개 변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차함수라고 한다.
- 고차함수는 콜백함수를 자신의 일부분으로 합성한다.
고차함수는 매개변수를 통해 전달받은 콜백 함수의 호출 시점을 결정해서 호출한다.
콜백함수는 고차 함수에 의해 호출되며, 이때 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다.
따라서 고차 함수에 콜백 함수를 전달할 때 콜백 함수를 호출하지 않고 함수 자체를 전달해야 한다.
- 콜백 함수를 다른 곳에서도 호출할 필요가 있거나, 콜백 함수를 전달받는 함수가 자주 호출된다면 함수 외부에서 콜백 함수를 정의한 후 참조 함수를 고차 함수에 전달하는 편이 효율적이다
- 콜백 함수는 비동기 처리에 활용되는 중요한 패턴이다.
- 콜백 함수는 배열 고차 함수에서도 사용된다
12.7.5 순수 함수와 비순수 함수
- 순수 함수는 어떤 외부 상태에도 의존하지 않고 오직 매개변수를 통해 함수 내부로 전달된 인수에게만 의존해 반환값을 만든다
- 순수 함수의 특징은 함수의 외부 상태를 변경하지 않는다
- 순수 함수는 어떤 외부 상태에도 의존하지 않으며 외부 상태를 변경하지도 않는 함수이다
- 외부 상태에 의존하는 함수를 비순수 함수라고 한다
- 함수의 외부 상태를 변경하는 부수 효과가 있다
- 비순수 함수는 외부 상태에 의존하거나 외부 상태를 변경하는 함수다
- 자바스크립트는 멀티 패러다임 언어이므로 객체지향 프로그래밍 뿐만 아니라 함수형 프로그래밍을 적극적으로 활용하고 있다
- 함수형 프로그래밍은 결국 순수함수를 통해 부수 효과를 최대한 억제해 오류를 피하고 프로그램의 안전성을 높이려는 노력의 일환이라 할 수 있다
함수
- 함수 {}중괄호를 '함수 바디'라고 한다
- 함수에는 입력값과 출력값이 있다
- return으로 출력(반환)
- break문이 그러하듯 바디에서 return을 만나면 함수는 반환값을 반환하며 함수를 종료시킨다
- 매개변수를 이용하여 함수에 입력값을 줄 수 있다
- 변수는 접근할 수 있는 범위가 있다
- 함수도 마찬가지로 유효범위 때문에 함수 외부에서 함수 내부로 접근할 수 없다
- 외부에서 함수에 접근하려면 매개체 역할을 하는 변수를 사용해 함수 내부로 값을 전달할 수 있도록 할 수 있다
- 매개변수(파라미터)를 통해 함수에 접근한다
- 매개변수는 함수 호출시 매개변수 자리값에 맞게 인자값(argument)을 넘겨준다
rest parameter
- 얕은 복사시 사용한 ...(spread 연산자)와 비슷하다
- 함수 정의시 매개변수를 선언해야 인자를 넘길 수 있다
- ...(rest parameter)로 나머지 매개변수를 선언하지 않은 나머지 인자들을 배열로 만든다
- ...(rest parameter)앞에 매개변수가 있다면 그 매개변수에 인자가 먼저 넘겨지고 들어갈 매개변수가 없는 나머지 인자들은 ...(rest parameter)가 있다면 해당 매개변수에 들어가 배열의 원소가 된다
함수 사용시 헷갈리는 부분
return과 console.log()
- console.log()는 그저 콘솔에 원하는 내용을 출력하는 방법이다
- return을 하지 않았다면 출력을 해 주지 않은 상황이다
- 하지만 반드시 return 해야만 하는 것은 아니다
- 바꿔주는 동작 같은 것만 하는 경우 함수 밖으로 값을 출력할 필요가 없다
- 하지만 값을 출력(반환)해야 할 경우 반드시 return 해준다
function keyword - argument객체
- function은 arguments라는 객체가 내장되어있다
- arguments는 유사 배열 객체이다
- 하지만 rest parameter가 있기 때문에 요즘은 사용하지 않는다(rest parameter은 배열이므로 rest parameter[index]와 같이 사용이 가능하기 때문이다)
- function키워드로 함수 정의시에만 arguments객체를 사용 가능하다
- 화살표 함수로 함수를 정의했을 경우 사용할 수 없다
arrow function
- 화살표 함수 정의시 매개변수가 하나라면 ()로 묶을 필요 없다
- 다른 동작 없이 바로 return하는 경우 아래와 같은 코드로 작성할 수 있다
const bar = 매개변수 => 매개변수 + 2;
- 하지만 동작을 바디에 추가한다면 기존의 화살표 함수처럼 사용해야 한다
익명함수
- 이름이 없는 함수
- 콜백함수(함수의 인자로 들어가는 함수)로 익명함수를 사용할 수 있다
- 한번 실행 후 사용하지 않을 함수일 경우 사용할 수 있다
즉시 실행 함수
- 함수를 선언과 동시에 바로 실행시키는 함수
- 함수를 ()소괄호 로 묶고 그 함수를 ()로 바로 호출한다
- 함수 선언과 동시에 호출하는 것
- jquery나 script함수(?) 사용시 즉시 실행 함수로 사용하는 것과 마찬가지이다
익명함수와의 차이점
- 익명함수는 함수 선언만 하고 호출은 하지 않는다
- 즉시 실행 함수는 함수 선언과 호출을 동시에 한다
함수에 식별자가 필요하지 않다면 익명함수를 사용하고,
식별자도 필요하지 않고 바로 실행이 가능한 함수를 사용하고 싶다면 즉시 실행 함수를 사용할 수 있다
콜백함수
- 함수의 인자값으로 넘기는 함수(함수의 인자인 함수)
- 결과적으로 콜백함수는 매개변수에 어떤 인자값을 넘길 때 그 인자값으로 함수를 넘긴다는 의미이다
- 인자로 넘긴 함수를 콜백함수로 받은 함수의 바디 안에서 사용할 수 있다
- 인자로 함수를 호출하며 넘기는 것 과 콜백함수로 인자를 넘기는 것은 전혀 다르다
- 콜백함수는 어떤 함수의 바디 안에서 호출된다
- 타입 스크립트 에서는 타입을 정할 수 있다(어떤 타입으로 retrun되어야 하는지까지 정할 수 있다)
배열의 반복
for (let i = 0; i < Array.length - 1; i++){
...
}
- Array.length -1은 배열의 인덱스 번호(원소 수)만큼만 배열을 한번 순환하겠다는 의미이다
- 배열의 처음부터 끝까지의 인덱스 번호를 모두 순회하고 싶다면 반복문의 초기값이 0부터 시작되어 Array.length에 -1을 해줘야 인덱스 0부터 배열의 마지막 인덱스까지를 순환할 수 있다
재귀 함수
- 자기 자신을 호출하는 함수
- while문과 유사하다 -> true라면 무한 반복 된다
- while문은 break할 수 있는 트리거가 있어야 하는 것 과 같이 재귀 함수도 무한 반복이 될 수 있기 때문에 탈출할 방법을 만들어 놔야 한다
- 함수 안에 있는 조건문이나 반복문에서 return될 경우 해당 문이 있는 함수 자체에서 return되어 함수를 빠져나간다
고차 함수
- 함수를 반환하는 함수이다
- 나중에 언제 사용하는지 알려주신다 하심!!
12.2 함수를 사용하는 이유
- 함수는 재사용이 용이하다
- 식별자를 통해 이 함수가 어떤 역할을 하는 함수인지 판단할 수 있다. 따라서 코드 가독성이 높아진다
- 유지보수의 편의성을 높일 수 있다
12.3 함수 리터럴
- 화살표 함수나, funcion 식별자 와 같은 형태로 주로 사용한다
- 일반적인 함수의 식별자는 camel case를 사용한다
- 생성자 함수의 식별자는 pascal case를 사용한다
12.4 함수 정의
12.4.2 함수 표현식
- 사용하지 않는다
- 화살표 함수나, funcion 식별자 와 같은 형태로 주로 사용한다
12.4.3 함수 생성 시점과 함수 호이스팅
- 호이스팅 -> 끌어올림
- 함수 선언문으로 함수를 정의하면 런타임 이전에 함수 객체가 먼저 생성된다
12.5 함수 호출
12.5.1 매개변수와 인수
- 함수에 default parameter를 지정해 줄 수 있다
- 함수 호출시 해당 자리에 인자값을 준다면 default parameter에선 인자값으로 치환된다
- 예제 12-19 argument는 잘 사용하지 않는다
- 매개변수도 만들어지는 순간 선언하는 것이다
- 매개변수에 인자값을 넘기지 않는다면(할당하지 않는다면) undefined이다
- 함수가 복잡해지면 매개변수 순서에에 맞춰 인자를 주는 것이 매우 헷갈린다
- 이런 경우 인자로 객체를 주고 객체를 인자로 받은 해당 함수의 바디 안에서는 객체의 프로퍼티를 이용하면 순서를 신경쓰지 않고 인자로 받은 객체의 프로퍼티를 이용할 수 있다
12.7 다양한 함수의 형태
12.7.2 재귀 함수
- 고차함수는 당장 알지 못해도 괜찮다(매개변수를 통해 함수의 외부에서 콜백함수를 전달받은 함수를 고차 함수라고 한다)
12.7.5 순수 함수와 비순수 함수 -> 중요
- 함수의 인자로 주는 값(입력 값)이 동일하다면 매변 같은 값이 출력되야 한다
- 이 때 어떤 의존 값이 붙는다면 -> 이때부터는 이 함수를 순수하지 않은 비순수 함수라고 한다
- 함수 외부의 값을 함수 내부로 끌어와서 사용하는 경우 외부의 값이 바뀌는 것에 따라서 함수의 출력값이 바뀔 가능성이 존재한다
- 함수형 프로그래밍의 기본은 순수함수를 사용하는 것이다(알아보기)