오늘은 함수에 대해 알아볼 것이다.
함수 양이 많다..
그만큼 중요한 것.
양이 많아서 쓰기 싫다.
함수
자.. 함수란 무엇인가
우리는 함수를 이미 중학교? 초등학교 때부터 배웠다.
그때 함수를 코드로 쓰는 것이다.
대신 단순한 x,y가 아니라
x,y로 요리를 하는 것으로 바뀜.
먼저 함수에 대해 정의해보자.
함수란
일련의 과정을 문으로구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의
라고 할 수 있다.
말이 너무 어렵지?
우선 함수의 모양을 보자
1
2
3
function add(x, y) {
return x+y
}
가장 일반적인 함수의 모양이다.
여기서 x,y를 매개변수라고 한다.
x,y에 실제로 들어가는 2,5 같은 숫자를 인자라고 한다.
그리고 return에 해당하는 x+y를 반환값이라고 한다.
함수의 보양은 보통 이렇게 정해져있다.
여기서 매개변수는 여러 개를 할 수 있고,
다른 곳에서 사용되는 식별자를 사용할 수도 있다.
이렇게 하나의 함수를 만드는 것을 함수 정의 라고 한다.
함수를 만들면 실행도 따로 시켜줘야한다.
함수 실행을 다른 말로 함수 호출이라고 한다.
또한, 함수는 객체 타입의 값이다.
하지만 일반 객체와는 다르게 호출이 가능하다.
함수가 객체라는 사실은 나중에 한 번 더 나올 예정이다.
잘 기억해두자!
함수를 사용하는 이유
그럼 이러한 함수를 왜 사용하는 것일까?
가장 중요한 것은 코드의 재사용이다.
우리가 로직을 짜다보면 한 번만 사용하는 것이 아니라,
반복적, 지속적으로 사용하게 된다.
함수를 정의해야 코드의 유지보수의 편의성을 높일 수 있고
실수를 줄일 수 있다.
그렇다고 해서 한 함수에 모든 내용을 담으면 안 된다.
이상적인 함수는 한 가지 일만 하고,
가급적 작게 만드는 것이 중요하다.
함수 표현식
위에서도 얘기했지만 함수는 객체 타입의 값이다.
그래서 함수는 변수에 할당 할 수 있고, 프로퍼티의 값이 될 수 있으며
배열에도 들어갈 수 있다.
이런 성질을 갖는 객체를 일급 객체라고 한다.
함수는 일급 객체이다.
요것은 함수를 값처럼 자유롭게 사용할 수 있다는 것이다.
우리가 함수를 선언하게 되면
자바스크립트 엔진은 함수의 이름으로 식별자를 암묵적으로 생성하고,
그곳에 함수 객체를 할당하게 된다.
하지만 함수 선언문과 표현식을 서로 다르다.
어떤 차이가 있는지 보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
console.dir(add) // f add
console.dir(sub) // undefined
console.log(add(2,5)) // 7
console.log(sub(7,2)) // 오류
function add(x, y) {
return x+y
}
const sub = function (x,y) {
return x-y
}
위에 보면 선언문과 표현식을 만들기 전에 위에서 호출했다.
그랬을 때 선언문은 실행 결과가 나오지만
표현식은 그렇지 않다.
그 이유는 서로의 생성 시점이 다르기 때문이다.
이전에 변수에서도 배웠지만 코드가 한 줄씩 순차적으로 실행되는 런타임 전에
자바스크립트 엔진에 의해 모든 선언문이 먼저 실행된다.
함수 선언문으로 정의할 경우 런타임 이전에 실행이되고 생성되는 것이다.
이런 과정을 우리는 호이스팅이라고 배운 적이 있다.
함수 표현식도 물론 런타임 이전에 평가가 되지만
함수 호이스팅이 아니라 번수 호이스팅에 들어가게 된다.
그래서 먼저 sub라는 변수를 undefined라고 먼저 할당을 해서 console.dir에 뜨는 것이다.
그 이후 할당문이 실행되는 시점에 함수 객체가 된다.
다시 정리하면,
표현식은 표현식 이전에 함수를 참조하면 변수 호이스팅에 의해 먼저 메모리 공간을 undefined로 만들어 둔다.
이때 호출하면 에러가 뜨게 되고, 표현식 이후에는 함수 객체가 할당!
함수 호이스팅이 좋아보이지만
코드 가독성이 매우 안 좋다.
그래서 자바스크립트에서는 함수 표현식을 권장하고 있다.
함수 호출
함수 호출 시 매개변수에 대해 조금 알아보자.
매개변수는 함수를 정의할 때 만들게 되며, 개수 제한은 없다.
선언할 때 변수와 동일하게 취급된다.
함수는 매개변수는 인수와 일치하지 않아도 된다.
함수가 체크하지 않기 떄문이다.
전달되지 않은 매개변수는 undefined 값으로 함수를 실행하고
초과되는 인수는 arguments 객체의 프로퍼티로 보관된다.
arguments에 대한 내용은 이후에 또 배울 것이다.
또한 자바스크립트는 동적 타입 언어라서
매개변수의 타입을 사전에 정의할 수 없다.
정의하고 싶은 경우 typescript를 이용하자.
그래서 타입으로 인한 오류를 방지하기 위해
ES6에서는 매개변수의 기본값을 사용할 수 있도록 한다.
매개변수에 인수를 전달하지 않을 때 기본값을 사용한다.
함수에서 값의 변경
우리는 함수에 인수를 전달하고,
그 값을 변경시키는 일을 많이한다.
그럼 실제로 함수 안에서는 어떤 방식으로 값이 변경되는 것일까?
우선 2가지로 나눌 수 있다.
원시 타입의 값과 객체 타입의 값.
아래 예시를 보자.
1
2
3
4
5
6
7
8
9
10
11
12
let num = 100;
let person = {name : "LEE"}
function change(primitive, obj){
primitive +=100;
obj.name = "KIM"
}
change(num, person)
console.log(num) // 100
console.log(person) // { name: "KIM" }
위에서 보면 원시타입의 값은 변경 불가하기 때문에
값이 복사되어 전달되기 때문에 원본에 영향이 없다.
하지만 객체 타입의 값은 변경이 가능하기에
참조 값이 전달되어 원본이 바뀌게 된다.