[JS] 모던 자바스크립트 - 07. 함수
함수
- 일련의 과정을 문(statement)로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것
- 함수 내부로 입력을 전달받는 변수는 매개변수(parameter), 입력을 인수(argument), 출력을 반환값(return value)이라 한다
- 함수는 객체타입의 값, 함수가 객체라는 사실은 다른 프로그래밍 언어와 구별되는 자바스크립트의 중요한 특징
- 함수는 일급객체, 값의 성질을 갖는 객체다
- 함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자
- 변수는 선언한다고 하지만, 함수는 정의한다고 한다
- 일반 객체는 호출할 수 없지만 함수는 호출 가능
함수 정의
함수 선언문
function add(x,y){
return x + y ;
}
- 함수 이름을 생략할 수 없다
- 표현식이 아닌 문이므로 변수에 할당할 수 없다
- 그룹 연산자( ) 내에 있는 함수 리터럴은 함수 선언문으로 해석되지 않고 함수 리터럴 표현식으로 해석 (그룹 연산자의 피연산자는 값으로 평가될 수 있는 표현식이어야하기 때문, 함수 선언문은 피연산자로 사용 불가)
- 함수 몸체 외부에서는 함수 이름으로 함수를 호출할 수 없음
( function bar() {console.log('bar'); });
bar(); // RefereceError : bar is not defined
- 자바스크립트 엔진은 함수 선언문을 해석해 런타임 이전에 함수 객체를 생성
- 함수 선언문으로 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고 거기에 함수 객체를 할당
- 함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출
- 함수 선언문 이전에 호출해도 함수 호이스팅에 의해 호출 가능
함수 표현식
var add = function (x,y) {
return x + y ;
}
- 함수 리터럴로 생성한 함수 객체는 표현식인 문이므로 변수에 할당 가능
- 함수 리터럴의 함수 이름은 생략 가능(익명 함수)
- 런타임에 함수 리터럴이 변수에 할당되는 시점에 평가되어 함수 객체가 됨
- 함수 호이스팅이 아닌 변수 호이스팅이 발생
- 함수 표현식 이전에 함수 참조시 undefined로 평가되어 TypeError 발생
- 함수 선언문보다 함수 표현식을 사용하는 것이 좋음
Function 생성자 함수
var add = new Funtion('x','y','return x + y');
- 일반적이지 않고 바람직하지도 않음
- 클로저를 생성하지 않는 등 함수 선언문이나 함수 표현식으로 생성한 함수와 다르게 동작
화살표 함수
const add = (x,y) => x + y;
- ES6에서 도입
- function 키워드 대신 화살표(=>)를 사용
- 항상 익명 함수로 정의
- 기존 함수와 this 바인딩 방식이 다르고, prototype 프로퍼티가 없으며, argument 객체를 생성하지 않음
- 함수 내부에 this가 없고, 접근하려고 할 때 스코프 체인상 가장 가까운 this에 접근
함수 호출
매개변수와 인수
- 인수는 값으로 평가될 수 있는 표현식이어야 함, 함수를 호출할 때 지정
- 매개변수는 함수를 정의할 때 선언, 함수 몸체 내부에서 변수와 동일하게 취급
- 매개변수의 스코프(유효 범위)는 함수 내부
- 함수는 매개변수의 개수와 인수의 개수가 일치하는지 체크하지 않음, 에러 발생 X
- 인수가 할당되지 않은 매개변수의 값은 undefined
- 매개변수보다 인수가 더 많은 경우 초과된 인수는 무시, 버려지는 것은 아니고 arguments 객체의 프로퍼티로 보관(arguments 객체는 함수를 정의할 때 매개변수 개수를 확정할 수 없는 가변 인자 함수를 구현할 때 유용)
- 자바스크립트는 동적타입 언어로서 매개변수 타입을 사전에 지정 할 수 없음(이 때문에 타입스크립트를 사용)
- ES6의 매개변수 기본값을 사용하면 함수 내부에서 하던 인수 체크 및 초기화를 간소화
function add(a=0, b=0, c=0){
return a + b + c;
}
- 원시 값의 인수는 부수효과가 없음
- 객체 타입 인수는 함수 내부에서 변경 시 부수효과 발생, 그러므로 객체는 깊은 복사를 통해 새로운 객체를 생성하고 재할당을 통해 교체
반환문
- 함수 호출은 표현식으로 return 키워드가 반환한 표현식의 평가 결과, 즉 반환값으로 평가됨
- 함수의 실행을 중단하고 함수 몸체를 빠져나감
- return 키워드 뒤에 오는 표현식을 평가해 반환, 표현식을 명시적으로 지정하지 않은 경우 undefined 반환
- 생략 가능, 생략 시 암묵적으로 undefined 반환
- 함수 내부에서만 사용 가능, 전역에서 사용 시 문법 에러(SyntaxError) 발생 (Node.js 환경에서는 파일별로 독립적인 파일 스코프를 갖기 때문에 에러 발생 X)
함수의 형태
즉시 실행 함수
- 함수 정의와 동시에 호출되는 함수
// 익명 즉시 실행 함수
(function () {
var a = 3;
var b = 5;
return a * b;
}());
- 익명함수를 쓰는 것이 일반적, 함수 이름을 쓸 순 있지만 그룹 연산자 내에서의 기명함수는 함수 선언문이 아닌 함수 리터럴로 평가되어 외부에서 호출 불가능하므로 불필요함
- 반드시 그룹 연산자(...)로 감싸야함
- 함수 선언문 뒤에 붙이는 ( )는 함수 호출 연산자가 아니라 그룹 연산자로 해석, 그룹 연산자에 피연산자가 없어 에러 발생
- 즉시 실행 함수 내에 코드를 모아두면 변수나 함수 이름의 충돌 방지 가능
재귀 함수
- 함수가 자기 자신을 호출하는 재귀 호출을 수행하는 함수
- 반복되는 처리를 반복문 없이 구현 가능
- 함수 이름, 함수 식별자 두가지로 전부 호출 가능
- 재귀 함수 내에 재귀 호출을 멈출 수 있는 탈출 조건을 반드시 만들어야 함, 그렇지 않으면 함수가 무한 호출되어 stack overflow 에러 발생
- 무한 반복에 빠질 위험이 있으므로 반복문보다 재귀함수를 사용하는 것이 직관적으로 이해하기 쉬울 때만 한정적으로 사용하도록 해야함
중첩 함수
- 함수 내부에 정의된 함수(inner function)
- 중첩 함수를 포함하는 함수는 외부 함수(outer function)
콜백 함수
- 매개변수를 통해 다른 함수의 내부로 전달되는 함수
- 매개변수를 통해 외부에서 콜백 함수를 전달받은 함수는 고차함수
- 고차 함수는 콜백 함수를 자신의 일부분으로 합성
- 고차 함수에 의해 호출되며 콜백 함수에 인수를 전달할 수도 있음
- 함수형 프로그래밍 패러다임과 비동기처리(이벤트 처리, Ajax 통신, 타이머 함수 등)에 활용되는 중요한 패턴
- 배열 고차 함수에서도 사용
순수 함수와 비순수 함수
- 순수함수는 부수효과가 없는 함수, 외부 상태를 변경 X
- 비순수 함수는 부수효과가 있는 함수, 외부 상태를 변경, 외부 상태에 의존
- 순수 함수는 동일한 인수가 전달되면 언제나 동일한 값을 반환
- 함수 내부에서 외부 상태를 직접 참조하지 않더라도 매개변수를 통해 객체를 전달 받으면 비순수 함수가 됨
- 함수형 프로그래밍은 순수 함수와 보조 함수의 조합을 통해 외부 상태를 변경하는 부수 효과를 최소화해서 불변성을 지향하는 프로그래밍 패러다임
- 자바스크립트는 멀티 패러다임 언어로, 객체 지향 뿐 아니라 함수형 프로그래밍을 적극적으로 활용
출처
- 모던 자바스크립트 Deep Dive - 자바스크립트의 기본 개념과 동작 원리
- 코어 자바스크립트