📌 참고 사이트
함수
ko.javascript.info
📋 함수 (function)
➡️ 함수는 프로그램을 구성하는 주요 구성 요소(building block)로 어떤 동작을 수행하기 위한 코드를 모아놓은 것이다. 함수를 이용하면 유사한 동작을 하는 코드를 여러 번 호출 가능하다.
➡️ 앞선 시간에는 alert(message), prompt(message, default), confirm(question) 등과 같은 내장 함수들을 살펴보았다.
➡️ 이번에는 함수를 직접 만드는 방법에 대해 알아볼 것이다.
📋 함수 선언
📍 함수 선언, 호출 방식
➡️ function 키워드, 함수 이름, 괄호로 둘러싼 매개변수를 차례로 적어준다. 그 다음 함수 본문을 작성하는데, 이것은 중괄호로 감싸 붙여준다.
➡️ 매개변수가 없는 경우도 있고, 매개변수가 여러 개인 경우에는 콤마로 구분해 주어야 한다.
➡️ 정의를 마친 함수는 함수명() 의 형식으로 호출하면 함수 본문이 실행된다. 매개변수가 필요한 함수인 경우 괄호 안에 인자를 넣어 호출해 주면 된다.
fucntion showMessage() {
alert('안녕하세요!');
}
showMessage(); // 안녕하세요!
📋 변수
📍 지역 변수 (local variable)
➡️ 함수 내에서 선언한 변수를 지역 변수라 하고, 지역 변수는 함수 안에서만 접근할 수 있다.
➡️ 지역변수를 함수 밖에서 접근하면 오류가 발생하게 된다.
function showMessage() {
let message = '안녕하세요!'; // 지역 변수 message (함수 안에서 선언)
alert(message); // 안녕하세요! (함수 안에서 접근 시)
}
alert(message); // Uncaught ReferenceError: message is not defined (함수 밖에서 접근 시)
📍 외부 변수 (outer variable)
➡️ 함수 내부에서는 함수 밖에서 선언한 외부 변수에 접근, 수정하는 것이 가능하다.
이렇게 함수 외부에 선언된 변수는 '전역 변수 (global variable)'라고 부른다.
let userName = 'John'; // 외부 변수(전역 변수) userName (함수 밖에서 선언)
function modifyName() {
userName = 'Bob'; // 함수 내부에서 외부 변수 userName 수정하기
}
console.log(userName); // 함수 호출 전에는 John
modifyName(); // 이름 수정 함수 호출
console.log(userName); // 함수 호출 후에는 Bob
➡️ 함수 내부에 외부 변수와 동일한 이름의 변수가 선언되었다면, 이 내부 변수(지역 변수)가 외부 변수(전역변수(를 가리게 된다.
let userName = 'John'; // 외부 변수 userName 선언
function showName() {
let userName = 'Bob'; // showName 함수 내부 변수 userName 선언
alert(userName);
}
showName(); // 함수는 내부 변수인 userName만 사용한다. (외부 변수에 접근 X) 따라서 Bob이 출력됨.
alert(userName); // 외부 변수인 John이 출력됨.
➡️ 전역 변수는 같은 이름의 지역변수에 의해 우선순위가 밀려나지만 않는다면 모든 함수에서 접근, 수정이 가능하므로 코드의 안정성을 위해 전역변수를 되도록 사용하지 않는 것이 좋다.
but 프로젝트 전반에서 사용되는 데이터 같은 경우는 전역 변수에 저장하는 것이 유리할 수 있다.
📍 매개 변수 (parameter)
➡️ 임의의 데이터를 함수 안에 전달하기 위해 존재하는 변수이다. '인자' 라고도 불린다.
➡️ 매개변수는 함수 선언 괄호 안에 존재하는 변수이다. (매개변수는 선언 시 쓰이는 용어)
이 매개변수는 함수 안에서 쓰이므로 지역변수이다. 따라서 같은 이름의 외부 변수가 있어도 그 외부 변수에 영향을 미치지 못한다.
➡️ 함수 호출 시 매개변수에 '인수(argument)'가 전달된다. (인수는 호출 시 쓰이는 용어)
인수는 함수 선언 괄호 안에 존재하는 매개변수에 복사되고, 함수는 그 지역변수(매개변수)에 복사된 값을 사용한다.
function greeting(from, text) { // 매개변수(= 파라미터= 인자) : from, text
alert(from + ': ' + text);
}
greeting('Ann', 'Hi!'); // Ann: Hi!
위의 경우 인수 'Ann'은 매개변수 from에, 'Hi'는 매개변수 text에 차례로 복사되고, greeting 함수는 본문에 지역변수(매개변수와 같은 이름의 변수)가 등장하면 복사된 값을 사용하게 된다.
let from = 'Ann'; // 외부 변수(전역 변수) from
function greeting(from, text) {
from = '*' + from + '*'; // 매개변수(지역변수) from에 복사된 값을 변형한다.
alert(from + ': ' + text);
}
greeting(from, 'Hi!'); // *Ann*: Hi!
alert(from); // Ann (함수에서는 복사된 값을 사용하므로 바깥의 from은 값이 변경되지 않는다.)
위의 예시에서는 함수가 인자로 들어온 from값을 변경하지만 함수 내부에서는 언제나 복사된 값을 사용하기 때문에 변경 사항이 외부 변수(전역 변수)인 from에 반영되지 않는다.
즉, 함수 내부에서 사용하는 from과 외부에서의 from은 아예 독립적인 변수라고 보면 된다.
📋 기본값
➡️ 함수 호출 시 매개변수에 인수를 전달하지 않아도 에러는 발생하지 않는다. 그저 그 매개변수에 undefined가 전달될 뿐이다.
function sum(a, b) {
console.log(a + b);
}
sum(1); // a에는 1이, b에는 undefined가 할당됨. 따라서 더하기 연산을 하면 NaN이 됨.
➡️ 매개변수에 값을 전달하지 않아도 그 값이 undefined가 되지 않게 하려면 함수 선언 시 매개변수 옆에 =를 사용해 매개변수에 값이 전달되지 않았을 때 사용할 기본값을 작성해 주면 된다.
이렇게 하면 매개변수로 undefined를 전달할 경우에도 기본값이 할당되게 된다.
기본값에는 단순한 문자열 뿐만 아니라 함수 같은 복잡한 표현식으로도 설정이 가능하다.
function greeting(from, text = "no text given") {
alert(from + ": " + text);
}
greeting("Ann"); // Ann: no text given
// from에 Ann 할당, text에 해당하는 인수는 작성하지 않았으므로 기본값 no text given 할당
greeting("Ann", undefined); // Ann: no text given
// undefined를 직접 할당했을 때도 마찬가지로 no text given 할당
📍 매개변수 기본값 평가 시점
자바스크립트에서는 함수 호출 시마다 해당하는 매개변수에 특정 값이 전달되지 않은 경우 기본값을 평가하게 된다.
function showMessage(from, text = anotherFunction()) {
// anotherFunction()은 text값이 없을 때만 호출됨. (인수로 들어간 값이 없을 때 혹은 undefined가 들어갔을 때)
// anotherFunction()의 반환 값이 곧 text의 값이 됨.
}
위에서, 매개변수 text에 값이 전달되는 경우 anotherFunction()은 호출되지 않는다.
text 값이 없는 경우에만 showMessage()를 호출할 때마다 anotherFunction()이 호출된다.
📍 구식 자바스크립트에서의 매개변수 기본값 설정법
구식 자바스크립트는 위와 같은 매개변수 기본값 설정 문법이 존재하지 않아 매개변수 기본값을 설정하려면 다음과 같이 if문이나 || 연산자나 ?? 연산자를 사용하여 작성해야 했다.
💻 if문 사용하기
function showMessage(from, text) {
if (text === undefined) { // 매개변수 text에 undefined를 넣어 준 경우 또는 값을 전달하지 않은 경우
text = 'no text given';
}
alert(from + ': ' + text);
}
💻 || 연산자 사용하기
function showMessage(from, text) {
// ||는 true인 값을 반환한다. text가 true인 값이면 text 그대로, false인 값(undefined나 "", 0 등)이면
// no text given을 text에 할당
text = text || 'no text given';
.....
}
💻 nullish 병합 연산자(??) 사용하기
function showCount(count) {
// count가 정의된 값이면 count에 할당된 값 출력, 정의된 값이 아니면(null이나 undefined) 'unknown' 출력
alert(count ?? "unknown");
}
showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown
?? 연산자를 사용하면 ||를 사용할 때와 달리 0이나 빈 문자열과 같이 falsy로 평가되는 값들을 일반 값처럼 처리 가능하여 좋다.
📋 반환 값 (return value)
➡️ 함수 본문에 return을 사용하면 함수를 호출했을 때 함수를 호출한 곳에 특정한 값을 반환하게 할 수 있다.
➡️ 지시자 return은 함수 내 어디서든 사용할 수 있다. 실행 흐름이 지시자 return을 만나면 함수 실행이 즉시 중단되고, 함수를 호출한 곳에 값을 반환한다.
function sum(a, b) {
return a + b; // a와 b의 값을 더한 값을 반환
}
let result = sum(1, 2); // sum 함수를 통해 1 + 2의 값이 반환되고 result에 할당됨
alert(result); // 3
➡️ return 문은 하나의 함수에서 여러 개가 오는 것도 가능하다.
function checkAge(age) {
if (age >= 18) { // age에 할당된 값이 18 이상이면
return true; // true를 반환하고 함수 종료
} else { // 그렇지 않은 경우
return confirm('보호자의 동의를 받으셨나요?'); // confirm 창에서 확인을 누르면 true, 취소를 누르면 false 반환
}
}
let age = prompt('나이를 알려주세요.', 18);
if (checkAge(age)) { // checkAge 함수가 반환한 값이 if문의 괄호 안에 들어감.
alert('접속 허용'); // true일 시 실행
} else {
alert('접속 차단'); // false일 시 실행
}
➡️ 그냥 return 지시자만 명시하는 것도 가능하다. 이러한 경우에는 return 지시자를 만나면 함수가 즉시 종료된다. 반환되는 값은 undefined이다. (return undefined와 동일하게 작동한다.)
function showMovie(age) {
if (!checkAge(age)) {
return;
}
alert("영화 상영");
.....
}
checkAge(age)의 반환 값이 false이면 if 조건문은 true가 되어 return 지시자를 만나게 되어 showMovie 함수가 종료되게 된다.
반면 checkAge(age)의 반환 값이 true라면 if 조건문이 false가 되어 return 지시자를 건너뛰게 되고, 아래 alert문이 실행되게 된다.
❗ return과 반환하고자 하는 값 사이에서 줄바꿈을 시도하면 안 된다!
반환하고자 하는 값이 긴 표현식일 경우 return과 반환하려는 값 사이에 줄바꿈을 하여 코드를 작성하려 하면 의도치 않은 결과를 볼 수 있다.
자바스크립트는 return문 끝에 세미콜론을 자동으로 넣기 때문에 return 아래에 작성한 값들을 반환받을 수 없게 된다.
// 줄바꿈이 있는 코드
return
(some + long + expression)
// 위 코드는 아래와 같이 동작한다.
// 따라서 아무런 값이 반환되지 않는 것처럼 보인다. (undefined 반환)
return;
(some + long + expression)
따라서 표현식을 여러 줄에 걸쳐 작성하고 싶다면 return 지시자가 있는 줄에서 시작해야 하고, 괄호도 사용하여 작성해 주면 더 좋다.
return (
some + long +
expression
)
📋 함수 이름짓기
코드를 읽는 사람이 함수 이름만 보고도 이 함수가 어떤 동작을 하는지 힌트를 얻을 수 있게 함수명을 지어야 한다.
관습적으로는 함수 이름에서 다음과 같은 접두어는 다음과 같은 뜻을 가지고 있다.
➡️ show... : 무언가를 보여주는 함수
ex) showMessage : 메시지를 보여주는 역할
➡️ get... : 어떤 값을 반환하는 함수
ex) getAge : 나이를 나타내는 값을 얻고 그 값을 반환하는 역할
➡️ calc... : 무언가를 계산하는 함수
ex) calcSum : 합계를 계산하고 그 결과를 반환하는 역할
➡️ create... : 무언가를 생성하는 함수
ex) createForm : form을 생성하고 만들어진 form을 반환하는 역할
➡️ check... : 무언가를 확인하고 불린값을 반환하는 함수
ex) checkPermission : 승인 여부를 확인하고 true나 false를 반환하는 역할
📋 함수 == 주석
➡️ 함수는 간결하고, 하나의 함수는 한 가지 기능만 수행이 가능하게 만들어야 한다.
ex 1) getAge 함수에서는 나이를 얻어오는 동작만 수행하고, alert 창에 나이를 출력하는 등 다른 동작을 하는 것은 좋지 않다.
ex 2) createForm 함수는 form을 만들고 반환하는 동작만 수행하고, form을 문서에 추가하는 등 다른 동작을 하는 것은 좋지 않다.
➡️ 함수가 길어질 경우, 함수를 분리해서 작성하는 것이 좋다.
이렇게 함수를 간결하게 만들면 디버깅을 할 때에도 편리하고, 함수 그 자체가 주석의 역할이 될 수 있기 때문이다.
📍 n까지의 소수(prime numbers)를 출력해 주는 코드 작성해 보기
💻 레이블을 사용하여 반복문으로 작성하기 (하나의 함수로 작성하기)
function showPrimes(n) {
// 숫자는 2부터 n까지 살피기
nextPrime: for (let i = 2 ; i < n ; i++) {
// 2부터 자기 자신 - 1까지의 숫자 중
for (let j = 2 ; j < i ; j++) {
// 하나라도 나누어 떨어지면 바깥 for문의 다음 반복으로 넘어가기
if (i % j == 0) continue nextPrime;
}
// 위에서 continue에 걸리지 않는다면 alert문이 실행됨. 출력되는 것은 소수밖에 없다.
alert(i);
}
}
💻 소수인지를 판별하는 함수를 따로 분리하여 작성하기 (2개의 함수로 작성하기)
// 소수를 화면에 보여주는 역할을 하는 함수
function showPrimes(n) {
for (let i = 2 ; i < n ; i++) {
// isPrime 함수가 false를 반환하면 다음 반복으로
if (!isPrime(i)) continue;
// isPrime 함수가 true를 반환했을 때 실행 (isPrime의 인자로 소수가 들어갔을 때)
alert(i);
}
}
// 소수인지 아닌지를 판별하는 함수
function isPrime(n) {
for (let i = 2; i < n ; i++) {
// 하나라도 나누어 떨어지는 경우가 있으면 false 반환
if (n % i == 0) return false;
}
// 위에서 return을 만나 종료되지 않았을 경우 소수이므로 true 반환
return true;
}
함수를 따로 분리해서 작성하는 경우가 더 눈에 잘 들어온다. showPrime과 isPrime 함수의 경우 이름만 보고도 어떤 동작을 하는지 알 수 있다. (이러한 경우를 자기 설명적 코드라고 한다.)
✏️ 과제
📍 'else'는 정말 필요한가요?
아래 함수는 매개변수 age가 18보다 큰 경우 true를 반환한다.
그 이외의 경우는 confirm 대화상자를 통해 사용자에게 질문한 후, 해당 결과를 반환한다.
function checkAge(age) {
if (age > 18) {
return true;
} else {
return confrim('보호자의 동의를 받았나요?');
}
}
위 코드에서 else문을 삭제해도 기존 코드와 동일하게 작동할까? 아니면 무언가 변화가 있을까?
function checkAge(age) {
if (age > 18) {
return true;
}
return confrim('보호자의 동의를 받았나요?');
}
🅰️
답은 '기존 코드와 동일하게 작동한다' 이다.
함수 본문을 실행하다가 return 지시자를 만나면 값을 반환하고 함수가 종료되게 된다.
경우는 age > 18 이거나 그렇지 않을 경우 2가지이고, 처음에 age > 18 조건이 true가 되면 true를 반환하고 함수가 종료되고, 그렇지 않으면 if에서의 실행문인 return true는 건너뛰게 되어 return confirm('보호자의 동의를 받았나요?')가 실행되게 된다.
확인을 클릭하면 true가, 취소를 클릭하면 false가 반환되게 된다.
📍 ? 나 ||를 사용하여 함수 다시 작성하기
아래 함수는 매개변수 age가 18보다 큰 경우 true를 반환한다.
그 이외의 경우는 confirm 대화 상자를 통해 사용자에게 질문한 후 해당 결과를 반환한다.
function checkAge(age) {
if (age > 18) {
return true;
} else {
return confirm('보호자의 동의를 받았나요?');
}
}
if문을 사용하지 않고 동일한 동작을 하는 함수를 한 줄에 작성해 보자.
🅰️
💻 물음표 연산자 ?를 사용하여 작성하기
function checkAge(age) {
return age > 18 ? true : confirm('보호자의 동의를 받으셨나요?');
}
물음표 연산자 사용 부분에서 조건인 age > 18 검사 결과 참이면 true가 반환되고, false이면 confirm 창에서 선택한 버튼에 따라 true나 false가 반환된다.
이렇게 해서 얻은 값이 함수에서 최종적으로 반환된다.
💻 OR 연산자 ||를 사용하여 작성하기
function checkAge(age) {
return (age > 18) || confirm('보호자의 동의를 받으셨나요?');
}
|| 연산자는 위와 같이 사용할 경우 처음으로 true가 되는 값을 반환한다.
age > 18이 true일 경우 true가 반환되고 함수가 종료된다.
age > 18이 false일 경우 confirm문이 실행되어 사용자가 선택한 버튼에 따라 true나 false가 반환된 후 함수가 종료된다.
📍 min(a, b) 함수 만들기
a와 b 중 작은 값을 반환해주는 함수, min(a, b)를 만들어 보자.
(a == b 인 경우 a나 b 중 어떤 것을 반환해도 상관 없다.)
🅰️
function min(a, b) {
return a > b ? b : a;
}
📍 pow(x, n) 함수 만들기
x의 n제곱을 반환해주는 함수, pow(x, n)을 만들어 보자.
x의 n제곱은 x를 n번 곱해서 만들 수 있다.
프롬프트 대화상자를 띄워 사용자로부터 x와 n을 입력받고 pow(x, n)의 반환 값을 보여주는 코드를 작성해 보자.
(단, n은 1 이상의 자연수여야 하고, 이외의 경우에는 자연수를 입력하라는 alert 창을 띄워 주어야 한다.)
🅰️
// x의 n제곱의 값을 구해주는 함수
function pow(x, n) {
return x ** n;
}
// 사용자로부터 x와 n값 입력받기
let x = prompt('x 값을 입력해 주세요.');
let n = prompt('n 값을 입력해 주세요.');
// n이 1 이상의 자연수일 경우에만 pow 함수 실행, 그렇지 않으면 자연수 입력 요청 문구 띄우기
if (Number.isInteger(+n) && n >= 1) {
alert(pow(x, n));
}
else {
alert("자연수를 입력해 주세요.");
}
'Javascript study' 카테고리의 다른 글
[Javascript] 객체 (0) | 2023.07.21 |
---|---|
[Javascript] 함수 표현식 (0) | 2023.07.18 |
[Javascript] switch문 (0) | 2023.07.14 |
[Javascript] while과 for 반복문 (0) | 2023.07.14 |
[Javascript] nullish 병합 연산자 '??' (0) | 2023.07.12 |
댓글