JS. 함수

MJ·2022년 8월 26일
0

Java Script

목록 보기
23/57
post-thumbnail

함수?

  • 코드를 저장해서 필요한곳에 호출해 사용할 수 있다.

  • 반복적인 작업이 간소화되며 가독성이 좋아집니다.

  • 브라우저상에서 자주 호출되는 함수는 alert prompt confirm등이 있습니다.

  • 함수 또한 객체이며, 일급객체로 분류되고 일반적인 객체와 다른 점은 호출이 가능.


1.1 함수 선언문(생성)

  • 함수를 직접 생성해서 사용할 수 있습니다. 이는 함수 선언문이라고 합니다.
❤️ 문법

function showMessage() {	// 키워드(function) 함수이름(showMessage) 매개변수() 현재 없음
 alert('안녕하세요!'); 		// 함수 본문 ( 함수를 호출하면 작동하는 코드 )
}


/* */
함수 선언 방식 : function(키워드), 함수 이름, (매개변수), { 함수 본문 } 

function : 함수를 선언하는 키워드 ( 변수를 선언하는 let과 동일하다 )
함수 이름 : 함수에 이름을 정해줍니다 ( 변수명과 동일하다 )
매개 변수 : 함수를 호출할 때 인수값을 인자로 받는 변수, 값들은 컴마로 구분한다.
함수 본문 : 함수를 호출할 때, 실행되는 코드들이 여기에 포함된다.

❤️ 함수 사용

function showMessage() {
 alert('안녕하세요!'); 
}

showMessage();
showMessage();


/* */
showMessage()
1) showMessage 라는 함수를 호출합니다.
2) 함수를 호출하면, 함수본문에 있는 코드가 실행됩니다.
3) 2번 호출 하였으므로, 함수본문에 있는 alert('안녕하세요!')2번 출력됩니다.

코드 확인

함수의 장점은 중복처리되는 코드를 정의해서 간단하게 사용할 수 있습니다.


1.2 hoisting

  • 함수는 호이스팅 특성으로 인해, 어떤 코드라인에서 선언하든지 항상 코드의 최상단에
    선언된 것으로 간주 됩니다.

  • 함수를 선언하기 이전에 호출해도 문제가 발생하지 않는다.
    호이스팅 참조

  • 함수 선언문에만 해당되며, 함수 표현식에서는 호이스팅이 발생하지 않습니다.

hoisting();
hoisting();

function hoisting(){
	console.log('호이스팅 !');
}


/* 
함수를 선언하기 이전에 호출해도, 함수가 선언되면 코드를 실행하기 이전에 검사하는 과정에서
함수를 코드의 최상단 부분으로 끌어 올리므로 사실상 선언이 호출보다 읽히게 됩니다.


* 호이스팅으로 인해, 함수 선언부분이 코드의 최상단 부분으로 올라간다 *
function hoisting(){
	console.log('호이스팅 !');
}

hoisting();
hoisting();

*/

1.3 지역 변수(local variable)

  • 함수 내에서 선언한 변수를 지역변수라고 합니다.

  • 지역 변수는 함수 내부에서만 접근할 수 있습니다.

❤️ 지역변수 

function showMessage () {
 let message = "지역변수 입니다";
 alert(message);
}

showMessage();		//  '지역변수 입니다' 출력

alert(message);		// 코드 오류


/* 
showMessage() 함수 내부에서 선언된 message 변수는 지역변수라고 합니다.
함수 내부에서 선언된 변수는, 함수 밖을 벗어나면 사용할 수 없습니다.

함수 밖에서 let message; 라고 변수를 선언하면 이는 지역변수와는 완전하게 다른
변수입니다.
*/

1.4 전역 변수(outer variable)

  • 함수 밖에 있는 변수를 전역변수 또는 외부변수라고 합니다.

  • 함수 내부에서 전역 변수를 호출해서 수정할 수 있습니다.

❤️ 전역변수

let userName="John";	// 전역 변수

function showMessage () {
  
 let message ="Hello" + userName;	// 함수 내부에서 전역변수를 호출
 alert(message); 	
  
}

showMessage();		// Hello John이 출력 됨

❤️ 전역변수를 함수 내부에서 수정하기

let userName="John";		// 전역변수

