12.1 함수란?
일련의 과정을 문으로 작성하고, 코드 블록으로 감싸 실행 단위로 정의한 것입니다.
12.2 함수를 사용하는 이유
코드의 재사용, 가독성, 유지보수 편의성 증가
12.3 함수 리터럴
리터럴의 구성요소는 3가지가 있습니다.
•
함수 이름
◦
식별자로 네이밍 규칙을 준수해야 합니다.
•
매개변수 목록
◦
0개이상의 매개변수를 소괄호로 감싸로 쉼표로 구분합니다.
◦
식별자 네이밍 규칙을 준수해야 합니다.
•
함수 몸체
◦
호출되었을 때 일괄적으로 실행될 문들을 하나의 실행 단위로 정의한 코드 블록입니다.
함수는 객체입니다. 근데 일반 객체는 호출할 수 없지만, 함수는 호출할 수 있습니다. 또한 함수만의 고유 객체 프로퍼티가 존재합니다.
12.4 함수 정의
함수의 정의방식으로는 4개지가 존재합니다.
함수 선언문
function add(x, y){
return x + y;
}
JavaScript
복사
함수 표현식
const a = function(x, y){
return x + y;
}
JavaScript
복사
Function 생성자 함수
const add = new Function('x', 'y', 'return x+y');
JavaScript
복사
화살표 함수(ES6)
const add = (x, y) => x + y;
JavaScript
복사
함수를 정의한다는 면에서는 똑같지만, 차이점이 존재합니다.
12.4.1 함수 선언문
함수 선언문은 함수 리터럴과 형태가 동일합니다. 단, 함수 리터럴은 함수 이름을 생략 가능하나, 선언문은 이름을 생략할 수 없습니다.
function (x, y){
return x + y
}
// Uncaught SyntaxError: Function statements require a function name
JavaScript
복사
함수 선언문은 표현식이 아니라 문으로, 선언문을 실행하면 완료값 undefined가 출력됩니다.
앞에서 문에는 변수를 할당할 수 없다고 했습니다. 하지만 아래와 같은 방식이 가능합니다.
const a = function add(x, y){
return x+y;
}
JavaScript
복사
이유는 JS 자체에서 기명 함수 리터럴을 단독으로 사용시 함수 선언문으로 해석하기 때문이다.
function foo() {
console.log('foo');
}
foo(); // foo
(function bar() { console.log('bar'); });
bar(); // ReferenceError: bar is not defined
JavaScript
복사
위에서 foo는 정상적으로 실행되지만 bar는 정상적으로 실행되지 않는다. bar의 경우에는 “함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자”이기 때문에 외부에서 호출할 수 없는 것이다. 하지만 foo의 경우에는 JS에서 암묵적으로 식별자를 생성하고, 그곳에 함수 객체를 할당했기 때문에 정상적으로 실행할 수 있다.
이를 코드로 살펴보면
const add = function add(x, y){
return x + y;
};
JavaScript
복사
와 같다. 즉 함수는 함수 이름으로 호출하는 것이 아닐, 함수 객체를 가리키는 식별자로 호출한다.
12.4.2 함수 표현식
JS의 함수는 값처럼 변수에 할당할 수도 있고, 프로퍼티 값이 될 수도 있고, 배열의 요소가 될 수도 있습니다. 이러한 것을 일급 객체라고 합니다. JS의 함수는 일급 객체로 변수에 할당할 수 있는데 이를 함수 표현식이라 합니다.
conat add = function (x, y) {
return x + y;
}
JavaScript
복사
함수 리터럴의 이름을 생략할 수 있는데 이를 익명 함수라고 합니다.
함수 선언문은 “표현식이 아닌 문”이고, 함수 표현식은 “표현식인 문”입니다.
12.4.3 함수 생셩 시점과 함수 호이스팅
console.dir(add); // f add(x,y)
console.dir(sub); // undefined
console.log(add(2, 5)); // 7
console.log(sub(2, 5)); // TypeError: sub is not a function
// 함수 선언문
function add(x, y) {
return x + y;
}
// 함수 표현식
var sub = function (x, y) {
return x + y;
}
JavaScript
복사
함수 선언문으로 정의한 함수는 선언 이전에 호출할 수 있지만, 표현식으로 정의한 함수는 호출할 수 없습니다. 이는 둘의 생성된 시점이 다르기 때문입니다.
함수 선언문의 경우 런타임 이전에 JS엔진에 의해서 먼저 실행되기 때문에 객체가 미리 생성되고, 동일한 식별자에 할당까지 완료된 상태입니다. 따라서 함수 선언문 이전에 함수를 참조할 수 있고, 호출할수도 있는데 이를 함수 호이스팅이라고 합니다.
변수호이스팅과 다른점은 변수의 경우 undefined로 초기화되지만, 함수 선언문으로 생성된 객체는 함수 객체로 초기화됩니다.
함수 표현식은 변수에 할당되는 값이 함수 리터럴인 문입니다. 따라서 함수 표현식은 변수 선언문과 변수 할다문을 한번에 기술한 축약 표현과 동일하게 동작합니다. 변수 선언은 런타임 이전에 실행되어 undefined로 초기화되지만 변수 할당문의 값은 할당문이 실행되는 시점인 런타임에 평가되므로 함수 표현식의 함수 리터럴도 할당문이 실행되는 시점에 평가되어 함수 객체가 됩니다. 따라서 함수 표현식으로 정의시 변수 호이스팅이 발생합니다.
12.4.4 Function 생성자 함수
new 연산자 없이 호출해도 결과는 동일합니다. 이러한 방법은 클로저를 생성하지않는등 일반적이지 않습니다.
12.4.5 화살표 함수
화살표 함수는 항상 익명함수로, this바인딩 방식도 다르고, prototype 프로퍼티가 없으며, arguments 객체를 생성하지 않습니다.
12.5 함수 호출
12.5.1 매개변수와 인수
함수를 실행하기 위해 필요한 값을 외부에서 내부로 전달할 때 매개변수(parameter)를 통해 인수(argument)를 전달한다. 이때 햄수 내부에서 변수와 동일하게 취급되는데 암묵적으로 매개변수가 생서되고, undefined로 초기화된다.
매개변수의 갯수와 인수의 갯수가 일치하는지 체크하지 않으며, 인스가 부족해서 할당된 매개변수 값은 undefined다.
그리고 매개변수보다 인수가 많은 경우 초과된 인수는 무시된다.
12.5.2 인수 확인
arguments 객체를 통해서 인수 갯수를 확인할 수도 있으며, 전달되지 않는 경우 단축 평가를 사용해 기본값을 할당하는 방법도 있다. 또한 ES6에서 도입된 매개변수 기본값을 활용해서 undefined일 경우에 대처할 수 있다.
12.5.3 매개변수의 최대 갯수
가급적 작게 만들어야한다.
12.5.4 반환문
함수 호출은 표현식이여서, 평가결과 즉 반환값으로 평가된다.
만약 이를 return으로 반환값을 주지 않을시 undefined가 반환된다.
12.6 참조에 의한 전달과 외부 상태의 변경
매개변수에 새로운 값을 넣는다면, 원시 값은 값 자체가 복사되어 외부 값에 변화가 일어나지 않지만, 객체는 참조값이 전달되어 변화가 일어난다. 따라서 이를 객체의 깊은 복사를 통해 전달하는 등의 방법이 필요하다.
12.7 다양한 함수의 형태
12.7.1 즉시 실행 함수
즉시 실행함수는 주로 익명함수를 사용하나 기명함수도 사용할 수 있다. 또한 반드시 그룹연산자로 묶어줘야한다.
12.7.2 재귀 함수
함수안에서 자기 자신을 사용해 재귀함수를 구현할 수 있다.
12.7.3 중첩 함수
함수 내분에 정의된 함수를의미한다.
function a(){
function b(){}
b();
}
JavaScript
복사
12.7.4 콜백 함수
함수의 매개변수를 통해 내부로 전달되는 함수를 일컫습니다. 또한 매개변수를 통해 함수의외부에서 콜백 함수를 전달받은 함수를 고차함수라고합니다.
12.7.5 순수 함수와 비순수 함수
외부의 어떤 상태에 의존하지도, 변경하지도, 부수효과가 없는 함수를 순수 함수라합니다.