HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🐣
프론트엔드 데브코스 3기 교육생
/
📚
3기 스터디 가이드
/
💯
자바스크립트 Deep Dive 스터디
/
🕤
자바스크립트 Deep Dive
/
😀
4장 - 15장
/
🌟
별
🌟

별

 
12장 함수

12.1 함수란?

  • 일련의 과정을 문(statement)으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것.
  • 함수 내부로 입력을 전달받는 변수를 매개변수, 입력을 인수, 출력을 반환값이라 한다.
 

12.2 함수를 사용하는 이유

  • 함수는 몇 번이든 호출할 수 있으므로 코드의 재사용이라는 측면에서 매우 유용
  • 잘 정의된 함수는 유지보수의 편의성을 높이고 실수를 줄여 코드의 신뢰성을 높이는 효과
  • 함수는 객체 타입의 값으로, 이름을 붙일 수 있으며, 함수 이름은 함수 자신의 역할을 잘 설명해야 한다. → 함수의 내부 코드를 이해하지 않고도 함수의 역할 파악 가능. 코드의 가독성 향상
 

12.3 함수 리터럴

  • 자바스크립트의 함수는 객체 타입의 값
  • 함수 리터럴은 function 키워드, 함수 이름, 매개변수 목록, 함수 몸체로 구성
// 변수에 함수 리터럴을 할당 var f = fucntion add(x, y) { return x + y; }
  • 함수 리터럴의 자세한 구성 요소는 157p 참고
    • 함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자다.
  • 리터럴은 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기 방식(5.2절 “리터럴” 참고)
  • 즉, 리터럴은 값을 생성하기 위한 표기법이며, 이 값은 객체로, 함수는 객체다.
  • 일반 객체는 호출할 수 없지만 함수는 호출 가능. 함수는 일급 객체이다.
 

12.4 함수 정의

  • 함수를 호출하기 이전에 인수를 전달받을 매개변수와 실행할 문들, 반환할 값을 지정하는 것을 말한다.
  • 정의된 함수는 자바스크립트 엔진에 의해 평가되어 함수 객체가 된다.
  • 함수 정의에는 4가지 방법이 존재
// 함수 선언문. 함수 이름 생략 불가능 function add(x, y) { return x + y; } // 함수 표현식. var add = fucntion(x, y) { return x + y; } // Function 생성자 함수 var add = new Function('x', 'y', 'return x + y'); // 화살표 함수(ES6) var add = (x, y) => x + y;
  • 함수 선언문은 표현식이 아닌 문. 함수 선언문을 콘솔에서 실행하면 완료 값 undefined가 출력
 
  • 함수 선언문과 함수 리터럴 표현식의 차이
// 기명 함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석 // 함수 선언문에서는 함수 이름을 생략할 수 없다. function foo() { console.log('foo'); } foo(); // foo // 함수 리터럴을 피연산자로 사용하면 함수 선언문이 아니라 함수 리터럴 표현식으로 해석 // 함수 리터럴에서는 함수 이름을 생략할 수 있다. (function bar() { console.log('bar'); }); bar(); // ReferenceError: bar is not defined;
  • foo는 함수 선언문으로 해석, 그룹 연산자 () 내에 있는 bar는 함수 리터럴 표현식으로 해석된다.
  • 그룹 연산자의 피연산자는 값으로 평가될 수 있는 표현식이어야 하므로, 표현식이 아닌 문인 함수 선언문은 피연산자로 사용할 수 없다.
  • 함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자이므로, 함수를 가리키는 식별자가 없는 것과 마찬가지이다. 따라서 위 예제의 bar 함수는 호출할 수 없다.
  • 그렇다면 foo는 어떻게 실행되는 것인가? → foo는 자바스크립트 엔진이 암묵적으로 생성한 식별자이다.
  • 자바스크립트 엔진은 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고, 거기에 함수 객체를 할당한다.
 
함수 선언문을 의사 코드로 표현하면 다음과 같다.
var add = function add(x, y) { return x + y; } console.log(add(2, 5)); // 7
  • 함수는 함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출한다.
  • 즉, 함수 선언문으로 생성한 함수를 호출한 것은 함수 이름 add가 아니라, 자바스크립트 엔진이 암묵적으로 생성한 식별자 add이다.
  • 위 의사 코드는 함수 표현식과 유사하다. 결론적으로 자바스크립트 엔진은 함수 선언문을 함수 표현식으로 변환해 함수 객체를 생성한다고 생각할 수 있다.
  • 단, 함수 선언문과 함수 표현식이 정확히 동일하게 동작하는 것은 아니다.
// 기명 함수 표현식 var 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
 