function showMessage() {
 
  userName = "Eunji";		// 전역 변수 UserName을 호출하고 수정할 수 있다.
  let message = "Hello" + userName;
  
  alert(message);			// Hello EunJi가 출력 됩니다.
  	
}

alert(userName)	// 함수 호출 전, John이 출력 됩니다.

showMessage()	// Hello Eunji가 출력 됩니다.

alert(userName)	// 함수 호출 이후, 함수에서 수정된 전역변수가 호출됩니다 (EunJi)


/* */
1) 전역에 설정된 전역 변수를 함수에서 호출해서 사용할 수 있다. 
2) 전역변수를 호출해서 수정하면, 전역 변수의 데이터도 수정된다.

❤️ 전역변수와 지역변수명이 동일할 때

let userName = 'John ';

function showMessage () {
 let userName = 'BoB';		// 외부변수명과 동일하기에, 지역변수가 덮어 씌웁니다. 
 let message = "Hello" + userName;	
  
 alert(message);			// Hello BoB
}

alert(userName)				// John 출력
showMessage();				// Hello BoB 출력

alert(userName)				// John 출력 ( 지역변수가 전역변수를 덮어씌웠기에, 전역변수의 값이 변경되지 않았습니다 )


/* */
1) 전역변수와 지역변수의 변수명이 똑같다면 서로 다른 변수가 된다.
2) 서로 다른 변수기에 함수에서 전역변수를 수정할 수 없다.

1.5 매개변수 (parameter)

  • 함수 밖에서 함수를 호출할 때, 실제 데이터가 있는 인수(argument)를 함수에게 전달할 수
    있습니다.

  • 함수는 인수를 전달받기 위해 매개변수(인자)를 생성해서 값을 저장합니다.

  • 인수를 전달받는 인자를 매개변수라고 합니다.

❤️ 매개변수 (인자)

function showMessage(from, text) { 		// 인자 : from, text
  alert(from + ': ' + text);
}

showMessage('Ann', 'Hello!'); 			// 인수 : 'Ann' 'Hello'
showMessage('Ann', "What's up?"); 		// 인수 : 'Ann' 'What's up?'


/* 
1. 본문에서 인수값을 전달해서 함수를 호출.
2. 함수는 인수값을 전달받을 매개변수를 생성
3. alret 메서드에 매개변수를 호출합니다.
4. from과 text 매개변수에 실제로 저장되있는 인수값을 사용합니다.
5. 출력 : 'Ann: Hello!' , 'Ann: What"s up?'
*/

/* 
array.index('h') 같이 메서드에서도 인수가 사용됩니다 ( 여기서 인수는 'h' )
*/

❤️ 매개변수는 인수를 복사해서 사용한다.

function showMessage(from, text) {	// 매개변수 from, text

  from = '*' + from + '*'; 			// from = *Ann*, 매개변수 수정 

  alert( from + ': ' + text );		// *Ann*: Hello 출력
}

let from = "Ann";					// 전역변수 from 선언 

showMessage(from, "Hello");			// 함수호출, 인수로 전역변수 from과 "Hello" 전달


alert( from ); 						// Ann 출력, 바뀌지 않는다.


/* 
from이라는 전역변수를, 함수에서 매개변수로 받아오는 것이 아니라 단순하게 호출했다면
값을 수정할 수 있습니다. 하지만 매개변수로 받아오는 인수 값은 전역변수를 호출하는 것이 아닌
값을 복사해서 오는 것이므로 값을 수정해도, 원본의 인수 값은 바뀌지 않습니다.
*/

1.6 매개변수의 기본 값

  • 함수는 매개변수가 없거나, 매개변수가 인수를 전달받지 못하면 기본 값으로 undefined
    할당 합니다.

  • undefined이외의 다른 값을 기본 값으로 사용하고 싶을 때 기본 값을 정의할 수 있습니다.

❤️ 매개변수 기본 값 정의

function showMessage(from, text = "no text given") {	// 매개변수 text에 기본값을 지정
  alert( from + ": " + text );							// "Ann: no text given" 호출 됨
}

showMessage("Ann"); 		// 함수 호출, 인수를 1개만 전달합니다. 


/* */
함수에 from 매개변수는 인수를 전달받지만, text 매개변수는 인수를 전달받지 못합니다.
이 때 기본 값으로 정해놓은 "no text given"이 text 매개변수에 할당됩니다.

