12 함수
함수?
입력을 받아 출력을 내보내는 일련의 과정을 정의함
함수는 함수 정의(function definition)을 통해 생성
- 매개변수(parameter) : 함수 내부로 입력을 전달받은 변수
- 인수(argument) : 입력
- 반환값(return value) : 출력
함수의 호출
함수를 호출하게 되면 코드 블록에 담긴 문들이 일괄적 실행 -> 반환값을 반환
// 함수의 호출
const result = add(2, 5);
console.log(result); // 7
함수 사용 이유
- 코드의 재사용 : 함수는 몇 번이든 호출 가능
- 유지보수의 편의성 : 코드 중복을 억제하고 재사용성을 높이는 함수 개발
- 코드의 신뢰성 : 실수를 줄임
- 코드의 가독성 : 함수 이름은 자신의 역활을 잘 설명하게 식별자를 붙여 가독성 향상
함수 리터럴
함수 리터럴은 function 키워드, 함수 이름, 매개변수 목록, 함수 몸체로 구성
함수는 객체지만 일반 객체와 다름
일반 객체는 호출할 수 없지만 함수는 호출할 수 있음
-
함수 이름
- 함수 이름은 식별자이므로 식별자 네이밍 규칙을 준수
- 함수 이름 생략가능 (기명 함수: 이름 있음, 무명/익명 함수: 이름없음)
-
매개변수 목록
- 0개 이상의 매개변수를 소괄호로 감싸고 쉼표 구분
- 각 매개변수에는 함수를 호출할 때 지정한 인수가 순서대로 할당, 순서에 의미가 있음
- 매개변수도 식별자 네이밍 규칙 준수
-
함수 몸체
- 함수가 호출되었을 때 일괄적으로 하나의 실행 단위로 정의한 코드 블록
함수의 정의
1. 함수 선언문
- 함수 선언문은 함수 이름을 생략할 수 없음
- 함수는 함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출
- 함수 선언문은 "표현식이 아닌 문"
function add(x, y) {
return x + y;
}
// 함수 참조
console.log(add); // f add(x, y)
// 함수 호출
console.log(add(2,5)); // 7
// 함수 선언문은 함수 이름을 생략할 수 없음
// 함수 선언문은 표현식이 아님
function (x, y) {
return x + y; // SyntaxError
}
2. 함수 표현식
- 함수는 일급 객체이므로 함수 리터럴로 생성한 함수 객체를 변수에 할당할 수 있음
- 함수 표현식은 "표현식인 문"
// 기명 함수 표현식
const add = function foo(x, y) {
return x + y;
}
console.log(add(2,5)); // 7
// 함수 이름으로 호출하면 ReferenceError 발생
console.log(foo(2,5)); // ReferenceError : foo is not defined
3. 함수 생성 시점과 함수 호이스팅
//함수 참조
console.dir(add); // f add(x, y)
console.dir(sub); // undefined
// 함수호출
console.log(add(2, 5)); // 7
console.log(sub(2, 5)); // TypeError : sub is not a function
// 함수 선언문
function add(x, y) {
return x + y;
}
// 함수 표현식
const sub = function (x, y) {
return x - y;
}
- 함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출 불가능
- 함수 선언문으로 정의한 함수와 함수 표현식으로 정의한 함수의 생성 시점이 다름 - 함수 표현식으로 함수를 정의하면 함수 호이스팅이 발생하는 것이 아니라 변수 호이스팅이 발생
함수 호이스팅(function hoisting) : 함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트의 고유의 특징
4. Function 생성자 함수
- 생성자 함수는 객체를 생성하는 함수를 뜻함.
- new 연산자 없이 호출해도 결과는 동일함
const add1 = (function () {
var a = 10;
return function (x, y) {
return x + y + a;
};
}());
console.log(add1(1, 2)); // 13
// Function 생성자 함수로 생성한 함수는 클로저를 생성하지 않는 등,
// 함수 선언문이나 함수 표현식으로 생성한 함수와 다르게 동작
const add2 = (function () {
var a = 10;
return new Function('x', 'y', 'return x + y + a;');
}());
console.log(add2(1, 2)); // ReferenceError : a is not defined
5. 화살표 함수
- ES6에서 도입된 화살표 함수(arrow function)은 function 키워드 대신 화살표를 사용하여 좀 더 간략한 방법으로 함수를 선언 할 수 있음
- 화살표 함수는 생성자 함수로 사용할 수 없음
- 기존 함수와 this 바인딩 방식이 다르고, prototype 프로퍼티가 없음
- arguments 객체를 생성하지 않음
const add = (x, y) => x + y;
console.log(add(2, 5)); // 7
함수 호출
- 함수는 함수를 가르키는 식별자와 한 쌍의 소괄호인 함수 호출 연산자로 호출
1. 매개변수와 인수
- 함수를 실행하기 위해 필요한 값을 함수 외부에서 함수 내부로 전달할 필요가 있는 경우 매개변수(parameter 인자)를 통해 인수(argument)를 전달
- 개수와 타입에 제한이 없음
- 매개변수의 스코프(유효 범위)는 함수 내부
- 자바스크립트 함수는 매개변수와 인수의 개수가 일치하는지 확인하지 않음
- 자바스크립트는 동적 타입 언어 이므로 매개변수의 타입을 사전에 지정할 수 없음
function add(x, y) {
return x + y;
}
//매개변수보다 인수가 더 많은 경우 초과된 인수 무시
console.log(add(2, 5, 10)); // 7
// 인수가 전달되지 않는 경우 단축 평가를 사용하여 기본값 할당
function add(a, b, c) {
a = a || 0;
b = b || 0;
c = c || 0;
return a + b + c;
}
console.log(add(1, 2, 3)); // 6
console.log(add(1, 2)); // 3
console.log(add()); // 0
2. 매개변수의 최대 개수
- ECMAScript 사양에서는 매개변수의 최대 개수에 대해 명시적으로 제한하고 있지 않음
- 매개변수는 순서에 의미가 있음 -> 매개변수가 많아질 수록 유지보수성이 나빠짐
- 매개변수는 최대 3개 이상을 넘지 않는 것을 권장함
- 이상적인 함수는 한 가지 일만 해야 하며 가급적 작게 만들어야 함
3. 반환문
- 함수는 return 카워드와 표현식(반환값)으로 이뤄진 반환문을 사용해 외부로 반환(return)할 수 있음
// ex1)
function multiply(x, y) {
return x * y; // 반환문
// 반환문 이후에 다른 문이 존재하면 그 문은 실행되지 않고 무시
console.log('실행되지 않음');
}
const result = multiply(3, 5);
console.log(result); // 15
// ex2)
function foo () {
return;
}
console.log(foo()); // undefined
// ex3)
function multiply2(x, y) {
// return 키워드와 반환값 사이에 줄바꿈이 있으면
return // 세미콜론 자동 삽입 기능(ASI)에 의해 세미콜론 추가
x * y; // 무시
}
console.log(multiply2(3,5)); // undefined
참조에 의한 전달과 외부 상태 변경
// 매개변수 primitive는 원시 값을 전달받고, 매개변수 obj는 객체를 전달받음
function changeVal(primitvie, obj) {
primitive += 100;
obj.name = 'Kim';
}
// 외부
var num = 100;
var person = { name: 'Lee' };
console.log(num); // 100
console.log(person); // { name: "Lee" }
// 원시 값은 값 자체가 복사되어 전달, 객체는 참조 값이 복사되어 전달
changeVal(num, person);
// 원시 값은 원본이 훼손되지 않음
console.log(num); // 100
// 객체는 원본이 훼손
console.log(person); // { name: "Kim" }
- 원시 값은 변경 불가능한 값(im-mutable value)이므로 직접 변경할 수 없기 때문에 재할당을 통해 할당된 원시 값을 새로운 원시 값으로 교체
- 객체 타입 인수를 전달받은 매개변수 obj인 경우, 객체는 변경 가능한 값(mutable value)이므로 직접 변경할 수 있기 때문에 재할당 없이 직접 할당된 객체를 변경
다양한 함수
1. 즉시 실행 함수
- 함수의 정의와 동시에 즉시 함수 호출
-> 즉시 실행 함수는 단 한 번만 호출되어 다시 호출 불가능 - 즉시 실행 함수는 함수 이름이 없는 익명 함수를 사용하는 것이 일반적
(function () {
var a = 3;
var b = 5;
return a * b;
}());
// 즉시 실행 함수는 반드시 그룹 연산자(...) 감싸야 함
function foo() {
}(); // SyntaxError
// 함수 코드 블록의 닫는 중괄호 뒤에 ";"이 암묵적으로 추가되어 오류 발생
// => function foo() {};();
// 즉시 실행 함수도 일반 함수처럼 값을 반환 가능
var res = (function () {
var a = 3;
var b = 5;
return a * b;
}());
console.log(res); // 15
// 즉시 실행 함수에도 일반 함수처럼 인수를 전달할 수 있음
res = (function (a, b) {
return a * b;
}(3, 5));
console.log(res); //15
재귀 함수
- 함수가 자기 자신을 호출하는 것 (재귀 호출을 수행하는 함수)
- 탈출 조건을 반드시 만들어야 됨
-> 조건이 없는 경우 함수가 무한 호출되어 스택 오버플로 에러발생
function countdown(n) {
for (var i = n; i >= 0; i--) console.log(i);
}
countdown(10);
// 재귀 함수로 변경
function countdown(n) {
if (n < 0) return;
console.log(n);
countdown(n - 1); // 재귀 호출
}
countdown(10);
중첩 함수
- 함수 내부에 정의된 함수를 중첩 함수(nested function) 또는 내부 함수(inner function)
- 중첩 함수를 포함하는 함수는 외부 함수(outer function)
- ES6부터 함수 정의는 문이 위치할 수 있는 문맥이면 어디든 가능
- 단, 호이스팅으로 혼란이 발생할 수 있으므로 if문 또는 for문 등의 코드 블록에서 함수 선언문을 통해 함수를 정의하는 것은 바람직하지 않음.
function outer() {
var x = 1;
// 중첩함수
function inner() {
var y = 2;
// 외부 함수의 변수 참조 가능
console.log(x + y); // 3
}
inner();
}
outer();
콜백 함수
- 콜백 함수(callback function) : 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수
- 고차 함수(Higher-Order function) : 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수
- 고차 함수는 매개변수를 통해 전달받은 콜백 함수의 호출 시점을 결정해서 호출
- 콜백 함수를 다른 곳에서 호출할 필요가 있거나, 콜백 함수를 전달 받는 함수가 자주 호출된다면 함수 외부에서 콜백 함수를 정의한후 함수 참조를 고차 함수에 전달하는 편이 효율적
// ex1)
// 익명 함수 리터럴을 콜백 함수로 고차 함수에 전달
// 익명 함수 리터럴은 repeat 함수를 호출할 때마다 평가되어 함수 객체를 생성
repeat(5 , function (i) {
if (i % 2) console.log(i);
}); // 1 3
// ex2)
const logOdds = function (i) {
if (i % 2) console.log(i);
};
// 고차 함수에 함수 참조를 전달
repeat(5, logOdds); // 1 3
// 콜백 함수를 사용하는 고차 함수 map
var res = [1,2,3].map(item => item * 2);
console.log(res); // [2, 4, 6]
// 콜백 함수를 사용하는 고차 함수 filter
res = [1,2,3].filter(item => item % 2);
console.log(res); // [1, 3]
// 콜백 함수를 사용하는 고차 함수 reduce
res = [1, 2, 3].reduce((acc, cur) => acc + cur),0);
console.log(res); // 6
순수 함수와 비순수 함수
순수 함수(prue function) : 부수 효과가 없는 함수
var count = 0; // 순수 함수는 동일한 인수가 전달되면 언제나 동일한 값을 반환 function increase(n) { return ++n; } count = increase(count); console.log(count); // 1; count = increase(count); console.log(count); // 2;
비순수 함수(impure function) : 부수 효과가 있는 함수
var count = 0; function increase() { return ++count; // 외부 상태에 의존하여 외부 상태를 변경 } increase(); console.log(count); // 1; increase(); console.log(count); // 2;
📖 참고도서 : 모던 자바스크립트 Deep Dive 자바스크립트의 기본 개념과 동작 원리 / 이웅모 저 | 위키북스
Author And Source
이 문제에 관하여(12 함수), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dev_jazziron/12저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)