12.1 함수란?
일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것
- 매개변수 : 함수 내부로 입력을 전달받는 변수
- 인수 : 입력 (input)
- 반환값 : 출력 (output) = 함수 실행 결과
- 함수이름 : 특정 함수를 구별하기 위한 식별자
- 함수 실행 = 함수 정의 (생성) + 함수 호출 (함수 실행 지시)
12.2 함수를 사용하는 이유
- 코드의 재사용 : 몇 번이든 호출할 수 있는 것
- 적절한 함수명은 코드의 가독성을 높임
12.3 함수 리터럴
var f = function add(x,y) {
return x+y;
}
- 함수 리터럴의 구성요소
- 함수 이름 : 식별자 네이밍 규칙을 준수한 이름 (생략 가능)
- 매개변수 목록 : 0개 이상 식별자 네이밍 규칙을 준수한 변수명 사용 (순서 유의미함)
- 함수 몸체 : 함수가 호출되었을 때 일괄적으로 실행될 문들을 하나의 실행 단위로 정의한 코드 블록
- 함수는 객체이지만 일반 객체와 다르게 호출할 수 있음
12.4 함수 정의
함수를 호출하기 이전에 인수를 전달받을 매개변수와 실행할 문들, 반환할 값을 지정하는 것
함수를 정의하는 방법에는 4가지가 존재한다.
함수 선언문
function add(x,y) {
return x + y;
}
console.dir(add);
console.log(add(2,5));
- 함수 선언문은 함수 이름을 생략할 수 없음
- 함수 선언문은 표현식이 아닌 문으로 선언문 실행시 undefined 출력됨
- 변수에 할당 불가
- 함수 리터럴로 함수 호출 불가 ⇒ 함수 리터럴에서 함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자이므로 함수 몸체 외부에서 호출할 수 없음
- 단 기명 함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석됨
- JS 엔진은 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성한 후 함수 객체를 할당함
- 함수 선언문은 ‘표현식이 아닌 문’
💬 **함수**는 함수 이름으로 호출하는 것이 아니라 **함수 객체를 가리키는 식별자로 호출**한다.
함수 표현식
- 일급 객체 : 값의 성질을 갖는 객체
- 함수는 일급 객체로 리터럴로 생성한 함수 객체를 값처럼 자유롭게 사용할 수 있음
var add = function foo(x,y) {
return x + y;
}
console.log(add(3,5));
console.log(foo(3,5));
- 함수 리터럴의 함수 이름은 생략하며 익명 함수라고 부름
- 일반적으로 함수 표현식의 함수 리터럴의 함수 이름은 생략됨
- 호출시 함수 이름이 아닌 함수 객체를 가리키는 식별자를 사용해야 함
- 즉 식별자와 함수 이름이 다를 때, 함수 이름으로 호출하면 ReferenceError
- 함수 선언문과 함수 표현식이 정확히 동일하게 동작하지 않음
- 함수 표현식은 ‘표현식인 문’
함수 생성 시점과 함수 호이스팅
함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 고유의 특징을 함수 호이스팅이라 한다.
- 함수 선언문과 함수 표현식으로 정의한 함수의 생성 시점은 서로 다름
- 함수 선언문은 런타임 전에
-
함수 객체 생성
-
함수 이름과 동일한 이름의 식별자 생성하고 객체를 식별자에 할당함
⇒ ‼️함수 호이스팅에 의해 함수 선언문 이전에 함수 참조 및 호출 가능 (런타임 전에 다 준비해놨으〰)
- 함수 표현식은 변수 선언문 + 변수 할당문의 축약 표현
-
런타임 전에 변수 선언 = 변수 호출시 undefined 호출하는 것이어유
-
런타임에 변수에 함수 객체 할당
⇒ 함수 리터럴도 할당문이 실행되는 시점에 평가됨
⇒ 함수 표현식으로 함수 정의시 ‼️변수 호이스팅이 발생
변수 호이스팅 🆚 함수 호이스팅
- 변수 호이스팅도 런타임 이전에 생성되지만 변수 선언문 이전에 참조시 undefined로 평가
- 함수 호이스팅은 함수 선언문을 통해 생성된 식별자가 함수 객체로 초기화 되기 때문에 함수 선언문 이전에 함수 호출 가능 → 대신, 함수를 호출하기 전에 반드시 함수를 선언해야 한다는 당연한 규칙을 무시함 ..
Function 생성자 함수
- Function 생성자 함수로 함수 생성 가능
- new 연산자는 생략해도 상관없음
- 일반적인 함수 생성 방식이 아니므로 함수 선언문과 표현식으로 생성된 함수와는 다르게 동작
var add = new Function ('x', 'y', 'return x + y');
console.log(add(2,5));
화살표 함수
- function 키워드 대신 화살표(⇒)를 사용해 간략하게 함수 선언 가능
- 항상 익명 함수로 정의
- 생성자 함수로 사용할 수 없으며, this 바인딩 방식 다름, prototype 프로퍼티 없음, arguments 객체 생성안함
const add = (x,y) => x + y;
console.log(add(2,5));
12.5 함수 호출
함수를 가리키는 식별자와 한 쌍의 소괄호인 함수 호출 연산자로 호출함
- 0개 이상의 인수를 쉼표로 구분
- 호출시 현재의 실행 흐름을 중단하고 호출된 함수로 흐름 옮김
- 함수는 매개변수와 인수의 개수가 일치하는지 체크 안함 ⇒ 개수가 적으면 에러 안나고 undefined, 더 많으면 무시됨
매개변수와 인수
- 매개변수 : 함수를 실행하기 위해 필요한 값을 함수 외부에서 내부로 전달할 필요가 있는 경우 함수 정의시 선언됨
- 함수 몸체 내부에서 변수와 동일하게 취급 = 일반 변수처럼 undefined로 초기화 후 순서대로 할당
- 함수 몸체 내부에서만 참조 가능
- 인수 : 값으로 평가될 수 있는 표현식으로 호출시 지정됨
인수 확인
- 자바스크립트에서는 개발자의 의도와 다르게 함수가 실행될 수 있다.
- JS 함수는 매개변수와 인수의 개수가 일치하는지 확인하지 않음
- JS는 동적 타입 언어로 매개변수의 타입을 사전에 지정할 수 없음
- 위 두가지 이유로 함수 정의시 적절한 인수가 전달되었는지 확인해야 함
매개변수의 최대 개수
- 매개변수는 순서에 의미가 있음
- 매개변수의 개수나 순서가 변경되면 호출 방법도 바뀌고 함수를 사용하는 코드의 유지보수성이 나빠짐
- 함수는 한 가지 일만 해야하며 가급적 작게 만들어야 함 (최대 3개까지)
- 객체를 인수로 전달하면 코드의 가독성이 좋음 → 전달된 객체를 함수 내부에서 변경시 부수 효과 발생 조심
반환문
return 키워드와 표현식으로 이뤄진 반환문을 사용해 실행 결과를 함수 외부로 반환할 수 있다.
- return 키워드를 사용하면 JS에서 사용 가능한 모든 값을 반환할 수 있음
- 함수 호출은 표현식
- 생략 가능 ⇒ 함수 몸체의 마지막 문까지 실행 후 undefined 반환
반환문의 역할
- 함수의 실행을 중단하고 함수 몸체를 빠져나감 = 이후 다른 문은 무시
- return 키워드 뒤에 오는 표현식을 평가해 반환 (표현식 미지정시 undefined)
12.6 참조에 의한 전달과 외부 상태의 변경
- 매개변수도 함수 몸체 내부에서 변수와 동일하게 취급되므로 타입에 따라 값에 의한 전달 & 참조에 의한 전달 방식을 그대로 따름
- 함수 내에서 매개변수로 받은 원시 값(값에 의한 전달)은 원본 훼손 안됨
- 매개변수로 받은 객체는(참조에 의한 전달) 원본 객체가 훼손되고 변경됨
- 해결 방법으로 객체를 불변 객체로 만들어 사용하면 됨
12.7 다양한 함수의 형태
즉시 실행 함수
함수 정의와 동시에 즉시 호출되는 함수
- 단 한번만 호출되며 다시 호출시 ReferenceError
- 반드시 (…)로 감싸야 함
- 일반 함수처럼 값 반환 및 인수 전달 가능
var res = (function (매개변수 넣는 곳) {
...
return 반환 표현식
}(인수 전달하는 곳 ));
재귀 함수
자기 자신을 호출하는 재귀호출을 수행하는 함수
- 재귀 함수는 반복되는 처리를 위해 사용됨
- 재귀 함수는 자신을 무한 재귀 호출함
- 재귀 호출을 멈추기 위해서 탈출 조건을 무조건 작성해야 함
function countdown(n) {
for (var i = n; i >= 0; i--) console.log(i);
}
countdown(10);
function countdown(n) {
if(n < 0) return;
console.log(n);
countdown(n - 1);
}
countdown(10);
중첩 함수
함수 내부에 정의된 함수
- 외부 함수 내부에서만 호출할 수 있음
- 일반적으로 자신을 포함하는 외부 함수를 돕는 핼퍼 함수의 역할을 함
- 함수 내에서 if 문이나 for 문 등의 코드 블럭에서 함수 선언문을 통해 함수 정의하는 것은 비추
콜백 함수
함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수
- 고차함수 : 변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수
- 콜백 함수도 고차 함수에 전달되어 헬퍼 함수의 역할을 함
- 대신 중첩 함수와 다르게 자유롭게 교체할 수 있음
💬 콜백 함수는 고차 함수에 의해 호출되며 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있음
- 콜백 함수를 전달받는 함수가 자주 호출시 함수 외부에서 콜백 함수 정의 후 고차 함수에 함수 참조를 전달하는 것이 효율적
- 콜백 함수는 함수형 프로그래밍 패러다임 뿐만 아니라 비동기 처리 및 배열 고차 함수에 사용됨
순수 함수와 비순수 함수
- 순수 함수 : 어떤 외부 상태에도 의존하지 않으며 외부 상태를 변경하지 않는 함수
- 인수의 불변성 유지 ⇒ 변수에 재할당 후 상태 변경
- 비순수 함수 : 외부 상태에 의존하거나 외부 상태를 변경하는 부수 효과가 있는 함수
- 외부 상태를 변경하므로 상태 변화 추적 어려움
💡 함수형 프로그래밍은 순수 함수와 보조 함수의 조합을 통해 외부 상태를 변경하는 부수 효과를 최소화하는 불변성을 지향하는 프로그래밍 패러다임