만약 text 매개변수도 인수를 전달 받았다면, 인수의 값으로 할당되었을 겁니다.

❤️ 매개변수의 기본 값은 함수도 가능

function showMessage(from, text = anotherFunction()) {
  // 매개변수의 기본 값을 다른 함수의 반환 값으로 할당할 수 있습니다.
  // 다른 함수의 반환 값이 text 매개변수로 할당됩니다.
}

❤️ 함수 본문에서 기본 값을 정의 할 수 있음

function showMessage(text) {
  if (text === undefined) {
    text = '빈 문자열';
  }

  alert(text);
}

showMessage(); // 빈 문자열


/* */
text 매개변수의 값이 undefined라면 (인수를 받지 못했다면) text 매개변수에 '빈 문자열' 값을 할당합니다.
때로는 함수 내부에서 매개변수의 기본 값을 설정해주는 것이 더 적합한 경우도 있습니다.


* 1. ----------------------------------------------------------------------


function showMessage(text) {
  text = text || '빈 문자열';

  alert(text);
}

showMessage(); // 빈 문자열


/* */
text 매개 변수의 값이 거짓 된 값이라면 '빈 문자열' 출력
거짓된 값 : '' 빈 문자열, null , undefined, 숫자 0


* 2. ----------------------------------------------------------------------


function showMessage(text) {
  text = text ?? '빈 문자열';		// 피 연산자가 null이나 undefined가 아니라면 반환

  alert(text);
}

showMessage(0); 	// 출력 : 0
showMessage(null);	// 출력 : '빈 문자열'
showMessage();		// 출력 : '빈 문자열'


/* */
1) text가 0이나 공백같은 빈 문자열이라면, 그 값을 text 변수에 반환
2) text가 null이나 undefined라면 '빈 문자열'이 반환 된다.

1.7 블럭 범위

  • 함수에 지역변수와 전역변수처럼, 조건문이나 반복문에서 변수를 할당하면 해당 문
    범위 밖에서는 접근할 수 없습니다.

  • 함수 var 선언자는 문단을 선언하면 반복문이나 조건문등 블럭 안에서 선언해도
    전역에서 호출해서 사용할 수 있습니다.

  • let 또는 const 선언자는 블럭 밖에서는 사용할 수 없다.

let redius = 8; 

if(radius > 0) {
	const PI = 3.14159;
	let msg = 'HIII';
}

console.log(PI);
console.log(msg);
/* 접근 불가. 오류 */
/* var 변수를 사용하면 블럭 밖에서 호출할 수 있다 */

if(radius > 0) {
	var PI = 3.14159;
	var msg = 'HIII';
}

console.log(PI);	// 3.14159
console.log(msg);	// 'HIII'



2. return 지시자

  • return을 사용하면 실행중인 명령을 즉시 종료하고, 자신을 호출한 함수로 값을 반환합니다.

  • 반환될 때 값은 한 가지의 값만 반환합니다. 여러 가지의 값을 반환하고 싶다면 배열을
    사용해야 합니다. 다만 배열도 1개여야 한다.

❤️ 형식

function sum(a, b) {		// 매개변수에서 전달받은 인수 값 저장 ( 1,2 )
  return a + b;				// a와 b를 더하고 자신을 호출한 함수에게 값을 반환합니다.
}

let result = sum(1, 2);		// 인수로 1과 2를 전달합니다.
alert( result ); 			// 출력 : 3

❤️ return 지시자의 위치는 자유롭게 사용 가능

function checkAge(age) {	// 3. 인수로 전달받은 값을 매개변수 age에 저장 (18)
  if (age >= 18) {			// 4. age(18)값은 18보다 크거나 같으므로 조건문은 참
    return true;			// 5. 함수를 즉시 종료합니다. 돌아갈 때 true값을 반환
  } else {
    return confirm('보호자의 동의를 받으셨나요?');	// 번외. 사용자가 입력값이 18보다 작다면
    											// 질문 메세지를 한 번 더 수행한다. (확인/취소)
    											// 확인을 누르면 true값이 반환, 취소를 누르면 false를 반환
  }
}

let age = prompt('나이를 알려주세요', 18);	// 1. 전역 변수 선언

