[JavaScript] 20221101 function

wrld_worthy·2022년 11월 3일

JavaScript

목록 보기
8/21

1. 함수

-수학적인 개념에서 나온 프로그래밍 개념이다.
-수학의 함수와는 좀 다른 성질을 띈다. ( 무조건 공역(input), 정의역(output)이 존재하는게 아님. )

(1) 사용하는 이유

  • 코드를 재사용 할 수 있다.
    (함수를 구현해 놓고 여러번 사용함)

  • 중복 코드를 피함 -> 코드 간결화 -> 가독성이 좋아짐

특징

-함수는 값이다.
JavaScript 함수는 객체이기 때문에 변수에 할당할 수 있고, 함수의 매개변수로 넘겨줄 수 있다. 이 덕분에 우리는 JS 콜백(CallBack) 패턴을 쉽게 구현할 수 있다.

Hoisting : 끌어올림
function 선언문 으로 선언한 함수는 함수 이름이 hoisting 되어 한 파일안 어느위치에서든 접근 가능하다. 우선순위 최상단으로 올라가기 때문에 가능한 것이다. 그러나 익명함수, 즉 표현식으로 선언된 함수는 호이스팅이 되지 않는다.

Scope 와 Closure
JavaScript 는 함수 스코프를 따른다. ES6에서는 let, const 로 block scope를 만들 수 있지만, 원래 JavaScript는 함수를 기준으로 그 범위가 나뉜다. 이러한 특징때문에 클로저(closure: 함수가 선언되었을 때의 환경을 저장하는 상태)가 생긴다

(2) 함수의 선언과 호출

  • 선언(매개변수: parameter)

  • 호출(전달인자: argument)


함수 선언

  • 함수 선언은 함수 표현식대로 나뉘는데
function 함수명(매개변수) {
	code
}

function 함수명(매개변수) {
 	code
    return 반환값
}

함수 호출

  • 함수는 선언할때 매개변수를 사용하여 값을 받아 올 수 있었다. 여기에 할당하는 값을 인자라고 한다.
function()
function(value)
  1. Hoisting
    • 자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 최상단에 선언한다.

이런 현상이 이러나는 이유는 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 생략가능
}

특징:

// 단점으로는 가독성이 좀 떨어질 수가 있다.

return

  • 함수 안에서 쓰인다.
  • return을 만나면 함수가 종료된다.
  • Default값이다. 함수 마지막에 생략되어 있다.

즉시 실행 함수

(function(){
})();
or
;(function(){
})()
// 화살표 함수로도 가능함
;(() => {
})();
// 주의
/* console.log()같은 구문을 전에 사용했다면 ()가 겹쳐서 
컴퓨터가 인식하는데 실패할 수 있다. 세미콜론(;)을 평소에 문장 마지막에
붙이는 스타일이 아니라면 앞에 붙여주고 실행하자.
*/
  • 즉시실행 함수에도 이름을 붙여 즉시실행 함수로 사용 할 수 있다. 하지만 즉시실행 함수는 선언과 동시에 호출되어 반환되기 때문에 재사용 할 수 없어서 이름을 짓는게 의미가 없다. ( 하지만 쓸일이 있다면 함수의 설명?이나 의미를 위해 이름을 지어서 가독성을 올리는 정도는 괜찮은 것 같다. )

필요없는 전역 변수의 생성을 줄일 수 있다.
함수를 생성하면 그 함수는 전역 변수로써 남아있게 되고, 많은 변수의 생성은 전역 스코프를 오염시킬 수 있다.

즉시 함수 왜 사용하는가?

  1. 즉시실행함수를 선언하면 내부 변수가 전역으로 저장되지 않기 때문에 전역 스코프의 오염을 줄일 수 있다.

  2. private한 변수를 만들 수 있다.
    즉시실행함수는 외부에서 접근 할 수 없는 자체적인 스코프를 가지게된다. 이는 클로저의 사용 목적과도 비슷하며 내부 변수를 외부로부터 private하게 보호 할 수 있다는 장점이 있다.


Callback 함수

간단하게 정의해보면
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

0개의 댓글