CH12. 함수
12.1 함수란?
// 함수 정의
function add(x, y) {
return x + y;
}
// 함수 호출
add(2, 5); // 7
12.2 함수를 사용하는 이유
- 몇 번이든 재사용할 수 있음
- 동일한 작업을 반복적으로 수행하는 경우 호출해서 사용
- 유지보수의 편의성을 높이고, 코드의 신뢰성을 높이는 효과가 있음
- 적절한 함수의 이름은 코드의 가독성을 향상시킴
12.3 함수 리터럴
- 함수 리터럴은 function 키워드, 함수 이름, 매개 변수 목록, 함수 몸체로 구성
- 함수는 객체, 하지만 일반 객체와는 다름
: 일반 객체는 호출할 수 없지만 함수는 호출할 수 있음
12.4 함수 정의
- 함수를 정의하는 4가지 방법
12.4.1 함수 선언문
// 함수 선언문
function add(x, y){
return x + y;
}
// 함수 참조
// console.dir은 console.log와는 다르게 함수 객체의 프로퍼티까지 출력함
// 단, 노드JS 환경에서는 console.log와 같은 결과가 출력됨
console.dir(add); // f add(x, y)
// 함수 호출
console.log(add(2, 5))
- 함수 선언문은 함수 리터럴과 형태가 동일함
- 함수 리터럴은 함수 이름을 생략할 수 있으나, 함수 선언문은 함수 이름을 생략할 수 없음
- 함수 선언문은 표현식이 아닌 문임
- 표현식이 아닌 문은 변수에 할당할 수 없음
- 즉, 함수 선언문도 표현식이 아닌 문으로 변수에 할당할 수 없음
- 하지만 함수 선언문이 변수에 할당되는 것처럼 보이는 아래 예제
이유? 자바스크립트 엔진이 코드의 문맥에 따라 동일한 함수 리터럴을
표현식이 아닌 문인 함수 선언문으로 해석하는 경우와
표현식인 문인 함수 리터럴 표현식으로 해석하는 경우가 있기 때문
var add = function add(x, y) {
return x + y;
};
console.log(add(2,5));
- 그룹연산자() 내에 있는 함수 리터럴은 함수 선언문으로 해석되지 않고 함수 리터럴 표현식으로 해석됨
- 그룹 연산자의 피연산자는 값으로 평가될 수 있는 표현식이어야 함
- 표현식이 아닌 문인 함수 선언문은 피연산자로 사용할 수 없음
- 함수는 함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출함
// 기명 함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석됨
// 함수 선언문에서는 함수 이름을 생략할 수 없음
function foo() { console.log("foo"); }
foo();
// 함수 리터럴을 피연산자로 사용하면 함수 선언문이 아니라 함수 리터럴 표현식으로 해석됨
// 함수 리터럴에서는 함수 이름을 생략할 수 있음
(function bar() { console.log('bar'); });
bar(); // ReferenceError: bar is not defined
12.4.2 함수 표현식
일급 객체?
값처럼 변수에 할당할 수도 있고 프로퍼티 값이 될 수도 있으며 배열의 요소가 될 수 있는 것
자바스크립트의 함수는 일급 객체 - 함수를 값처럼 자유롭게 사용할 수 있다는 의미
- 함수 리터럴의 함수 이름은 생략할 수 있음(익명 함수)
- 함수 표현식의 함수 리터럴은 함수 이름을 생략하는 것이 일반적임
// 함수 표현식
var add = function(x, y) {
return x + y;
};
console.log(add(2, 5));
- 함수 이름은 함수 몸체 내부에서만 유효한 식별자이므로 함수 이름으로 함수를 호출할 수 없음
// 기명 함수 표현식
var add = function foo(x, y) {
return x + y;
};
// 함수 객체를 가리키는 식별자로 호출
console.log(add(2, 5));
// 함수 이름으로 호출하면 ReferenceError가 발생함
// 함수 이름은 함수 몸체 내부에서만 유효한 식별자
console.log(foo(2, 5)); // ReferenceError: foo is not defined
12.4.3 함수 행성 시점과 함수 호이스팅
- 함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출 가능
- 그러나 함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출 불가능
: 함수 선언문으로 정의한 함수와 함수 표현식으로 정의한 함수의 생성 시점이 다르기 때문
함수 호이스팅?
- 함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징
: 변수 호이스팅이랑 다른점?
런타임 이전에 먼저 실행되어 식별자를 생성한다는 점에서 동일함
var키워드를 사용한 변수 선언문 이전에 변수를 참조하면 변수 호이스팅에 의해 undefined로 평가되지만,
함수 선언문으로 정의한 함수를 함수 선언문 이전에 호출하면 함수 호이스팅에 의해 호출이 가능함
- 함수 표현식으로 함수를 정의하면 함수 호이스팅이 발생하는 것이 아닌 변수 호이스팅이 발생하는 것
12.4.4 Function 생성자 함수
- Function 생성자 함수로 함수를 생성하는 방식은 일반적이지 않으며 바람직하지도 않음
var add = new Function('x', 'y', 'return x + y');
console.log(add(2, 5));
12.4.5 화살표 함수
- 항상 익명 함수로 정의함
- 화살표 함수는 생성자 함수로 사용할 수 없음
const add = (x, y) => x + y;
console.log(add(2, 5));
12.5 함수 호출
12.5.1 매개변수와 인수
- 매개변수는 함수 몸체 내부에서만 참조할 수 있고 외부에서는 참조 불가능
- 함수는 매개변수의 개수와 인수의 개수가 일치하는지 체크하지 않음
- 인수가 부족해서 인수가 할당되지 않은 매개변수의 값은 undefined
- 매개변수보다 인수가 더 많은 경우 초과된 인수는 무시됨
// 인수가 부족한 경우
function add(x, y) {
return x + y;
}
console.log(add(2)); // NaN
// 인수가 초과된 경우
function add(x, y) {
return x + y;
}
console.log(add(2, 5, 10));
12.5.2 인수 확인
function add(x, y) {
if (typeof x !== 'number' || typeof y !== 'number') {
throw new TypeError('인수는 모두 숫자 값이어야 합니다.');
}
return x + y;
}
12.5.3 매개변수의 최대 개수
- 함수의 매개변수는 코드를 이해하는 데 방해되는 요소이므로 이상적인 매개변수 개수는 0개이며 적을수록 좋음
- 이상적인 함수는 한 가지 일만 해야하며 가급적 작게 만들어야 함
12.5.4 반환문
- 반환문의 역할?
: 함수의 실행을 중단하고 함수 몸체를 빠져나감
: return 키워드 뒤에 오는 표현식을 평가해 반환함
- 반환문은 생략할 수 있음
- 함수 몸체 내부에서만 사용할 수 있음
12.6 참조에 의한 전달과 외부 상태의 변경
function changeVal(primitive, obj) {
primitive += 100;
obj.name = 'Kim';
}
var num = 100;
var person = {name : 'Lee'};
console.log(num);
console.log(person);
changeVal(num, person);
console.log(num);
console.log(person);
12.7 다양한 함수의 형태
12.7.1 즉시 실행 함수
- 함수의 정의와 동시에 즉시 호출되는 함수
- 실행 함수는 단 한 번만 호출되며 다시 호출할 수 없음
- 즉시 실행 함수는 익명 함수를 사용하는 것이 일반적
- 기명 즉시 실행 함수도 사용할 수 있으나, 함수 리터럴로 평가되어 실행 함수를 다시 호출할 수 없음
- 즉시 실행 함수는 그룹 연산자 (..) 로 감싸줘야 함
// 익명 즉시 실행 함수
(function() {
var a = 3;
var b = 5;
return a * b;
}());
// 기명 즉시 실행 함수
(function foo() {
var a = 3;
var b = 5;
return a * b;
}());
foo(); // ReferenceError: foo is not defined
- 즉시 실행 함수도 일반 함수처럼 값을 반환할 수 있고 인수를 전달할 수도 있음
var res = (function() {
var a = 3;
var b = 5;
return a * b;
}());
res = (function(a, b) {
return a * b;
}(3, 5));
12.7.2 재귀함수
- 탈출조건을 꼭 만들어줘야 함
function countdown(n) {
if (n < 0) return;
console.log(n);
countdown(n - 1);
}
countdown(10);
12.7.3 중첩 함수
- 함수 내부에 정의된 함수
- 중첩 함수 혹은 내부 함수라고 함
- 중첩 함수를 포함하는 함수는 외부 함수
- 중첩 함수는 외부 함수 내부에서만 호출 가능
function outer() {
var x = 1;
function inner() {
var y = 2;
// 외부 함수의 변수를 참조할 수 있음
console.log(x + y);
}
inner();
}
outer();
12.7.4 콜백 함수
- 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수? 콜백 함수
- 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수? 고차 함수
function repeat(n, f) {
for(var i=0; i < n; i++){
f(i); // i를 전달하면서 f를 호출
}
}
var logAll = function(i) {
console.log(i);
};
// 반복 호출할 함수를 인수로 전달함
repeat(5, logAll); // 0 1 2 3 4
var logOdds = function(i){
if (i % 2) console.log(i);
};
// 반복 호출할 함수를 인수로 전달함
repeat(5, logOdds); // 1 3
- 콜백 함수는 비동기 처리에 활용되는 중요한 패턴
- 비동기 처리 뿐만 아니라 배열 고차 함수에서도 사용됨
12.7.5 순수 함수와 비순수 함수
순수함수?
: 어떤 외부 상태에 의존하지도 않고 변경하지도 않는 부수 효과가 없는 함수
- 동일한 인수가 전달되면 언제나 동일한 값을 반환함
- 오직 매개변수를 통해 함수 내부로 전달된 인수에게만 의존해 값을 생성해 반환함
var count = 0;
// 순수 함수 increase는 동일한 인수가 전달되면 언제나 동일한 값을 반환함
function increase(n) {
return ++n;
}
// 순수 함수가 반환한 결과값을 변수에 재할당해서 상태를 변경
count = increase(count);
console.log(count); // 1
count = increase(count);
console.log(count); // 2
비순수 함수?
: 외부 상태에 의존하거나 외부 상태를 변경하는 부수 효과가 있는 함수
var count = 0;
// 비순수함수
function increase() {
return ++count;
}
// 비순수 함수는 외부 상태를 변경하므로 상태 변화를 추적하기 어려워진다
increase();
console.log(count); // 1
increase();
console.log(count); // 2
'2022-2 웹개발 스터디' 카테고리의 다른 글
[모던 JS] CH23 실행컨텍스트, CH13 스코프 (0) | 2022.10.03 |
---|---|
[코드] (0) | 2022.09.21 |
[모던 JS] CH10 객체 리터럴, CH11 원시 값과 객체의 비교 (0) | 2022.09.20 |
[모던 JS] CH8 제어문, CH9 타입 변환과 단축 평가 (1) | 2022.09.19 |
[모던 JS] CH6 데이터 타입, CH7 연산자 (0) | 2022.09.14 |