if ( checkAge(age) ) {		// 2. 함수호출 ( 인수 : age 전달 ), 조건문은 checkAge 함수의 반환값으로 확인한다.
  alert( '접속 허용' );		// 5. 조건문이 참이기 때문에, '접속 허용' 메세지가 출력
} else {
  alert( '접속 차단' );		// 6. 조건문이 거짓이라면, '접속 차단' 메세지가 출력
}

❤️ return 지시자만 사용 (위 구문이랑 이어집니다)

function showMovie(age) {
  if ( !checkAge(age) ) {
    return;
  }

  alert( "영화 상영" ); // (*)
  // ...
}


/* */
showMovie 함수에서 checkAge(age)의 반환 값을 확인 합니다. !(Not) 논리 연산자로 인해서
참이라면 거짓으로, 거짓이라면 참으로 반환합니다.

만약, 거짓 값이 오면 참으로 반환되어 함수를 즉시 종료합니다. ( 영화상영 메세지 출력 X )
참의 값이 오면, 거짓으로 반환되어 조건문을 수행하지 않고, alert를 수행합니다 ( " 영화 상영 " )

❗ 즉, else절이 필요 없다.

⚠️ undefined 자료형이 반환되는 경우 두 가지

1) 매개 변수의 값이 없는 경우

function doNothing() { /* empty */ }
/
alert( doNothing() === undefined ); // true
/* 매개변수의 값이 없다면 undefined가 할당 된다 */


2) return 지시자에 반환 값이 없는 경우

function doNothing() {
  return;
}
/
alert( doNothing() === undefined ); // true
// return 지시자만 반환 할 경우에는, undefined를 반환한다. 

⚠️ return 지시자 주의사항

✔️ return 지시자를 사용해서 연산결과를 반환 값으로 가져갈 때 주의사항은
연산이 시작되는 부분은 지시자와 같은 라인에 있어야 합니다.


✔️ return 지시자는 문 끝에 자동으로 ;(세미콜론)이 붙기 때문에, 표현식을 표현하고
싶다면 표현식의 시작위치는 항상 지시자와 같은 라인에서 시작해야 합니다.


❌ 올바르지 않은 사용 법

return
( a+b )
a+b의 연산 결과를 반환으로 가져가지 않습니다. 연산의 시작 부분이 return과 다른 라인에 있기 때문에
인식하지 않습니다.


⭕ 올바른 사용 법

return (		<= 연산의 시작은 return 지시자와 같은라인에 있어야 한다.
  a + b )
a+b의 연산 결과를 반환 값으로 가져 갑니다.



3. 렉시컬 범위(lexical scope)

  • 중첩된 함수나 내부 함수는 상위 몇 레벨 위에 있던 상관없이 부모 함수나 조부모 함수등에
    있는 변수등을 접근해서 호출할 수 있습니다.

  • 다만 역으로, 중첩함수 내부에 있는 변수는 상위레벨의 함수에서는 접근할 수 없다.

function bankRobbery() {
    let herose = ['chulsu', 'Spiderman', 'Wolverine', 'Black Panther'];
    
    function cryForHelp() {
       
        function inner() {
            for (let hero of herose) {	// 중첩함수는 조부모의 배열의 접근 가능
                console.log(`${hero} HI`)
            }
        }
        inner();	// 두번째 중첩함수
    } 
    cryForHelp();	// 첫번째 중첩함수
}

bankRobbery();
/* 
출력

chulsu HI
Spiderman HI
Wolverine HI
Black Panther HI
*/

/* 중첩 함수에서 선언한 변수는, 상위 레벨의 함수에선 접근할 수 없다*/

function bankRobbery() {
    let herose = ['chulsu', 'Spiderman', 'Wolverine', 'Black Panther'];
    console.log(color);	// 오류 발생
  	
    function cryForHelp() {
       let color = 'blue';	// 중첩 함수에서 변수 선언
      
        function inner() {
            for (let hero of herose) {	
                console.log(`${hero} HI`)
            }
        }
        inner();	// 두번째 중첩함수
    } 
    cryForHelp();	// 첫번째 중첩함수
}



4. 함수 이름 짓기

  • 함수의 이름은 유의미하고 가능한 간결하게 정의해야 한다.

  • 함수는 동작과 관련된 코드의 집합체로 함수명은 동작에 관련된 이름으로 정의합시다.

