on
[Javascript]함수(1)
함수의 정의와 표현 방법
함수
함수란 목적을 달성하기 위한 일련의 과정을 문으로 구현하고 코드블록으로 감싸서 하나의 실행 단위로 정의한 것이다.
//함수도 수학과 같이 입력을 받아 출력을 내보낸다.
// f(x, y) = x + y
function add(x, y) {
return x + y;
}
// f(2, 5) = 7
add(2, 5); // 7
1. 함수의 구성과 호출
함수 이름: 값인 함수를 구별하기 위해 사용하는 이름
- 매개변수(parameter): 함수 내부로 전달하는 입력을 전달받은 변수
- 인수(argument): 함수를 호출하면서 함수 내부로 전달할 입력 값
- 리턴값(반환값, return value): 함수가 실행 후 내부의 과정을 거치면서 반환한 결과 값
함수는 정의만으로 실행되지 않는다. 정의한 함수를 호출해야 실행된다.
// 함수 정의
function add(x, y) {
return x + y;
}
// 함수 호출
add(2, 5);
2. 함수 왜 사용는 걸까?
함수는 한번 정의하면 여러 번 호출할 수 있다. 즉 재사용이 가능하다. 동일한 작업(기능)을 반복적으로 수행한다면 함수를 정의하고 재사용함으로써 유지보수의 편의성을 높이고 코드 신뢰성을 높인다.
//함수를 사용하지 않고 반복적으로 코드 작성
var x = 0;
var y = 0;
var result = 0;
x = 1;
y = 2;
result = x + y;
x = 4;
y = 5;
result = x + y;
x = 7;
y = 2;
result = x + y;
// 함수를 이용하여 더하기 기능을 재사용함
var result = 0;
function add() {
reutrn x + y;
}
result = add(1,2);
result = add(4,5);
result = add(7,2);
3. 함수 리터럴
함수 리터럴은 function 키워드, 함수 이름, 매개 변수 목록, 함수 몸체로 구성된다.
function add(x, y) {
return x + y;
}
// function -> 키워드
// add -> 함수 이름
// x,y -> 매개 변수 목록
// {...} -> 함수 몸체
함수 이름
- 함수 이름은 함수를 구별하는 식별자 역할을 함으로 식별자 네이밍 규칙을 준수해야한다.
- 함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자다.
- 함수 이름은 생략할 수 있다. (이름이 있는 함수:기명 함수, 이름이 없는 함수: 무명/익명 함수)
매개변수 목록
- 0개 이상의 매개변수를 소괄호로 감싸고 쉼표로 구분한다.
- 각 매개변수에는 함수를 호출할 때 지정한 인수가 순서대로 할당된다.
- 매개변수는 함수 몸체 내에서 변수와 동일하게 취급한다. 따라서 매개변수도 식별자 네이밍 규칙을 준수해야 한다.
함수 몸체
- 함수가 호출되었을 때 일괄적으로 실행될 문들을 하나의 실행단위로 정의한 코드 블록이다.
- 함수 몸체는 함수 호출에 의해 실행된다.
함수는 객체 값이다. 일반 객체와 다른 점은 일반 객체는 호출할 수 없지만, 함수는 호출할 수 있는 객체이며, 다른 객체는 없는 고유한 프로퍼티를 갖는다.
4. 함수의 정의
1) 함수 선언문
함수 리터럴과 형태는 동일하나, 함수 이름을 생략할 수 없다.
function add(x, y) {
return x + y;
}
function (x, y) {
return x + y;
}
// SyntaxError: Function statements require a function name
함수 선언문은 표현식이 아닌 문이다. 즉 표현식으로서 평가되어 생성된 함수가 출력되는 것이 아니라 undefined
가 출력되며, 함수 선언문은 값으로 사용할 수 없는 문이다.
하지만 함수 표현식을 보면 함수 선언문이 변수에 값으로 할당 되는 것으로 보이기도 한다.
var item = function add(x, y) {
return x + y;
};
하지만 여기서 변수에 할당된 것은 함수 선언문이 아닌 함수 리터럴이다. 변수에 할당할 수 있는 것은 값으로 평가될 수 있는 표현식이므로 함수 선언문은 변수에 할당할 수 없고 자바스크립트 엔진은 당연히 함수 add가 함수 선언문이 아닌 값으로 평가받는 함수 리터럴이라고 해석하는 것이다. 이처럼 함수가 단독으로 사용되면 함수선언문이라고 해석되고, 변수에 할당하거나 피연산자로 사용하는 함수의 경우 함수 선언문이 아닌 함수 리터럴로 해석된다.(혼자 있는 함수 리터럴은 없는 것이다)
함수 선언문으로 평가되는지, 리터럴로 평가되는지의 가장 큰 차이점은 값으로 평가된 함수 리터럴은 함수 객체를 참조하고 있는 식별자가 없으므로 호출할 수가 없다. 함수를 함수 밖에서 호출할때는 함수 이름을 호출하는 것이 아니라, 함수를 할당받은 변수(식별자)를 호출하는 것이기 때문이다.
// 기명 함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석된다.
// 함수 선언문에서는 함수 이름을 생략할 수 없다.
function foo() {
console.log("foo");
}
foo(); // foo
// 함수 리터럴을 피연산자로 사용하면 함수 선언문이 아니라 함수 리터럴 표현식으로 해석된다.
// 함수 리터럴에서는 함수 이름을 생략할 수 있다.
(function bar() {
console.log("bar");
});
bar(); // ReferenceError: bar is not defined
하지만 함수 선언문도 함수 이름만 있고 함수를 참조하는 식별자가 없는데 어떻게 실행시키는 것일까?
정답은 자바스크립트 엔진이 함수를 함수 선언문이라고 해석하고 메모리에 객체를 생성하는 순간에, 나중에 함수 선언문을 사용해야함으로 함수 이름과 같은 식별자를 암묵적으로 생성하고, 거기에 함수 객체를 할당하기 때문이다.
function add(x, y) {
return x + y;
}
// 자바스크립트 엔진이 진행하는 의사코드
// var add = function add(x, y) {
// return x + y;
// };
console.log(add(2, 5)); // 7
2) 함수 표현식
함수(함수리터럴)은 객체이지만 값의 성질을 갖는 일급객체이며, 값의 성질을 갖는 다는 것은 자유롭게 여기저기서 사용할 수 있다는 것이다. 따라서 함수(리터럴)를 변수에 할당할 수 있는데, 이것을 함수 표현식이라고 한다.
// 함수 표현식
var add = function (x, y) {
return x + y;
};
console.log(add(2, 5)); // 7
함수 표현식의 함수는 함수 리터럴이므로 함수 이름을 쓸수도, 생략할 수도 있다. 함수 이름으로 함수를 호출하는 것은 어차피 함수 몸체(내부)에서만 가능함으로 사실상 생략하는 것이 일반적이다. (함수 내부에서 자기 자신인 함수를 다시 호출하면 돌고도는 무한루프에…..)
// 기명 함수 표현식
var add = function foo(x, y) {
return x + y;
};
// 함수 객체를 가리키는 식별자로 호출
console.log(add(2, 5)); // 7
// 함수 외부에서 함수 이름으로 호출하면 ReferenceError가 발생한다.
console.log(foo(2, 5)); // ReferenceError: foo is not defined
5. 함수의 생성 시점과 함수 호이스팅
함수선언문과 함수 표현식을 바꿔 사용하다면 두 방법의 동작 차이가 발생하는데, 이것은 호이스팅으로 인한 함수 생성시점의 차이로 발생하는 것이다.
// 함수 참조
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;
};
위 예제에서 보면, 함수 선언문 add는 정의 되기전에 참조와 호출이 가능했지만 함수 표현식 sub는 정의되기 전에 참조와 호출을 할 경우 에러를 발생시킨다.
이유는 자바스크립트의 호이스팅 이 적용되어 변수 선언과 함수 선언문은 자바스크립트 런타임 이전에 컨텍스트 실행 환경의 최상단으로 끌어올려지고 함수 표현식의 할당문만 제자리에 남아있게 된 뒤, 자바스크립트 런타임이 진행되기 되기때문이다.
// 호이스팅 상태 의사코드
function add(x, y) {
return x + y;
}
var sub;
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
//이때 변수 sub는 함수객체가 할당되지 않았기 때문에 함수 호출을 할수 없다.
sub = function (x, y) {
return x - y;
};
따라서, 의사코드가 아닌 실제 코드 기준에서는 함수가 정의 되기 전에 함수를 사용한 것이나 마찬가지므로, 함수 선언문과 함수표현식 중에 함수 표현식을 사용하길 더 권장한다. (함수 리터럴 개념이랑 헷갈리기도 하고…)
6. 화살표 함수
ES6에 도입된 새로운 함수 표현 방법이다. function
키워드 대신 화살표 =>
를 사용해 함수를 선언할 수 있다. 화살표 함수는 항상 익명 함수로 정의한다.
// 화살표 함수
const add = (x, y) => x + y;
console.log(add(2, 5)); // 7
화살표 홤수가 기존 함수와 다른 점은 그저 생긴 모양만 다른 것이 아니라, 내부 기능이나 특징도 차이가 있는데 다른 포스트에서 자세히 살펴보도록 하겠다.