-수학적인 개념에서 나온 프로그래밍 개념이다.
-수학의 함수와는 좀 다른 성질을 띈다. ( 무조건 공역(input), 정의역(output)이 존재하는게 아님. )
코드를 재사용 할 수 있다.
(함수를 구현해 놓고 여러번 사용함)
중복 코드를 피함 -> 코드 간결화 -> 가독성이 좋아짐
-함수는 값이다.
JavaScript 함수는 객체이기 때문에 변수에 할당할 수 있고, 함수의 매개변수로 넘겨줄 수 있다. 이 덕분에 우리는 JS 콜백(CallBack) 패턴을 쉽게 구현할 수 있다.
Hoisting : 끌어올림
function 선언문 으로 선언한 함수는 함수 이름이 hoisting 되어 한 파일안 어느위치에서든 접근 가능하다. 우선순위 최상단으로 올라가기 때문에 가능한 것이다. 그러나 익명함수, 즉 표현식으로 선언된 함수는 호이스팅이 되지 않는다.
Scope 와 Closure
JavaScript 는 함수 스코프를 따른다. ES6에서는 let, const 로 block scope를 만들 수 있지만, 원래 JavaScript는 함수를 기준으로 그 범위가 나뉜다. 이러한 특징때문에 클로저(closure: 함수가 선언되었을 때의 환경을 저장하는 상태)가 생긴다
선언(매개변수: parameter)
호출(전달인자: argument)
function 함수명(매개변수) {
code
}
function 함수명(매개변수) {
code
return 반환값
}
function()
function(value)
이런 현상이 이러나는 이유는 JavaScript의 코드실행을 먼저 설명해야한다. JavaScript는 코드를 실행하기 전에 익명함수가 전체적으로 Parsing을 하는데 코드를 한번 검사 한 후에 인터프리터 형식으로 한 문장씩 코드를 실행하게 되는데 이때 함수나 변수가 우선 처리되어야 한다고 판단되는 것들을 아래에서 끌어 올려 최상단에 선언하게 만들기 때문이다.
예시코드console.log(testfunc()) console.log(testvalue) function testfunc() { console.log("testfunc print success") } var testvalue = "testvalue var" /*=> 결과 testfunc print success undefined */
함수 같은 경우에는 함수가 가지고 있는 구조( 변수, 내부 함수 등) 모두
끌어 올려서 선언하게 되는데 변수는 변수 값까지 호이스팅이 일어나지 않고 변수선언까만 일어난다.
코드를 짜는데 있어서 호이스팅이 일어나는 것은 바람직한 코드가 아니고 호이스팅이 일어나지 않도록 코딩을 해야한다. 이런 함수의 단점을 보완하기 위해 나온 함수 표현식이 존재한다.
const f = function() { code } const f => () { // return 생략가능 }
특징:
호이스팅이 일어나지 않는다.
( const가 아닌 var로 선언하면 f변수명이 최상단에서 우선 선언이 되고 함수 값이 들어가지 않기 때문에 f()로 호출을 해보면 f는 함수로 인식되지 않아 오류가 발생한다. )
// 단점으로는 가독성이 좀 떨어질 수가 있다.
(function(){ })(); or ;(function(){ })() // 화살표 함수로도 가능함 ;(() => { })(); // 주의 /* console.log()같은 구문을 전에 사용했다면 ()가 겹쳐서 컴퓨터가 인식하는데 실패할 수 있다. 세미콜론(;)을 평소에 문장 마지막에 붙이는 스타일이 아니라면 앞에 붙여주고 실행하자. */
필요없는 전역 변수의 생성을 줄일 수 있다.
함수를 생성하면 그 함수는 전역 변수로써 남아있게 되고, 많은 변수의 생성은 전역 스코프를 오염시킬 수 있다.
즉시 함수 왜 사용하는가?
즉시실행함수를 선언하면 내부 변수가 전역으로 저장되지 않기 때문에 전역 스코프의 오염을 줄일 수 있다.
private한 변수를 만들 수 있다.
즉시실행함수는 외부에서 접근 할 수 없는 자체적인 스코프를 가지게된다. 이는 클로저의 사용 목적과도 비슷하며 내부 변수를 외부로부터 private하게 보호 할 수 있다는 장점이 있다.
간단하게 정의해보면
1. 다른 함수의 인자로써 사용되는 함수.
2. 특정 이벤트가 끝나고 호출되는 함수.
정도로 할 수 있을 것 같다.
예시1
const hello = function(callback) {
console.log(callback)
console.log(callback())
}
const print = function() {
return 10
}
hello(hello(print))
/* 결과
const print = function() {
return 10
}
10
*/
위 코드에서 callback 함수는 hello함수의 매개변수로써 사용되고 print함수의 함수 자체 값을 인자로 받는다. ( hello(print) 이 부분에서는 print함수가 실행되지 않고 callback매개변수에 함수 자체값을 인자로 준다.) callback과 callback()을 출력해보면 callback은 인자로 받은 print함수 값이 그대로 들어와 있고 callback()은 함수를 호출하여 return값이 출력이 되는 것을 볼 수 있다.
예시2
const hello = function(callback) {
let helloName = 'javascript'
console.log(callback)
console.log(callback(helloName))
}
const print = function(name) {
return 10+name
}
console.log(hello(print))
/* 결과
const print = function(name) {
return 10+name
}
10javascript
*/
print함수에 매개변수를 설정하여 callback함수에 인자로써 준다면 hello함수 안에 변수를 callback함수의 인자로 사용할 수 있다.
callback함수 예제
function goak(callback) { const fn = function () { console.log('1') return 30 } const result = 1 + callback(fn) }// goak() function getNumber(callback){ console.log('3') return 2 * callback() }//getNumber() console.log(goak(getNumber)) console.log( getNumber(()=>60))goak함수에 getNumber 함수 값을 인자로 넣으면 getNumber가 호출이 되는게 아닌 goak(callback) 함수가 호출이 된다. goak(callback)함수의 매개변수인 callback함수는 getNumber 함수를 인자로 받게 되고 goak함수 내에서 fn()을 인자로 받는 함수가 된다. 가 다음에 goak함수블럭의 const result = 1+ callback(fn)이 실행 되는데 1+callback(fn)의 연산이 끝난 후 result변수에 대입하는 연산이 실행되기 때문에 callback(fn)이 먼저 호출된다. callback(fn)은 getNumber 함수 값을 인자로 받은 callback함수이기 때문에 getNumber의 구조를 가지고 있고 실행이 되면 console.log('3')이 실행되어 3이 출력되고 2 callback()을 반환한다. 여기서 callback()은 fn을 인자로 받아 호출되고 fn은 1을 출력하고 30을 반환하는 함수이다. 따라서 Fn()을 호출하여 연산하면 1이 출력되고 230이 되어 60을 반환한다.
goak()함수의 callback(fn)은 60의 값을 가지게 되고 result는 61의 값을 할당 받는다. 하지만 goak() 함수는 반환값이 없어 이대로 종료가 된다.
console.log(goak(getNumber))는 undefined가 출력된다.
그 다음 console.log( getNumber(()=>60))은 getNumber() 함수에 ()=>60인 Arrow함수 표기법으로 60의 값을 반환하는 함수라는 뜻이다.
따라서 함수가 실행되면서 60의 값을 반환하는 함수 값을 callback함수에 인자로 주고 getNumber 함수가 실행된다. 먼저 console.log('3')이 실행되면서 3이 출력되고 return 2 callback() 이 실행되면서 callback()은 60을 반환하고 종료되고 260을 반환하면서 getnumber함수도 종료된다. console.log(getNumber(()=>60))은 120의 값을 출력하게된다.
결과
3
1
undefined
3
120