함수명내용
show..show로 시작하는 함수명은, 메세지를 보여줍니다
get..무언가의 값을 반환합니다
calc..무언가를 계산합니다.
create..무언가를 생성합니다.
check..무언가를 확인하고 boolean값을 반환합니다.
showMessage(..)     // 메시지를 보여줌
getAge(..)          // 나이를 나타내는 값을 얻고 그 값을 반환함
calcSum(..)         // 합계를 계산하고 그 결과를 반환함
createForm(..)      // form을 생성하고 만들어진 form을 반환함
checkPermission(..) // 승인 여부를 확인하고 true나 false를 반환함



5. 함수 분리

  • 함수는 특정한 동작을 구현하기 위한 코드의 집합체입니다.

  • 함수에는 동작 1개만을 위한 코드를 구현하는게 좋습니다.

  • 하나의 함수에 1개 이상의 동작이 필요하다면, 함수도 1개 이상 생성해서 각 함수당 1개의
    동작만 구현할 수 있게 함수를 여러 개로 분리하는게 좋습니다.

  • 분리된 함수는 자신이 어떤 역할을 하는지 유의미한 함수명을 작성하는걸 권장합니다.

function showPrimes(n) {
  nextPrime: for (let i = 2; i <= n; i++) {

    for (let j = 2; j < i; j++) {
      if (i % j == 0) continue nextPrime;
    }

    alert( i ); // 소수
  }
}


/* */
1) 사용자가 입력한 값을 토대로, 그 값에 대한 모든 소수를 구하는 함수입니다.
2) 함수는 2가지 동작을 합니다. 사용자로부터 입력받은 값만큼 반복하는 i 반복문
   i 반복문의 값을 나눠서 소수를 구하는 j 반복문

3) 사용자가 입력한 값까지 소수를 구해야 하므로, j 반복문은 사용자가 입력한 값 까지
   반복 수행하는 i 반복문을 나누면 됩니다.

하나의 함수에서 2가지 동작을 하므로, 함수를 분리해서 구현 해보겠습니다.

----------------------------------------------------------------


let n = prompt('값을 입력하세요','');
showPrimes(n);

function showPrimes(n) {
  for(let i=2; i<=n; i++) {

    if( isPrime(i) )  alert(i);		// isprime 함수 호출, 인수 전달 (i), 반환 값이 참이라면 수행
 }

}
 
/* 첫 번째 반복문의 카운터변수를 매개변수 n로 저장해서 자신의 반복문으로 n을 반복해서 나눈다.*/
 function isPrime(n) {				
 
   for(let i=2; i<n; i++) {		// 소수를 구하는 과정

    if(n % i == 0) return false;	// n이 i로 나눠진다면 소수가 아니므로 거짓 반환

   }
   return true;	// if문이 만족하지 않으면 소수이므로 참을 반환
 }


/* */
소수는 자신과 1이외의 다른 수로 나눌 수 없는 수 입니다.1과 자신을 제외한 숫자로 나눠진다면 소수가 아닙니다. 그러므로 거짓을 반환해서
alert창이 출력되지 않게 해줍니다. => if (n % i ==0) return false;



정리

  1. 함수에 전달된 매개변수는 복사된 후, 함수의 지역변수가 됩니다.
  2. 함수는 전역변수를 호출할 수 있고, 전역에서는 함수의 지역변수를 호출할 수 없다.
  3. 함수는 값을 반환하며, return 지시자를 통해 중간에 함수를 빠져나올 수 있다.
  4. 함수에서 연산의 결과 값을 반환할 경우에는 return 지시자가 필수지만, 반환이 필요
    없는 경우라면, return을 사용하지 않아도 된다.
function sum(a,b) {
	return a+b; 		// a와 b의 덧셈결과를 반환 하려면 return이 필수다. 없으면 반환 안됨					
}

sum(1,2);


function num(value, yes, no) {
 if( value ) yes();			// alert 함수의 출력만 필요한 경우, return 필요 없음
 else no();					// 이하 동문
}

function truthy() {
  alert('나는 사람입니다');
}
  
function falsy() {
  alert('나는 사람이 아닙니다');
}
  
  
num( confirm('당신은 사람입니까?'), truthy, falsy);	// 함수 호출
profile
프론트엔드 개발자가 되기 위한 학습 과정을 정리하는 블로그

0개의 댓글