12.4.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 nor a function // 함수 선언문 function add(x, y) { return x + y; } // 함수 표현식 var sub = function(x, y) { return x - y; };
  • 함수 선언문으로 함수를 정의하면 런타임 이전에 함수 객체가 먼저 생성되며, 자바스크립트 엔진이 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고 함수 객체를 할당한다. → 이처럼 함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 함수 호이스팅이라 한다.
  • 함수 표현식은 변수에 함수 리터럴을 할당하는 것. 변수 할당문의 값은 할당문이 실행되는 시점, 즉 런타임에 평가되므로 함수 표현식의 함수 리터럴도 할당문이 실행되는 시점에 평가되어 함수 객체가 된다. → 따라서 함수 표현식으로 함수를 정의하면 함수 호이스팅이 발생하는 것이 아니라 변수 호이스팅이 발생한다.
  • 함수 호이스팅은 함수를 호출하기 전에 반드시 함수를 선언해야 한다는 당연한 규칙을 무시하기 때문에 함수 선언문 대신 함수 표현식을 사용할 것을 권장한다.
 

12.5 함수 호출

12.5.1 매개변수와 인수
  • 함수는 매개변수의 개수와 인수의 개수가 일치하는지 체크하지 X
  • 인수가 부족해서 할당되지 않은 매개변수의 값은 undefined
  • 매개변수보다 인수가 많은 경우 초과된 인수는 무시
    • 그냥 버려지는 것은 아니고 모든 인수는 암묵적으로 arguments 객체의 프로퍼티로 보관
 
12.5.2 인수 확인
  • 자바스크립트의 경우 함수를 정의할 때 적절한 인수가 전달되었는지 확인할 필요가 있음. 함수 내부에서 확인하더라도 부적절한 호출을 사전에 방지할 수는 없고 에러는 런타임에 발생하게 됨. → 타입스크립트로 사전에 방지 가능
  • 또는 매개변수 기본값을 통해 인수 체크 및 초기화를 간소화 가능
 
12.5.3 매개변수의 최대 개수
  • 엔진마다 조금씩 다르지만 충분히 많은 매개변수를 지정 가능
  • 매개변수는 최대 몇 개까지 사용하는 것이 좋을까?
    • 가장 이상적인 매개변수의 개수는 0개 → 매개변수의 개수가 많다는 것은 함수가 여러 가지 일을 한다는 증거이므로 바람직하지 않음. 이상적인 함수는 한 가지 일만 해야 하며 가급적 작게 만들어야 한다.
    • 매개변수는 최대 3개 이상을 넘지 않는 것을 권장한다. 만약 그 이상의 매개변수가 필요하다면 객체를 인수로 전달하는 것이 유리
      • 매개변수의 순서를 신경 쓰지 않아도 되고, 명시적으로 인수의 의미를 설명하는 키를 사용하게 되므로 코드의 가독성도 좋아지고 실수도 줄어든다. 단, 변경 시 발생하는 부수 효과에 주의
 
12.5.4 반환문
  • return 키워드로 함수 실행 결과를 함수 외부로 반환할 수 있다.
  • return 키워드 뒤에 표현식을 명시적으로 지정하지 않으면 undefined가 반환된다.
 

12.6 참조에 의한 전달과 외부 상태의 변경

  • 매개변수에 원시 타입 인수는 원본이 훼손되지 않으며, 객체 타입 인수는 원본이 훼손된다. → 원시 값은 값 자체가 복사되어 전달되고, 객체는 참조 값이 복사되어 전달되기 때문
  • 함수가 외부 상태를 변경하면 상태 변화를 추적하기 어려워진다. → 이는 코드의 복잡성을 증가시키고 가독성을 해치는 원인
    • 객체의 변경을 추적하는 옵저버 패턴이나, 객체를 불변 객체로 만들어 사용하기, 외부 상태를 변경하지 않고 외부 상태에 의존하지도 않는 순수 함수의 사용 등으로 이러한 문제를 해결할 수 있음.
  • 순수 함수를 통해 부수 효과를 최대한 억제하여 오류를 피하고 프로그램의 안정성을 높이려는 프로그래밍 패러다임을 함수형 프로그래밍이라 한다.
 

