인수를 매개변수를 통해 함수에 전달하면서 함수의 실행하는 것을 함수 호출이라 한다.
// 함수 호출
var result = add(2, 5);
// 함수 add에 인수 2, 5를 전달하면서 호출하면 반환값 7을 반환한다.
console.log(result); // 7
코드의 재사용, 유지보수의 편의성, 가독성
--> 함수는 어디든 여러번 호출할 수 있다.
❖ 리터럴: 값을 생성하기 위한 표기법
// 변수에 함수 리터럴을 할당
var f = function add(x, y) {
return x + y;
};
= 함수는 호출할 수 있는 객체다! (JavaScript만의 고유 특징)
// 함수 선언문
function add(x, y) {
return x + y;
}
// 함수 참조
// console.dir은 console.log와는 달리 함수 객체의 프로퍼티까지 출력한다.
// 단, Node.js 환경에서는 console.log와 같은 결과가 출력된다.
console.dir(add); // ƒ add(x, y)
// 함수 호출
console.log(add(2, 5)); // 7
함수 선언문은 함수 이름을 생략할 수 없다. --> 변수에 할당할 수 없음
undefined
가 출력된다.// 기명 함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석된다.
// 함수 선언문에서는 함수 이름을 생략할 수 없다.
function foo() { console.log('foo'); }
foo(); // foo
// 함수 리터럴을 피연산자로 사용하면 함수 선언문이 아니라 함수 리터럴 표현식으로 해석된다.
// 함수 리터럴에서는 함수 이름을 생략할 수 있다.
(function bar() { console.log('bar'); });
bar(); // ReferenceError: bar is not defined
함수 리터럴(foo
)은 함수 선언문으로 해석된다.
함수 리터럴(bar
)는 함수 리터럴 표현식으로 해석된다.
함수 선언문으로 생성된 foo
는 호출할 수 있고 함수 리터럴 bar
는 호출할 수 없다.
bar
함수는 함수를 가리키는 식별자가 없기 때문에 호출할 수 없다.
(= bar
함수는 함수 몸체 내에서만 참조할 수 있는 식별자이다.
foo
함수를 호출할 수 있는 이유: 자바스크립트 엔진이 암묵적으로 생성한 식별자 함수 이름은 함수 몸체 내부에서만 유효한 식별자이므로 함수 객체를 가리키는
식별자
가 필요하다.함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출한다.
함수는 일급 객체 이므로 함수를 값처럼 자유롭게 사용할 수 있다. -> 변수에 할당할 수 있다.
// 함수 표현식
var add = function (x, y) {
return x + y;
};
console.log(add(2, 5)); // 7
일반적으로 함수 표현식의 함수리터럴은 함수 이름을 생략한다.
// 함수 참조
console.dir(add); // ƒ 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;
};
함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출할 수 있다.
함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출할 수 없다.
- 함수 표현식은 할당문이 실행되는 시점에 평가되어
변수 호이스팅
이 발생하기 때문
호이스팅
함수 선언문이 코드 맨 위로 끌어 올려진 것처럼 동작하는 특징
❖ 변수 호이스팅과의 차이점: var
로 선언된 변수는 undefined
로 초기화, 함수 선언문으로 생성된 식별자는 함수 객체
로 초기화 --> 함수선언문은 함수 호이스팅에 의해 호출 가능
function add(x, y) {
return x + y;
}
console.log(add(2)); // NaN
매개변수의 개수와 인수의 개수가 일치하는지 체크하지 않는다.(에러 발생 ❌)
undefined
x + y => 2 + undefined가 되므로 NaN
이 반환된다.
초과된 인수
function add(x, y) {
return x + y;
}
console.log(add(2, 5, 10)); // 7
function add(x, y) {
console.log(arguments);
// Arguments(3) [2, 5, 10, callee: ƒ, Symbol(Symbol.iterator): ƒ]
return x + y;
}
add(2, 5, 10);
초과된 인수는 암묵적으로 arguments
객체의 프로퍼티로 보관된다.
-> 매개변수 개수를 확정할 수 없는 가변 인자 함수를 구현할 때 사용
이상적인 함수의 매개변수 최대 개수는 3개를 넘지 않는 것을 권장함
반환값 지정하지 않으면 undefined 반환
function foo () {
return;
}
console.log(foo()); // undefined
반환값 생략하면 undefined 반환
function foo () {
// 반환문을 생략하면 암묵적으로 undefined가 반환된다.
}
console.log(foo()); // undefined
자동으로 세미콜론이 삽입되어 undefined 반환
function multiply(x, y) {
// return 키워드와 반환값 사이에 줄바꿈이 있으면
return // 세미콜론 자동 삽입 기능(ASI)에 의해 세미콜론이 추가된다.
x * y; // 무시된다.
}
console.log(multiply(3, 5)); // undefined
// 매개변수 primitive는 원시 값을 전달받고, 매개변수 obj는 객체를 전달받는다.
function changeVal(primitive, obj) {
primitive += 100;
obj.name = 'Kim';
}
// 외부 상태
var num = 100;
var person = { name: 'Lee' };
console.log(num); // 100
console.log(person); // {name: "Lee"}
// 원시 값은 값 자체가 복사되어 전달되고 객체는 참조 값이 복사되어 전달된다.
changeVal(num, person);
// 원시 값은 원본이 훼손되지 않는다.
console.log(num); // 100
// 객체는 원본이 훼손된다.
console.log(person); // {name: "Kim"}
changeVal
함수는 함수 몸체에서 값을 변경한다.
단 한번 호출, 다시 호출 ❌
// 익명 즉시 실행 함수
(function () {
var a = 3;
var b = 5;
return a * b;
}());
// 즉시 실행 함수도 일반 함수처럼 값을 반환할 수 있다.
var res = (function () {
var a = 3;
var b = 5;
return a * b;
}());
console.log(res); // 15
// 즉시 실행 함수에도 일반 함수처럼 인수를 전달할 수 있다.
res = (function (a, b) {
return a * b;
}(3, 5));
console.log(res); // 15
반복 처리를 위해 사용
ex) 팩토리얼
함수 내부에서 자기 자신을 호출할 수 있기 때문에 가능 (함수 표현식)
// 팩토리얼(계승)은 1부터 자신까지의 모든 양의 정수의 곱이다.
// n! = 1 * 2 * ... * (n-1) * n
function factorial(n) {
// 탈출 조건: n이 1 이하일 때 재귀 호출을 멈춘다.
if (n <= 1) return 1;
// 재귀 호출
return n * factorial(n - 1);
}
console.log(factorial(0)); // 0! = 1
console.log(factorial(1)); // 1! = 1
console.log(factorial(2)); // 2! = 2 * 1 = 2
console.log(factorial(3)); // 3! = 3 * 2 * 1 = 6
console.log(factorial(4)); // 4! = 4 * 3 * 2 * 1 = 24
console.log(factorial(5)); // 5! = 5 * 4 * 3 * 2 * 1 = 120
동일한 인수가 전달되면 언제나 동일한 값을 반환하는 함수
var count = 0;
function increase(n) {
return ++n;
}
count = increase(count);
console.log(count); //1
let num3 = 10
func sum(num1: Int, num2: Int) -> Int {
return num1 + num2 + num3
}
num3을 전역변수라면 결과값은 num3의 값에 따라서 변경이 된다.
num3을 전역변수라면 결과값은 num3의 값에 따라서 변경이 된다.
var count = 0;
function increase() {
return ++n;
}
increase();
console.log(count); //1
let obj = {
a: 1
};
function func(obj) {
return obj.b = 1; // 인자로 받은 객체에 b 값을 추가하여 리턴
}
func(obj);
console.log(obj); // { a: 1, b: 1 }
위 함수는 외부 obj 객체에 b가 추가되었기 때문에 순수함수가 아니다.
비순수함수는 외부상태(count)
를 변경하므로 상태변화를 추적하기 어려워진다. 따라서 함수 외부 상태의 변경을 지양하는 순수함수
를 사용하는 것이 좋다.