6. 함수(Function)
1. 키워드
- 함수(Function)
- 매개변수(Parameter)와 인수(Argument)
- 지역 변수(Local Variable)와 전역 변수(Global Variable)
- 함수 호이스팅(Hoisting)
arguments
객체- 디폴트 매개변수(Default Parameter)와 나머지 매개변수(Rest Parameter)
2. 함수의 기초
1) 함수란?
- 함수란 하나의 특별한 목적의 작업을 수행하도록 설계된 독립적인 블록을 의미한다.
- 이러한 함수는 필요할 때마다 호출하여 해당 작업을 반복해서 수행할 수 있다.
Note
- 자바스크립트에서 블록이란 함수나 실행문의
{}
(중괄호)로 묶여진 부분을 가리킨다.
2) 자바스크립트 함수
-
자바스크립트에서는 함수도 하나의 타입이다.
-
따라서 함수를 변수에 대입하거나, 함수에 프로퍼티를 지정하는 것도 가능하다.
- 또한, 자바스크립트 함수는 다른 함수 내에 중첩되어 정의될 수 있다.
3) 함수의 정의
- 자바스크립트에서 함수의 정의는
function
키워드로 시작되며, 다음과 같은 구성요소를 가진다.
1] 함수의 이름
2] 괄호 안에 ,
(쉼표)로 구분되는 함수의 매개변수
3] {}
로 둘러싸인 자바스크립트 실행문
- 자바스크립트에서 함수를 정의하는 문법은 다음과 같다.
- 함수 이름은 함수를 구분하는 식별자이다.
- 매개변수란 함수를 호출할 때 인수로 전달된 값을 함수 내부에서 사용할 수 있게 해주는 변수이다.
// addNum라는 이름의 함수를 정의함.
function addNum(x, y) {
// x, y는 이 함수의 매개변수임.
document.write(x + y);
}
addNum(2, 3); // addNum() 함수에 인수로 2와 3을 전달하여 호출함.
- 위의 예제에서 매개변수
x
에는 인수2
가 저장되고,y
에는 인수3
이 저장되어 사용된다. - 이렇게 인수와 매개변수는 개수뿐만 아니라 순서 또한 매우 중요하게 적용된다.
Note
- 함수의 인수란 함수가 호출될 때 함수로 값을 전달해주는 변수나 상수를 의미한다.
4) 반환(Return)문
- 자바스크립트에서 함수는 반환문을 포함할 수 있다.
- 이러한 반환문을 통해 호출자는 함수에서 실행된 결과를 전달받을 수 있다.
- 반환문은 함수의 실행을 중단하고,
return
키워드 다음에 명시된 표현식의 값을 호출자에게 반환한다. - 반환문은 배열이나 객체를 포함한 모든 타입의 값을 반환할 수 있다.
function multiNum(x, y) {
return x * y; // x와 y를 곱한 결과를 반환함.
}
var num = multiNum(3, 4); // multiNum() 함수가 호출된 후, 그 반환값이 변수 num에 저장됨.
document.write(num);
5) 함수의 호출
- 정의된 함수는 프로그램 내에서 호출되어야 비로소 실행된다.
- 일반적인 함수의 호출은 함수의 정의문과 같은 형태로 호출할 수 있다.
var sum = addNum(3, 5); // 함수 addNum()을 호출하면서, 인수로 3과 5를 전달합니다.
// 함수의 호출이 끝난 뒤에는 그 반환값을 변수 sum에 대입합니다.
- 위의 예제에서 인수로 전달된 숫자
3
과5
는 함수에서 정의된 매개변수x
와y
에 각각 대입된다. - 따라서 호출된 함수의 내부에서는 매개변수
x
와y
에 각각3
과5
가 대입되어 계산된다.
6) 값으로서의 함수
- 자바스크립트에서 함수는 문법적 구문일뿐만 아니라 값이기도 하다.
- 따라서 함수가 변수에 대입될 수도 있으며, 다른 함수의 인수로 전달될 수도 있다.
- 다음 예제는 함수를 변수에 저장하여 사용하는 예제이다.
function sqr(x) {
// 제곱의 값을 구하는 함수 sqr를 정의함.
return x * x;
}
var sqrNum = sqr; // 변수 sqrNum에 함수 sqr을 대입함.
document.write(sqr(4) + "<br>"); // 함수 sqr을 호출함.
document.write(sqrNum(4)); // 변수 sqrNum를 함수처럼 호출함.
3. 변수의 유효 범위(Variable Scope)
- 자바스크립트에서 객체나 함수는 모두 변수이다.
- 변수의 유효 범위란 해당 변수가 접근할 수 있는 변수, 객체 그리고 함수의 집합을 의미한다.
- 자바스크립트에서 변수는 유효 범위에 따라 다음과 같이 구분된다.
1] 지역 변수
2] 전역 변수
1) 지역 변수
- 지역 변수란 함수 내에서 선언된 변수를 가리킨다.
- 이러한 지역 변수는 변수가 선언된 함수 내에서만 유효하며, 함수가 종료되면 메모리에서 사라진다.
- 함수의 매개변수 또한 함수 내에서 정의되는 지역 변수처럼 동작한다.
function localNum() {
var num = 10; // 지역 변수 num에 숫자 10을 대입함.
document.write(
"함수 내부에서 변수 num의 타입은 " + typeof num + "입니다.<br>" // number
);
}
localNum(); // 함수 localNum()을 호출함.
document.write(
"함수의 호출이 끝난 뒤 변수 num의 타입은 " + typeof num + "입니다." // undefined
);
Note
- 자바스크립트에서는 선언되지 않은 변수를 사용하려고 하거나 접근하려고 하면 오류를 발생시킨다.
- 하지만 선언되지 않은 변수에 대한
typeof
연산자의 결괏값은undefined
값을 반환한다.
2) 전역 변수
- 전역 변수란 함수의 외부에서 선언된 변수를 가리킨다.
- 이러한 전역 변수는 프로그램의 어느 영역에서나 접근할 수 있으며, 웹 페이지가 닫혀야만 메모리에서 사라진다.
var num = 10; // 전역 변수 num을 선언함.
function globalNum() {
document.write("함수 내부에서 변수 num의 값은 " + num + "입니다.<br>"); // 10
num = 20; // 전역 변수 num의 값을 함수 내부에서 변경함.
}
globalNum(); // 함수 globalNum()을 호출함.
document.write("함수의 호출이 끝난 뒤 변수 num의 값은 " + num + "입니다."); // 20
- 위의 예제처럼 전역 변수는 함수 외부뿐만 아니라 내부에서도 접근하여 변경할 수 있다.
- 자바스크립트에서 지역 변수를 선언할 때에는 반드시
var
키워드를 사용하여 선언해야 한다. - 함수 내부에서
var
키워드를 사용하지 않고 변수를 선언하면, 해당 변수는 지역 변수가 아닌 전역 변수로 선언된다.
function globalNum() {
num = 10; // var 키워드를 사용하지 않고 변수 num을 선언함.
document.write("함수 내부에서 변수 num의 값은 " + num + "입니다.<br>"); // 10
}
globalNum(); // 함수 globalNum()을 호출함.
document.write("함수의 호출이 끝난 뒤 변수 num의 값은 " + num + "입니다."); // 10
- 또한, 전역 변수와 같은 이름의 지역 변수를 선언하면, 해당 블록에서는 해당 이름으로 지역 변수만을 호출할 수 있다.
var num = 10; // 전역 변수 num을 선언함.
function globalNum() {
var num = 20; // 같은 이름의 지역 변수 num을 선언함.
document.write("함수 내부에서 변수 num의 값은 " + num + "입니다.<br>"); // 20
}
globalNum(); // 함수 globalNum()을 호출함.
document.write("함수의 호출이 끝난 뒤 변수 num의 값은 " + num + "입니다."); // 10
- 위의 예제와 같은 경우 해당 블록에서 전역 변수를 호출하려면, 전역 변수가
window
객체의 프로퍼티임을 명시하면 된다.
var num = 10; // 전역 변수 num을 선언함.
function globalNum() {
var num = 20; // 같은 이름의 지역 변수 num을 선언함.
document.write("함수 내부에서 변수 num의 값은 " + num + "입니다.<br>");
document.write("함수 내부에서 변수 num의 값은 " + window.num + "입니다.<br>");
}
globalNum(); // 함수 globalNum()을 호출함.
4. 함수의 유효 범위(Function Scope)
- 대부분의 프로그래밍 언어에서는 블록 내에서 정의된 변수를 블록 외부에서는 접근할 수 없다.
- 블록이란 코드 내에서
{}
로 둘러싸인 부분을 가리킨다. - 이러한 블록을 기준으로 하는 유효 범위를 블록 단위의 유효 범위라고 한다.
- 하지만 자바스크립트는 다른 언어와는 달리 함수를 블록 대신 사용한다.
- 자바스크립트에서 함수는 자신이 정의된 범위 안에서 정의된 모든 변수 및 함수에 접근할 수 있다.
- 전역 함수는 모든 전역 변수와 전역 함수에 접근할 수 있다.
- 반면, 다른 함수 내에 정의된 내부 함수는 그 함수의 부모 함수에서 정의된 모든 변수 및 부모 함수가 접근할 수 있는 모든 다른 변수까지도 접근할 수 있다.
// x, y를 전역 변수로 선언함.
var x = 10,
y = 20;
// sub()를 전역 함수로 선언함.
function sub() {
return x - y; // 전역 변수인 x, y에 접근함.
}
document.write(sub() + "<br>");
// parentFunc()을 전역 함수로 선언함.
function parentFunc() {
var x = 1,
y = 2; // 전역 변수와 같은 이름으로 선언하여 전역 변수의 범위를 제한함.
function add() {
// add() 함수는 내부 함수로 선언됨.
return x + y; // 전역 변수가 아닌 지역 변수 x, y에 접근함.
}
return add();
}
document.write(parentFunc());
1) 함수 호이스팅
- 자바스크립트에서 함수의 유효 범위라는 것은 함수 안에서 선언된 모든 변수는 함수 전체에 걸쳐 유효하다는 의미이다.
- 그런데 이 유효 범위의 적용이 변수가 선언되기 전에도 똑같이 적용된다.
- 이러한 자바스크립트의 특징을 함수 호이스팅이라고 한다.
- 즉, 자바스크립트 함수 안에 있는 모든 변수의 선언은 함수의 맨 처음으로 이동된 것처럼 동작한다.
var globalNum = 10; // globalNum을 전역 변수로 선언함.
function printNum() {
document.write(
"지역 변수 globalNum 선언 전의 globalNum의 값은 " +
globalNum +
"입니다.<br>"
); // ①
var globalNum = 20; // globalNum을 지역 변수로 선언함. // ②
document.write(
"지역 변수 globalNum 선언 후의 globalNum의 값은 " +
globalNum +
"입니다.<br>"
);
}
printNum();
- 위의 예제 ①의 시점에서는 변수
globalNum
가 전역 변수를 가리킨다고 생각하기 쉽다. - 하지만 자바스크립트 내부에서는 함수 호이스팅에 의해 다음과 같이 코드가 변경되어 처리된다.
var globalNum = 10;
function printNum() {
var globalNum; // 함수 호이스팅에 의해 변수의 선언 부분이 함수의 맨 처음 부분으로 이동됨.
document.write(
"지역 변수 globalNum 선언 전의 globalNum의 값은 " +
globalNum +
"입니다.<br>"
);
globalNum = 20;
document.write(
"지역 변수 globalNum 선언 후의 globalNum의 값은 " +
globalNum +
"입니다.<br>"
);
}
printNum();
- 위의 예제 ①의 시점에서는
globalNum
라는 지역 변수가 선언만 되어 있고, 아직 초기화만 안 된 상태이다. - 따라서 이때
globalNum
변수에 접근하면 아직 초기화되지 않은 변수에 접근했으므로,undefined
값을 반환하게 된다. - 실제로 변수가 초기화되는 시점은 원래 코드에서 변수가 선언된 ②의 시점이다.
Note
- 자바스크립트에서는 함수 호이스팅이 자동으로 수행되지만, 항상 함수 블록의 첫 부분에 변수를 선언하는 것이 좋다.
5. 매개변수와 인수
1) 매개변수
- 자바스크립트에서는 함수를 정의할 때는 매개변수의 타입을 따로 명시하지 않는다.
- 함수를 호출할 때에도 인수로 전달된 값에 대해 어떠한 타입 검사도 하지 않는다.
- 함수를 호출할 때 함수의 정의보다 적은 수의 인수가 전달되더라도, 다른 언어와는 달리 오류를 발생시키지 않는다.
- 이 같은 경우 자바스크립트는 전달되지 않은 나머지 매개변수에 자동으로
undefined
값을 설정한다.
Note
- 매개변수란 함수의 정의에서 전달받은 인수를 함수 내부로 전달하기 위해 사용하는 변수를 의미한다.
- 인수란 함수가 호출될 때 함수로 값을 전달해주는 값을 말한다.
- 다음 예제는
3
개의 매개변수를 가지는 함수에 각각 다른 수의 인수를 전달하는 예제이다.
function addNum(x, y, z) {
// x, y, z라는 3개의 매개변수를 가지는 함수 addNum()을 정의함.
return x + y + z;
}
addNum(1, 2, 3); // 인수로 1, 2, 3을 전달하여 함수를 호출함. -> 6
addNum(1, 2); // 인수로 1, 2을 전달하여 함수를 호출함. -> NaN
addNum(1); // 인수로 1을 전달하여 함수를 호출함. -> NaN
addNum(); // 인수로 아무것도 전달하지 않고 함수를 호출함. -> NaN
- 위의 예제에서
addNum()
함수를 호출할 때 인수가3
개보다 적게 전달되면, 계산할 수 없다는 의미인NaN
을 반환한다. - 그 이유는 전달되지 않은 나머지 값이 자동으로
undefined
값으로 설정되어, 산술 연산을 수행할 수 없기 때문이다.
- 하지만 다음 예제처럼 하면
NaN
을 반환하지 않고 전달된 인수만을 가지고 정상적으로 계산하는 함수를 작성할 수 있다.
function addNum(x, y, z) {
if (x === undefined)
// 함수 호출시 x에 해당하는 인수가 전달되지 않은 경우
x = 0; // 변수 x의 값을 undefined에서 0으로 변경함.
if (y === undefined)
// 함수 호출시 y에 해당하는 인수가 전달되지 않은 경우
y = 0; // 변수 y의 값을 undefined에서 0으로 변경함.
if (z === undefined)
// 함수 호출시 z에 해당하는 인수가 전달되지 않은 경우
z = 0; // 변수 z의 값을 undefined에서 0으로 변경함.
return x + y + z;
}
addNum(1, 2, 3); // 6
addNum(1, 2); // 3
addNum(1); // 1
addNum(); // 0
2) arguments
객체
- 만약 함수의 정의보다 더 많은 수의 인수가 전달되면, 매개변수에 대입되지 못한 인수들은 참조할 방법이 없게 된다.
- 하지만
arguments
객체를 이용하면, 함수로 전달된 인수의 총 개수를 확인하거나, 각각의 인수에도 바로 접근할 수 있다.
arguments
객체는 함수가 호출될 때 전달된 인수를 배열의 형태로 저장하고 있다.- 첫 번째 인수는
arguments[0]
에 저장되며, 다음 인수는arguments[1]
에 저장된다. - 또한, 인수의 총 개수는
arguments
객체의length
프로퍼티에 저장된다.
- 다음 예제의
addNum()
함수는 전달받는 인수의 개수에 상관없이 언제나 정상적인 계산을 수행한다.
function addNum() {
var sum = 0; // 합을 저장할 변수 sum을 선언함.
for (var i = 0; i < arguments.length; i++) {
// 전달받은 인수의 총 수만큼 반복함.
sum += arguments[i]; // 전달받은 각각의 인수를 sum에 더함.
}
return sum;
}
addNum(1, 2, 3); // 6
addNum(1, 2); // 3
addNum(1); // 1
addNum(); // 0
addNum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // 55
Note
arguments
객체는 배열과 비슷할 뿐, 실제로Array
객체는 아니다.- 숫자로 된 인덱스와
length
프로퍼티만을 가지고 있을 뿐, 모든 것을 배열처럼 다룰 수는 없다.
3) 디폴트 매개변수
- 디폴트 매개변수란 함수를 호출할 때 명시된 인수를 전달하지 않았을 경우에 사용하게 될 기본값을 의미한다.
- 자바스크립트에서 매개변수의 기본값은
undefined
값으로 설정되어 있다.
function mul(a, b) {
// 인수가 한 개만 전달되었을 때 나머지 매개변수의 값을 undefined 값이 아닌 1로 설정함.
b = typeof b !== "undefined" ? b : 1;
return a * b;
}
mul(3, 4); // 12
mul(3); // 3
- 하지만 디폴트 매개변수를 이용하면 이러한 매개변수의 기본값을 바꿀 수 있다.
function mul(a, b = 1) {
// 인수가 한 개만 전달되면 나머지 매개변수의 값을 언제나 1로 설정해 줌.
return a * b;
}
mul(3, 4); // 12
mul(3); // 3
4) 나머지 매개변수
- 나머지 매개변수는
...
(생략 접두사)를 사용하여 특정 위치의 인수부터 마지막 인수까지를 한 번에 지정할 수 있다.
- 다음 예제는 첫 번째 인수에서 두 번째 인수부터 마지막 인수까지를 뺀 후 그 결과를 반환하는 예제이다.
function sub() {
var firstNum = arguments[0]; // 첫 번째 인수에서
for (var i = 0; i < arguments.length - 1; i++) {
// 두 번째부터 마지막 인수까지를
firstNum -= arguments[i + 1]; // 뺌.
}
return firstNum;
}
sub(10, 2, 3); // 10 - 2 - 3 = 5
sub(10, 1, 5, 8); // 10 - 1 - 5 - 8 = -4
- 하지만 나머지 매개변수를 이용하면
sub()
함수를 좀 더 직관적으로 정의할 수 있다.
// 첫 번째 인수를 변수 firstNum에 저장하고 나머지 인수들은 배열 restArgs에 저장함.
function sub(firstNum, ...restArgs) {
for (var i = 0; i < restArgs.length; i++) {
firstNum -= restArgs[i];
}
return firstNum;
}
sub(10, 2, 3); // 10 - 2 - 3 = 5
sub(10, 1, 5, 8); // 10 - 1 - 5 - 8 = -4
5) 미리 정의된 전역 함수
- 자바스크립트는 사용자의 편의를 위해 다양한 기능의 여러 전역 함수를 미리 정의하여 제공한다.
- 이러한 전역 함수는 자바스크립트의 어떤 타입의 객체에서도 바로 사용할 수 있다.
- 자바스크립트에서 미리 정의되어 있는 전역 함수는 다음과 같다.
(1) eval()
- 문자열로 표현된 자바스크립트 코드를 실행하는 함수이다.
var x = 10,
y = 20;
var a = eval("x + y"); // 30
var b = eval("y * 3"); // 60
document.write(a + "<br>" + b);
(2) isFinite()
- 전달된 값이 유한한 수인지를 검사하여 그 결과를 반환한다.
- 만약 인수로 전달된 값이 숫자가 아니라면, 숫자로 변환하여 검사한다.
isFinite(123); // true
isFinite(123e100); // true
isFinite(0); // true
isFinite(true); // true
isFinite(false); // true
isFinite(null); // true
isFinite("123"); // true
isFinite(""); // true
isFinite("문자열"); // false
isFinite(undefined); // false
isFinite(NaN); // false
(3) isNaN()
- 전달된 값이
NaN
인지를 검사하여 그 결과를 반환한다. - 만약 인수로 전달된 값이 숫자가 아니라면, 숫자로 강제 변환하여 검사한다.
- 전달된 값이 숫자인지 아닌지를 확인하기 위하여
typeof
연산자를 대신 사용할 수도 있다.
isNaN(123); // false
isNaN(123e100); // false
isNaN(0); // false
isNaN(true); // false
isNaN(false); // false
isNaN(null); // false
isNaN("123"); // false
isNaN(""); // false
isNaN("문자열"); // true
isNaN(undefined); // true
isNaN(NaN); // true
(4) parseFloat()
- 문자열을 파싱하여 부동 소수점 수(Floating-point Number)로 반환한다.
parseFloat("123"); // 123
parseFloat("123.000"); // 123
parseFloat("123.456"); // 123.456
parseFloat("12 34 56"); // 12
parseFloat(" 123 "); // 123
parseFloat("123 초콜릿"); // 123
parseFloat("초콜릿 123"); // NaN
(5) parseInt()
- 문자열을 파싱하여 정수로 반환한다.
parseInt("123"); // 123
parseInt("123.000"); // 123
parseInt("123.456"); // 123
parseInt("12 34 56"); // 12
parseInt(" 123 "); // 123
parseInt("123 초콜릿"); // 123
parseInt("초콜릿 123"); // NaN
parseInt("10", 10); // 10
parseInt("10", 8); // 8
parseInt("10", 16); // 16
parseInt("0x10"); // 16
- 위의 예제처럼
parseInt()
함수에 두 번째 인수로 특정 진법을 전달하면, 해당 진법에 맞는 정수로 반환한다. - 또한, 전달받은 문자열의 시작이
"0x"
로 시작하면,parseInt()
함수는 해당 문자열을 16진수로 인식한다.
(6) encodeURI()
와 encodeURIComponent()
encodeURI()
함수는 URI(Uniform Resource Identifier)에서 주소를 표시하는 특수문자를 제외하고, 모든 문자를 이스케이프 시퀀스(Escape Sequences) 처리하여 부호화한다.- 하지만
encodeURIComponent()
함수는 URI에서encodeURI()
함수에서 부호화하지 않은 모든 문자까지 포함하여 이스케이프 시퀀스 처리한다.
var uri = "http://google.com/search.php?name=홍길동&city=서울";
var enc1 = encodeURI(uri);
var enc2 = encodeURIComponent(uri);
document.write(enc1 + "<br>" + enc2);
(7) decodeURI()
와 decodeURIComponent()
decodeURI()
함수는encodeURI()
함수나 다른 방법으로 만들어진 URI를 해독한다.decodeURIComponent()
함수는encodeURIComponent()
함수나 다른 방법으로 만들어진 URI 컴포넌트를 해독한다.
var uri = "http://google.com/search.php?name=홍길동&city=서울";
var enc1 = encodeURI(uri);
var enc2 = encodeURIComponent(uri);
document.write(enc1 + "<br>" + enc2 + "<br><br>");
var dec1 = decodeURI(enc1);
var dec2 = decodeURIComponent(enc2);
document.write(dec1 + "<br>" + dec2);
(8) Number()
- 전달받은 객체의 값을 숫자로 반환한다.
Number("123"); // 123
Number("123.000"); // 123
Number("123.456"); // 123.456
Number("12 34 56"); // NaN
Number("123 초콜릿"); // NaN
Number(true); // 1
Number(false); // 0
Number(new Date()); // 현재 날짜에 해당하는 숫자를 반환함.
Number(null); // 0
(9) String()
- 전달받은 객체의 값을 문자열로 반환한다.
String(123); // 123
String(123.456); // 123.456
String("123"); // 123
String(new Date()); // 현재 날짜에 해당하는 문자열을 반환함.
String(null); // null
String(true); // true
String(false); // false
String(Boolean(1)); // true
String(Boolean(0)); // false
References
- http://www.tcpschool.com/javascript/js_function_basic
- http://www.tcpschool.com/javascript/js_function_variableScope
- http://www.tcpschool.com/javascript/js_function_functionScope
- http://www.tcpschool.com/javascript/js_function_parameterArgument
- http://www.tcpschool.com/javascript/js_function_predefinedFunction