12.7 다양한 함수의 형태

  • 즉시 실행 함수
    • 함수 정의와 동시에 즉시 호출, 단 한 번만 호출되며 다시 호출할 수 없다.
    • // 가장 일반적인 방법 (function () { // ... }());
  • 재귀 함수
    • 함수가 자기 자신을 호출하는 함수
    • 반복되는 처리를 위해 사용 ex) 10부터 0까지 출력, 팩토리얼
    • 탈출 조건을 반드시 만들어야 함. 없으면 스택 오버플로 에러 발생
  • 중첩 함수
    • 함수 내부에 정의된 함수. 내부 함수라고도 한다.
    • 호이스팅으로 인해 혼란이 발생할 수 있으므로 if 문이나 for 문 등의 코드 블록에서 함수 선언문을 통해 함수를 정의하는 것은 바람직하지 않다.
  • 콜백 함수
    • 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수, 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수라고 한다. → 고차 함수는 콜백 함수를 자신의 일부분으로 합성한다.
    • 함수형 프로그래밍 패러다임뿐만 아니라 비동기 처리(이벤트 처리, Ajax 통신, 타이머 함수 등)에 활용되는 중요한 패턴이다.
    • // 콜백 함수를 사용한 이벤트 처리 // myButton 버튼을 클릭하면 콜백 함수를 실행한다. document.getElementById('myButton').addEventListener('click', function() { console.log('button clicked!'); }); // 콜백 함수를 사용한 비동기 처리 // 1초 후에 메시지를 출력한다. setTimeout(function () { console.log('1초 경과'); }, 1000);
  • 순수 함수와 비순수 함수
    • 어떤 외부 상태에 의존하지도 않고 변경하지도 않는, 즉 부수 효과가 없는 함수를 순수 함수, 외부 상태에 의존하거나 외부 상태를 변경하는, 즉 부수 효과가 있는 함수를 비순수 함수라고 한다.
    • 순수 함수를 통해 부수 효과를 최대한 억제해 오류를 피하고 프로그램의 안정성을 높여야 한다.
    •  
13장 스코프

13.1 스코프란?

  • 모든 식별자(변수 이름, 함수 이름, 클래스 이름 등)는 자신이 선언된 위치에 의해 다른 코드가 자신을 참조할 수 있는 유효 범위가 결정된다. 이를 스코프라 한다. 즉, 스코프는 식별자가 유효한 범위를 말한다.
  • 스코프 내에서 식별자는 유일해야 하지만 다른 스코프에는 같은 이름의 식별자를 사용할 수 있다.
    • var 키워드로 선언된 변수는 같은 스코프 내에서 중복 선언이 가능
    • let, const 키워드로 선언된 변수는 같은 스코프 내에서 중복 선언을 허용하지 않는다.
 

13.2 스코프의 종류

구분
설명
스코프
변수
전역
코드의 가장 바깥 영역
전역 스코프
전역 변수
지역
함수 몸체 내부
지역 스코프
지역 변수
 

13.3 스코프 체인

  • 스코프가 계층적으로 연결된 것
  • 변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.
  • 상위 스코프에서 유효한 변수는 하위 스코프에서 자유롭게 참조할 수 있지만 하위 스코프에서 유효한 변수를 상위 스코프에서 참조할 수는 없다. → 상속과 유사
 

13.4 함수 레벨 스코프

  • 코드 블록이 아닌 함수에 의해서만 지역 스코프가 생성된다는 의미
  • var 키워드로 선언된 변수는 함수의 코드 블록(함수 몸체)만을 지역 스코프로 인정하지만 ES6에서 도입된 let, const는 블록 레벨 스코프를 지원한다.
 

13.5 렉시컬 스코프

var x = 1; function foo() { var x = 10; bar(); } function bar() { console.log(x); } foo(); // 1 bar(); // 1
  1. 함수를 어디서 호출했는지에 따라 함수의 상위 스코프를 결정한다. - 동적 스코프
  1. 함수를 어디서 정의했는지에 따라 함수의 상위 스코프를 결정한다. - 렉시컬 스코프, 정적 스코프
  • 자바스크립트는 렉시컬 스코프를 따른다. 따라서 함수가 호출된 위치는 상위 스코프 결정에 어떠한 영향도 주지 않는다. 즉, 함수의 상위 스코프는 언제나 자신이 정의된 스코프다.
  • 이처럼 함수의 상위 스코프는 함수 정의가 실행될 때 정적으로 결정된다. 함수 정의(함수 선언문 또는 함수 표현식)가 실행되어 생성된 함수 객체는 이렇게 결정된 상위 스코프를 기억한다.
 
퀴즈
  1. 빈 칸에 들어갈 내용을 순서대로 작성해 주세요. 가장 이상적인 매개변수의 개수는 [ ]개이며, 최대 [ ]개 이상을 넘지 않는 것을 권장한다. 그 이상의 매개변수가 필요하다면 [ ]를 인수로 전달해야한다.
  1. 다음 코드의 실행 결과는?
    1. var x = 1; function foo() { var x = 10; bar(); } function bar() { console.log(x); } foo(); // ? bar(); // ?