
#자바스크립트함수 #함수리터럴 #함수선언문 #기명함수리터럴 #익명함수리터럴 #함수표현식 #일급객체 #함수호이스팅 #화살표함수
#즉시실행함수 #재귀함수 #중첩함수 #콜백함수 #순수함수 #비순수함수
함수
함수는 일련의 과정을 문(State)로 구현하고 코드블록으로 감싸서 하나의 실행단위로 정의한 것.
- 외부로부터 입력을 전달받는 변수를 매개변수, 입력을 인수, 출력을 반환값 이라고 한다.
- 함수는 함수정의 를 통해 생성한다.
- 함수는 여러번 사용할 수 있으므로 코드의 재사용성면에서 유리하다.
함수리터럴
자바스크립트 함수는 객체 타입의 값이다.
따라서 함수도 함수리터럴로 생성할 수 있다.
- 함수 리터럴은 function 키워드, 함수 이름, 매개 변수 목록, 함수 몸체로 구성된다.
- 함수 리터럴은 평가되어 객체를 반환한다. 즉 함수는 객체이다.
- 함수 이름은 함수 몸체내부에서만 참조할 수 있는 식별자이다.
- 함수 이름은 생략할 수 있다. 함수 이름 유무에 따라 기명함수리터럴, 익명함수리터럴 로 나뉜다.
- 함수는 객체이지만 일반 객체와 다른 호출할 수 있는 객체이다.
var f = function add(x, y) {
return x + y;
};
함수 정의
함수를 호출하기 이전에 인수를 전달받을 매개변수와 반환값을 정의하는 것
정의된 함수는 자바스크립트 엔진에 의해 함수객체가 된다.
// 함수를 정의하는 방법
// 함수 선언문
function add(x, y) {
return x + y;
}
// 함수 표현식
var add = function (x, y) {
return x + y;
};
// Function 생성자 함수
var add = new Function("x", "y", "return x + y");
// 화살표 함수
var add = (x, y) => x + y;
함수선언문
함수객체를 생성하고 암묵적으로 생성한 변수에 할당한다.
- 함수선언문은 함수리터럴과 형태가 동일하다.
- 함수리터럴은 함수명을 생략할 수 있지만 함수선언문은 함수이름을 생략할 수 없다.
- 함수선언문은 표현식이 아닌 값으로 평가되지 않는 문이다.
// 함수 선언문
function add(x, y) {
return x + y;
}
add; // f add(x, y)
add(2, 5); // 7
함수선언문은 기명함수리터럴과 형태가 동일하다.
즉, 기명함수 리터럴은 자바스크립트 엔진에 의해 문맥에 따라 해석이 달라질 여지가 있다.
- 자바스크립트 엔진은 기명함수 리터럴을 단독으로 사용하는 경우 함수선언문으로 해석한다
- 함수리터럴이 값으로 평가되어야할 경우(변수에 할당, 피연산자로 활용) 함수리터럴로 해석한다.
- 함수 선언문으로 해석되면 자바스크립트 엔진은 생성된 함수를 호출하기 위해 함수이름과 동일한변수를 암묵적으로 생성하고 할당한다.
- 함수는 함수이름으로 호출하는것이 아닌 함수객체가 할당된 식별자로 호출한다.
// 함수 선언문은 표현식이 아닌 문이므로 변수에 할당할 수 없다.
// 하지만 변수에 할당되는 것 처럼 보인다.
var add = function add(x, y) {
return x + y;
};
// 기명함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석한다.
// 이름 생략이 불가능하다
// 함수 선언문으로 해석되면 자바스크립트 엔진은 생성된 함수를 호출하기 위해 함수이름과 동일한 변수를 암묵적으로 생성하고 할당한다.
function foo() {
console.log("foo");
}
// 결국 다음과 같이 동작한다.
// 엔진이 함수선언문을 함수 표현식으로 변환해 함수 객체를 생성한다고 볼 수 있지만 정확히 동일하게 동작하지는 않는다.
var foo = function foo() {
console.log("foo");
};
// 그룹연산자의 피연산자로 사용하면 함수 리터럴로 해석한다.
// 함수리터럴의 함수명은 함수 몸체 내부에서만 참조가능하다.
// 기명함수 리터럴
(function bar() {}); // [Function:bar]
// 익명함수 리터럴
(function () {
console.log(this);
});
함수표현식
자바스크립트의 함수는 객체타입의 값이다.
- 값의 성질을 갖는 객체를 일급객체라고 한다.
- 함수는 일급객체이므로 함수 리터럴로 생성한 함수객체를 변수에 할당할 수 있다. 이러한 함수 생성방식을 함수표현식이라고 한다.
- 함수를 호출할때는 함수이름이 아닌 함수식별자로 호출한다.
- 함수 이름은 항상 함수몸체내부에서만 유효하다.
- 함수 선언문과 함수 표현식은 결과적으로 동일하게 동작하는 것 같지만 정확히 동일하게 동작하진 않는다.
// 함수는 일급객체이므로 함수 리터럴로 생성한 함수 객체를 변수에 할당할 수 있다. 이러한 함수 생성방식을 함수 표현식이라고 한다.
var add = function innerAdd() {
// 함수 이름은 항상 함수몸체 내부에서만 유효하다.
console.log(innerAdd === add);
};
// 함수를 호출할때는 함수이름이 아닌 함수 식별자로 호출한다.
add(); // true;
console.log(add); //[Function: innerAdd]
innerAdd(); //innerAdd is not defined
함수생성시점과 함수호이스팅
함수선언문으로 생성된 함수와 함수표현식으로 생성된 함수의 생성시점이 다르다.
함수선언문으로 생성된 함수는 선언문 이전에 호출 할 수 있다.
함수의 호이스팅
- 함수 선언문은 런타임 이전에 엔진에 의해 함수객체가 먼저 생성된다.
- 엔진은 함수 이름과 동일한 이름의 식별자를 생성하고 함수객체를 할당한다.
- 런타임 이전에 이미 함수의 생성과 할당이 완료된다. 따라서 호출할 수 있다.
- 함수호이스팅은 런타임 이전에 함수가 함수객체로 초기화되어 호출이 가능한 것을 말한다.
- 함수 표현식으로 생성된 함수는 선언문이전에 호출 할 수 없다.
변수의 호이스팅
- 변수의 호이스팅은 런타임 이전에 변수가 undefined로 초기화 되는것을 말한다.
- 함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 것을 함수의 호이스팅이라 한다
- 함수 표현식은 변수의 호이스팅과 동일하게 런타임이전에 변수가 undefined로 초기화 되고 런타임에 함수리터럴로 평가된 함수객체가 할당된다.
- 이런 이유로 함수표현식을 사용할 것이 권장된다.
add; // f add(x,y)
sub; // undefined
add(2, 5); // 7
sub(2, 5); // sub is not a function
function add(x, y) {
return x + y;
}
var sub = function (x, y) {
return x + y;
};
Function 생성자 함수
생성자 함수에 매개변수 목록과 함수 몸체를 문자열로 전달하면서 new 연산자와 함께 호출하면 함수 객체를 생성해서 반환한다.
var add = new Function("x", "y", "return x + y");
// 스코프가 정상으로 동작한다
var add1 = (function () {
var a = 10;
return function (x, y) {
return x + y + a;
};
})();
add1(1, 2); // 13
// 스코프가 정상적으로 동작하지 않는다.
var add2 = (function () {
var a = 10;
return new Function("x", "y", "return x + y");
})();
add2(1, 2); // a is not defined
화살표함수
화살표함수는 항상 익명으로 정의한다.
화살표함수는 표기법뿐아니라 내부 동작 또한 간략화 되어있다.
- 화살표 함수는 생성자 함수로 사용할 수 없다.
- 기존 함수와 this 바인딩 방식이 다르다.
- prototype 이 없다.
- arguments를 생성하지 않는다.
const add = (x, y) => x + y;
add(2, 5); //7
함수호출
함수를 호출하면 현재의 실행 흐름을 중단하고 호출된 함수로 실행 흐름을 옮긴다. 이때 매개변수에 인수가 할당되고 함수의 몸체의 문들이 실행된다.
- 함수의 매개변수는 함수 내에서만 참조할 수 있다. 즉 함수의 매개변수의 스코프는 함수내부이다.
- 함수는 매개변수의 개수와 인수의 개수가 일치하는지 체크하지않는다. 인수가 부족하다면 매개변수에 할당되는 값은 undefined 이다.
- 함수에 전달된 인수는 arguments 객체의 프로퍼티에 보관된다.
function add(x, y) {
console.log(arguments); // Arguments(2) [2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
return x + y;
}
add(2, 3);
인수 확인
다음과 같은 한계점으로 인수의 확인 절차가 필요하다
- 함수는 매개변수의 개수와 인수의 개수가 일치하는지 체크하지않는다.
- 자바스크립트는 동적 언어이기 때문에 매개변수의 타입을 사전에 지정할수 없다.
// 이 코드를 통해 런타임에서 오류를 발생시킬수는 있지만 부적절한 호출을 사전에 방지할 순 없다.
// 타입스크립트와 같은 확장을 도입해 컴파일 시점에 부적절한 호출을 방지할 수 있다.
function add(x, y) {
if (typeof x !== "number" || typeof y !== "number") {
throw new TypeError("인수는 모두 숫자값이어야 합니다.");
}
return x + y;
}
// 인수가 전달되지않는 경우를 대비해 단축평가를 통해 매개변수의 기본값을 할당하는 방법도 있다.
function add(a, b, c) {
a = a || 0;
b = b || 0;
c = c || 0;
return a + b + c;
}
//es6에서 제공하는 매개변수 기본값을 사용할수 도 있다.
// 인수가 전달되지않거나 undefined 인 경우 기본값을 할당한다.
function add(a = 0, b = 0, c = 0) {}
매개변수의 최대 개수
이상적인 함수의 매개변수는 0개이며 함수는 가능한 한가지일만을 처리해야하기 때문에 가급적 작게 만들어야한다.
반환문(return)
return 키워드를 활용해 실행 결과를 함수외부로 반환할 수 있다.
함수의호출은 표현식이다. 함수호출표현식은 return 키워드가 반환한 표현식의 평가결과로 평가한다.
- 반환문은 함수 실행을 종료하고 함수를 빠져나가는 역할을 한다.
- 반환문은 return 키워드 뒤의 값을 평가한다. 명시적으로 지정하지않으면 undefined를 반환한다.
참조에 의한 전달과 외부 상태의 변경
함수의 매개변수는 함수 몸체 내부에서 변수와 동일하게 취급되므로 값에 의한 전달과 참조에 의한 전달 방식을 따른다.
함수 외부에서 함수 내부로 전달한 참조값에 의해 원본객체가 변경되는 부수효과가 발생한다.
function changeVal(primitive, obj) {
primitive += 100;
obj.name = "kim";
}
var num = 100;
var person = { name: "Lee" };
num; // 100;
person.name; // Lee
changeVal(num, person);
// 원시타입인 primative는 변경불가능한 값이므로 재할당을 통해 할당된 원시 값을 새로운 원시 값으로 교체했다.
// 객체 타입인 obj는 변경가능한 값이므로 전달받은 객체의 속성을 직접 변경한다
// 함수 외부에서 함수 내부로 전달한 참조값에 의해 원본 객체가 변경되는 부수효과가 발생한다.
num; //100;
person.name; // kim
다양한 함수의 형태
즉시실행함수
함수 정의와 동시에 즉시 호출되는 함수를 즉시 실행 함수라고 한다.
즉시 실행함수는 한번만 호출되며 다시 호출할 수 없다.
//즉시 실행 함수 익명 함수로 정의하는것이 일반적이다.
(function () {
a = 3;
b = 5;
return a + b;
})(); // 8
// 기명함수로 정의하더라도 그룹연산자 () 내부의 함수 선언은 함수 선언문이 아닌
함수 리터럴로 평가되기 때문에 함수이름을 외부에서 사용할 수 없다.
(function foo() {
a = 3;
b = 5;
return a + b;
})(); // 8
foo(); // foo is not defined
- 즉시 실행함수는 반드시 그룹함수()로 감싸야한다.
// 값으로 쓰이고 있지않기 때문에 앤진은 함수선언문으로 해석한다.
// 함수선언문은 함수 이름을 생략할 수 없다.
function () {
...
} () // Function statement require a function name
// 앤진은 함수선언문끝에 자동으로 세미콜론을 붙인다.
// 결과적으로 function foo(){};() 과 같은 형태가 된다.
// ()는 그룹연산자로 평가되고 그룹연산자에 대한 피연산자가 없으므로 에러가 발생한다.
function foo(){
}() // unexpected token ')'
// 그룹연산자의 피연산자는 값으로 평가되므로 함수리터럴로 평가되어 함수객체를 반환한다
typeof (function f(){}) // function
typeof (function (){}) // function
//즉시실행함수도 값을 반환하고 인수를 전달할 수 있다.
var res = (function(){
var a = 5;
var b = 3;
return a + b;
})();//8
res = (function(a,b){
return a + b
})(3,5);//8
재귀함수
함수 자기자신을 호출하는 함수를 재귀함수라고 한다.
- 재귀함수 내에서 자기자신을 호출할때 사용한 식별자는 함수 이름이다.
function countDown(n) {
if (n < 0) return;
console.log(n);
countDown(n - 1);
}
- 함수 내부에서는 함수이름과 외부 식별자 모두 자기자신을 의미한다
var countDown = function foo(n) {
if (n < 0) return;
console.log(n);
countDown(n - 1);
};
countDown(10);
중첩함수
함수 내부에 정의 된 함수를 중첩함수 또는 내부 함수라고 한다.
- 중첩함수를 포함한 함수는 외부함수라고 한다.
- 중첩함수는 외부함수 내에서만 호출할 수 있다.
- 일반적으로 중첩함수는 외부함수를 돕는 헬퍼함수 역할을 한다.
function outer() {
var x = 1;
function inner() {
var y = 2;
x + y; // 3
}
inner();
}
outer();
콜백함수
함수의 변하지않는 공통 로직은 미리 정해두고 경우에 따라 변경되는 로직은 추상화해서 함수 외부에서 전달할 수 있다.
- 자바스크립트의 함수는 값으로 사용할 수 있는 일급 객체이므로 매개변수를 통해 함수내부로 전달할 수 있다.
- 함수 외부에서 매개변수를 통해 함수의 내부로 전달되는 함수를 콜백함수라고 한다.
- 매개변수를 통해 함수 외부에서 내부로 함수를 전달 받은 함수를 고차함수라고 한다.
- 고차 함수는 콜백함수를 자신의 일부로 합성한다.
- 고차 함수는 전달받은 콜백 함수의 호출시점을 결정해서 호출한다. 이때 고차함수는 필요에 따라 콜백함수에 인수를 전달할 수 있다.
function repeat(n, f){
for(var i = 0; i < n ; i ++){
f(i)
}
}
var logOdds = function (i) {
...
};
repeat(5, logOdds)
순수함수 비순수함수
어떤 외부상태에도 의존하지않고 변경하지도 않는 부수효과가 없는 함수를 순수함수라고 한다.
- 함수 내부에서 함수외부의 상태를 직접 참조하지않더라도 객체타입을 인수를 매개변수로 전달받는다면 비순수함수가 된다.
- 함수형 프로그래밍은 순수함수와 보조함수의 조합을 통해 외부상태를 변경하는 부수효과를 최소화해서 불변성을 지향하는 패러다임이다.
#자바스크립트함수 #함수리터럴 #함수선언문 #기명함수리터럴 #함수표현식 #일급객체 #함수호이스팅 #화살표함수
#즉시실행함수 #재귀함수 #중첩함수 #콜백함수 #순수함수 #비순수함수
'프로그래밍 > 자바스크립트 ES6' 카테고리의 다른 글
| 자바스크립트 ES6 #14 전역 변수의 문제점 (0) | 2023.09.18 |
|---|---|
| 자바스크립트 ES6 #13 스코프 (0) | 2023.09.16 |
| 자바스크립트 ES6 #11 원시 값과 객체의 비교 (0) | 2023.09.14 |
| 자바스크립트 ES6 #10 객체리터럴 (0) | 2023.09.14 |
| 자바스크립트 ES6 #9 타입변환과 단축평가 (0) | 2023.09.12 |