[JavaScript (6)] Javascript 함수(함수 기본, 재귀함수, 호이스팅 등)
- -
[JavaScript (6)] Javascript 함수(함수 기본, 재귀함수, 호이스팅 등)
안녕하세요. 갓대희 입니다. 이번 포스팅은 [ 자바스크립트 함수 ] 입니다. : )
0. 들어가기 앞서
함수의 정의, 호출방법, 그리고 활용 방법 등을 간단히 알아보려 한다.
1. 함수(function) 기본
▶ 1. 함수(function)란?
- 특별한 목적의 작업을 수행하도록 설계된 독립적인 블록
- javascript에서 코드 집합을 나타내는 자료형)
- 작업을 수행하거나 값을 계산하는 문장 집합 같은 자바스크립트 절차
- 함수도 일반 객체처럼 값으로 취급된다. 즉 하나의 데이터 타입 이다.
이러한 특징때문에 자바스크립트의 함수는 일급 객체라고 하며, 변수에도 할당 가능하다.
※ 참고할 용어
◎ 일급시민(First-Class Citizen) : 다음을 충족하는 값
1) 변수(variable)에 담을 수 있다.
2) 함수의 인자(parameter)로 전달할 수 있다.
3) 함수의 반환값(return value)으로 전달할 수 있다.
◎ 일급객체(First-Class-Object) : 일급시민의 조건을 충족하는 객체
◎ 일급함수(First-Class-Function) : 일급시민의 조건을 충족하는 함수
▶ 2. 함수의 구성
1) 함수명
- 함수명은 함수 내부 코드에서 자신을 재귀적으로 호출하거나 자바스크립트 디버거가 해당 함수를 구분하는 식별자로 사용 한다.
- 다만 함수명은 선택사항. 이때 함수명이 없는 함수를 익명 함수라 한다.
2) 매개변수(parameter)
- 함수의 정의에서 전달받은 인수를 함수 내부로 전달하기 위해 사용하는 변수.
- 매개변수는 C, Java 언어와 같은 기존 언어의 함수 매개변수 형태와 거의 비슷하지만, 변수 타입을 기술하지는 않는다.
3) 실행문
4) 반환문(Option)
- 반환문은 함수의 실행을 중단하고, return 키워드 다음에 명시된 표현식의 값을 호출자에게 반환한다.
- 반환시 리턴 타입 제한은 없다. 배열이나 객체를 포함한 모든 타입의 값을 반환할 수 있다.
▶ 3. 함수 생성 방법
1) 함수 선언문 방식
- 함수명 정의가 필수이다.
function 함수명(매개변수1, 매개변수2,...) {
실행문;
// 반환문; (optional)
}
ex)
function add(x, y){
return x+y;
}
console.log(add(3, 4));// 7
2) 함수 표현식 방식
- 함수 리터럴로 하나의 함수를 만들고, 여기서 생성된 함수를 변수에 할당하여 함수를 생성하는 것을 함수 표현식 이라고 한다.
2.1) 익명 함수 표현식(이름 없는 함수 표현식)
var 변수명 = function(매개변수1, 매개변수2,...) {
실행문;
// 반환문; (optional)
}
ex)
var addNoNamed = function(x, y){ // 이름 없는 함수형태 => 익명 함수 표현식
return x+y;
};
console.log(addNoNamed(3,4)); // 7
2.2) 기명 함수 표현식(이름 있는 함수 표현식)
var 변수명 = function 함수명(매개변수1, 매개변수2,...) {
실행문;
// 반환문; (optional)
}
ex)
var addNamed = function sum(x, y){ // 이름 포함된 함수 표현식 => 기명 함수 표현식
return x+y;
};
console.log(addNoNamed(3,4)); // 7
console.log(sum(3,4)); // Uncaught ReferenceError : sum is not defined 에러 발생
- 위의 예제에서 보면 함수 표현식에서 사용된 함수 이름이 외부 코드에서 접근 불가능 하기 때문에 오류가 발생 하였다.
- 함수 표현식에 사용된 함수 이름은 정의된 함수 내부에서 해당함수를 재귀적으로 호출하거나, 디버거 등에서 함수를 구분할 때 사용된다.
※ 1. 함수 선언문, 2.함수 표현식의 세미콜론
- 1. 함수 선언문, 2.함수 표현식을 살표 보았는데 비슷하지만, 미묘 하게 다른 부분이 있었을 것이다. => 끝에 세미콜론이 있고 없고의 차이다.
- 자바스크립트는 세미콜론 사용을 강제하지는 않는다. 자바스크립트 인터프리터가 자동으로 세미콜론을 삽입시켜 주기 때문이다.
- 기본적으로 함수 선언문에서는 ";"을 붙이지 않는다.
- 함수 표현식에서는 ";"을 붙인다.(변수 선언할때 보면 세미콜론을 붙였을 것이다.)
ex)var 변수 = 1;
- 다음 예제를 먼저 한번 실행하여 보자.
var testFunc = function(){
return 1;
} //세미콜론 사용하지 않음.
(function() {
console.log("test");
})();
- 에러가 발생한다. 자바스크립트 파서가 testFunc()의 함수 정의에서 세미콜론을 사용하지 않아, return 1; } 이후 함수가 끝났다고 판단하지 않기 떄문이다.
- 이 부분은 이해할 필요는 없을 것 같다. 아무튼 세미콜론을 어떤 문법에 따라 잘 써준다면, 오류도 발생하지 않고 유용하다.
- 많은 자바스크립트 가이드에서 함수 표현식 방식에서의 세미콜론 사용을 강력 히 권고한다.
3) Function() 생성자 함수를 통한 함수 생성
new Function (arg1, arg2, ... argN, functionBody)
- arg1, arg2, .., argN : 함수의 매개변수
- functionBody : 함수가 호출될 때 실행될 코드를 포함한 문자열
ex)
var add = new Function('x', 'y', 'return x + y');
console.log(add(3,4)); //7
▶ 4. 함수 호출 방법
- 예를 통해 살펴 보자.
ex)
ex)
function add(x, y){
return x+y;
}
var result = add(3, 4); // add()함수를 호출하며 파라미터를 x,y에 대입한다. 결과7을 result에 대입니다.
console.log(add(3, 4));// 7
▶ 5. 함수의 유효 범위(function scope)
- 자신이 정의된 범위 안에서 모든 변수 및 함수에 접근할 수 있다.
- '전역 함수'는 모든 전역 변수와 전역 함수에 접근할 수 있다.
- '내부 함수'는 그 함수의 부모 함수에서 정의된 모든 변수 및 부모 함수가 접근할 수 있는 모든 다른 변수까지도 접근할 수 있다.
- 변수의 유효 범위도 함수의 유효 범위랑 비슷하게 보면 된다. 이 부분은 예제를 통해 살펴 보자
ex)
// 전역 변수 선언. 어디에서도 접근 가능.
var a = 3, b = 4;
// sub()를 전역 함수로 선언함.
function add() {
return a + b; // 전역 변수인 a, b에 접근 가능
}
console.log(add()); // 7
function parentAdd() {
var x = 1, y = 2; // 전역 변수와 같은 이름으로 선언.
function add2() { // add() 함수는 내부 함수로 선언.
return x + y; // 전역 변수가 아닌 지역 변수 a, b에 접근함.
}
return add();
}
console.log(parentAdd()); // 3
console.log(add2()); // Uncaught ReferenceError: add2 is not defined
console.log(a) // 3
console.log(x) // Uncaught ReferenceError: x is not defined
▶ 6. 함수 호이스팅(hoisting)
- 예를 먼저 살펴보자.
ex)
console.log(add(2,3)); //5
// 함수 선언문
function add(x, y){
return x + y;
}
console.log(add(3, 4)); //7
- "함수 선언문" 정의 이전에 함수를 호출해도 5라는 결과가 노출된다.
- 즉 "함수 선언문" 형태로 정의한 함수의 유효범위는 코드의 맨 처음부터 이다. 이를 "함수 호이스팅" 이라고 한다.
- 이와 같은 이유로 함수 표현식을 권장 하고 있다.
- 위의 예제를 "함수 표현식" 형태로 정의하고 다시 호출해 보자.
ex)
add(2,3); // uncaught type error
var add = function (x, y){
return x + y;
}
- "함수 표현식" 형태로 정의하게되면 호이스팅이 일어나지 않는다.
▶ 7. 매개변수(parameter), 인수(argument)
1) 매개변수(parameter)
- 함수의 정의에서 전달받은 인수를 함수 내부로 전달하기 위해 사용하는 변수.
- 매개변수는 C, Java 언어와 같은 기존 언어의 함수 매개변수 형태와 거의 비슷하지만, 변수 타입을 기술하지는 않는다.
- 자바스크립트의 경우는 함수를 호출할 때 함수의 정의보다 적은 수의 인수가 전달되더라도, 오류를 발생시키지 않는다.
이 경우 전달되지 않은 나머지 매개변수에 자동으로 undefined 값을 설정한다.
2) 인수(argument)
- 함수가 호출될 때 함수로 값을 전달해주는 값을 말한다.
ex) 매개변수, 인수
function add(x, y){ // x, y 2개의 매개변수를 가지는 함수 정의
return x+y;
}
add(3, 4); // 인수로 3, 4를 전달. 결과 : 7
add(3); // 인수로 3 전달. y에는 undefined 값이 설정됨. 결과 : 3 + undefined = NaN(계산할수 없음)
add(); // 인수로 아무것도 전달하지 않고 함수 호출. 결과 : undefined + undefined = NaN(계산할수 없음)
3) arguments 객체
- 함수의 정의보다 더 많은 수의 인수가 전달된 경우, 해당 인수들을 참조할 수 없다.
- 이럴때 사용할 수 있는 것이 arguments 객체이다.
- 활용 방법은 예제를 통해 확인하면 좋을 것 같다.
ex)
function add(){
var sum = 0;
for (var i=0; i<arguments.length; i++){
sum += arguments[i];
}
return sum;
}
console.log(add(3, 4)); // 7
console.log(add(3)); // 3
console.log(add()); // 0
4) 디폴트 매개변수(default parameter)
- 함수를 호출할 때 명시된 인수를 전달하지 않았을 경우에 사용하게 될 기본값
- 현재 모든 브라우저에서 지원하지 않기 때문에 추천하지 않는다.
- 선언하지 않은 경우엔 undefined
ex)
function add(a, b = 0) { // b에 해당하는 인수가 없으면 디폴트 0으로 설정한다.
return a + b;
}
add(3, 4); // 7
add(3); // 3
add(); // NaN
5) 나머지 매개변수(rest parameter)
- 생략 접두사(...)를 사용하여 특정 위치의 인수부터 마지막 인수까지를 한 번에 지정할 수 있다.
ex) 첫 번째 인수에 값을 저장하고, 생략 접두사를 통해 모든 값을 빼보자.
function minusFunc(firstNum, ...restArguments){
for(var i = 0; i < restArguments.length; i++) {
firstNum -= restArguments[i];
}
return firstNum;
}
var result = minusFunc(20, 1,2,3,4,5);
console.log(result); // 5
2. 함수(function) 심화
▶ 8. 재귀함수
- 자기 자신을 호출하는 함수를 재귀함수 라고 한다.
- 위에서 설명했듯이, 함수는 자신을 참조, 호출 가능하다.
ex)
function factorialTest(x) {
console.log("현재 x : " + x);
var y = 1;
if(x==y) return y;
else return x*factorialTest(x-1); // 재귀 호출
}
var result = factorialTest(3);
console.log("결과 : " + result); // 6
▶ 9. 클로저
- 함수가 실행 후 종료 되어도, 종료된 함수 내의 변수가 소멸되지 않는 특성 이다.
- 이런 특성을 활용한 함수가 클로저 함수 이다.
- 리턴문이 포함된 함수여야 한다.
- 예제를 통해 먼저 확인 해 보자.
ex)
function outerFunc(a, b) {
var c = 10;
function innerFunc(x) {
return (x * x) * c;
}
return innerFunc(a) + innerFunc(b);
}
var a = outerFunc(2, 3); // 130
console.log(a); //130
console.log(innerFunc(3)); // Uncaught ReferenceError: innerFunc is not defined
console.log(c); // Uncaught ReferenceError: c is not defined
- 외부 함수는 내부 함수의 인수와 변수를 사용할 수 없는 반면에, 내부 함수는 외부 함수의 인수와 변수를 사용할 수 있다.
▶ 10. 즉시 실행 함수
- 익명 함수를 만들면서 즉시 실행 하는 함수
- 플러그인이나 라이브러리 등을 만들 때 많이 사용 한다.
- 기본 문법
(function () {
// statements
})()
1) 기명 즉시 실행 함수
ex) 다음 두 예제는 똑같은 의미의 기명 함수
(function square(x) {
console.log(x*x);
})(2);
(function square(x) {
console.log(x*x);
}(2));
2) 익명 즉시 실행 함수
ex) 다음 두 예제는 똑같은 의미의 익명 함수
(function (x) {
console.log(x*x);
})(2);
(function (x) {
console.log(x*x);
}(2));
3) 변수에 즉시 실행 함수 저장 하기
- 함수 이기 때문에 변수에 저장 할 수 있다.
- 이 경우에는 즉시 실행 함수임에도 재사용 가능하다.
ex)
ex)
(square = function (x) {
console.log(x*x);
})(2);
square(2);
4) 라이브러리 전역 변수 충돌 해결
- jQuery와 prototype.js 또는 MooTools 등 다양한 라이브러리를 사용하다보면, $라는 전역변수가 충돌하는 경우가 있다.
다른 라이브러리에서 $를 재정의하면 jQuery에서 정상동작하지 않을 수 있는데, 이럴때 즉시실행 함수를 사용하여 해결 가능하다.
방법1)
(function ($) {
// You can use the locally-scoped $ in here as an alias to jQuery.
})(jQuery);
방법2)
jQuery( document ).ready(function( $ ) {
// You can use the locally-scoped $ in here as an alias to jQuery.
});
▶ 11. this
- 자바스크립트의 경우 함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정된다.
- this는 매우 중요하지만, 이해하기 어려운 것 같다. 일단 이번엔 함수에서의 간단한 this의 의미를 알아 보고
this에 대해 자세히 다음 기회에 알아 보도록 한다.
1) 일반함수의 this
- 함수 내부의 this는 전역 객체 window를 가리킨다.
ex)
function sum(a, b) {
console.log(this === window); // => true, 즉 this는 전역 객체이다.
this.result = a + b; // 전역 객체에 'result'라는 속성을 추가 한것과 같다.
return this.result;
}
console.log(sum(3, 4)); // => 7
window.result; // => 7
2) 내부함수의 this
- 외부 함수에서의 this와 내부 함수에서의 this는 전혀 다르다.
ex)
var numbers = {
a: 3,
b: 4,
sum: function() {
console.log(this === numbers); // => true
function calculate() {
// this는 window
console.log(this === numbers); // => false
return this.a + this.b;
}
return calculate();
}
};
numbers.sum(); // NaN
- 주석을 보지 않고 생각해보면 마치 3+4인 7이 나올꺼 같지만 NaN이라는 결과가 나온다.
- 이런 문제를 해결하는 방법을 확인해 보자.
해결법1) .call 메소드를 사용
var numbers = {
a: 3,
b: 4,
sum: function() {
function calculate() {
// this는 window
return this.a + this.b; // => numbers.numberA + numbers.numberB 와 동일한 결과
}
return calculate.call(this);
}
};
numbers.sum(); // 7
해결법2) this를 변수에 넣어 내부함수에서 사용
var numbers = {
a: 3,
b: 4,
sum: function() {
var objThis = this;
function calculate() {
// this는 window
return objThis.a + objThis.b; // => numbers.numberA + numbers.numberB 와 동일한 결과
}
return calculate();
}
};
numbers.sum(); // 7
- this는 정말 복잡하다. 일단 this는 따로 포스팅하고 일단 간단한 활용법만 정리하였다.
▶ 12. 화살표 함수(Arrow function)
- function 키워드 대신 화살표(=>)를 사용하여 보다 간략한 방법으로 함수를 선언할 수 있다.
- 물론 모든 함수가 가능한것은 아니다.
- 매개변수 지정 방법
() => { ... } // 매개변수가 없을 경우
(x) => { ... } // 매개변수가 한 개인 경우(소괄호를 생략 가능)
(x, y) => { ... } // 매개변수가 여러 개인 경우(소괄호를 생략 불가)
- 함수 몸체 지정 방법
x => { return x + y } // 함수 몸체가 한줄 구문인 경우
x => x + y // 함수 몸체가 한줄의 구문인 경우(중괄호를 생략 가능, 암묵적으로 return)
(x) => { // 함수 몸체가 여러줄 구문인 경우
var y = 2;
return x * y;
};
- 객체 반환시에는 소괄호를 사용한다.
() => { return { x : 2 }; }
() => ({ x : 2 })
- 익명함수로만 사용 가능하다.
- 참고로 var대신 const로 선헌 하였는데, 이런 경우 변수 재선언, 재할당 모두 불가능하다.
const add = (x,y) => x + y;
console.log(add(3,4)); // 7
const add = (x,y) => x + y; // Uncaught SyntaxError: Identifier 'add' has already been declared
'2. 웹개발 > Javascript' 카테고리의 다른 글
[JavaScript (8)] Javascript prototype chain(프로토타입 체인) (0) | 2020.03.25 |
---|---|
[JavaScript (7)] Javascript 함수2 - 기본 내장함수(eval, parseInt, encodeURI, encodeURIComponent 등) (0) | 2020.03.23 |
[JavaScript (5)] Javascript 제어문(2) - 반복문(for, while, break, continue) (0) | 2020.03.16 |
[JavaScript (4)] Javascript 제어문(1) - 조건문(if문, switch문) (0) | 2020.03.16 |
[JavaScript (3)] Javascript 연산자 (0) | 2020.03.16 |
당신이 좋아할만한 콘텐츠
-
[JavaScript (8)] Javascript prototype chain(프로토타입 체인) 2020.03.25
-
[JavaScript (7)] Javascript 함수2 - 기본 내장함수(eval, parseInt, encodeURI, encodeURIComponent 등) 2020.03.23
-
[JavaScript (5)] Javascript 제어문(2) - 반복문(for, while, break, continue) 2020.03.16
-
[JavaScript (4)] Javascript 제어문(1) - 조건문(if문, switch문) 2020.03.16
소중한 공감 감사합니다