🎋

5. 함수

Index

5. 함수

5.1 함수

 
함수는 입력, 출력, 기능을 하나로 묶어 재사용 할 수 있도록 만드는 것입니다. 자바스크립트는 실행 코드들이 들어있는 독립 블록 단위객체인 함수를 사용할 수 있습니다. 여기서 객체란 데이터와 그 데이터를 포함한 모든 동작에 대해 말합니다.
<!-- 함수 --> <p id="result"></p> <script> function myFunction(x,y){ //함수의 정의 z = x + y //함수의 기능 return z; //함수의 결과값 } // 함수의 호출 document.getElementById("result").innerHTML = myFunction(4,3); </script>
 
 
 
notion imagenotion image
 
 
함수는 기본적으로
 
function( ) { };
 
형태의 구조를 가집니다.
notion imagenotion image
 
소괄호()내에는 매개변수와 중괄호 {}내에는 실행코드와 return(결과) 값을 가지고 있습니다. 함수를 호출 하기 위해서는 선언된 함수의 매개변수 값을 인수로 전달합니다.
myFunction으로 선언된 함수에 인수로 4, 3을 전달하면 함수내 실행코드의 결과값인 7일을 출력 할 수 있습니다.
 
notion imagenotion image
 
 
<button type="button" onclick="test();"name="button">클릭!!</button>
// 함수 // 참고 : function은 python에 def과 같습니다. // 읽어볼만한 문헌 : https://ko.javascript.info/function-basics //함수선언 function circleWidth(r){ let width = r*r*3.14; return undefined; } document.write(circleWidth(10)); //함수호출 function test(){ document.write('hello world!!'); }
 

5.2 지역변수 전역변수

let z = 100; function sum(x){ //x는 매개변수(parameter)이면서 지역변수(local val) let y = 50; //y는 지역변수 z = z + y; return x + y; } document.write(sum(10));//10은 전달인자(argument) document.write('<br>'); document.write(z); //키워드로 인해 전역, 지역이 갈리는 것은 아닌지, let, var, const 모두 테스트 필요
  • 지역변수는 어디까지 가능한지
 

5.3 화살표 함수

// 읽어볼만한 문헌 : https://ko.javascript.info/arrow-functions-basics function sum(x, y){ return x + y; } let sumArrowFunction = (x, y) => x + y; document.write(sum(10, 20)); document.write('<br>'); document.write(sumArrowFunction(10, 20));
 
 

5.4 함수의 다양한 형태

// 함수 선언문 function sum(x, y){ return x + y; } //함수 표현식 let sumXY = function(x, y){ return x + y; }; // let x = 10; // let y = x; let sumXYcopy = sumXY; document.write(sumXYcopy(10, 20), '<br>'); //콜백함수 function sum(x, y, c){ c(x + y); return x + y; } function documentWrite(s){ document.write('콜백함수', s); } sum(10, 20, documentWrite);
 

5.5 함수의 호이스팅

<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> </head> <body> <script> // 참고자료 : https://hanamon.kr/javascript-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85%EC%9D%B4%EB%9E%80-hoisting/ // JS의 모든 선언은 호이스팅(선언이 먼저 메모리에 저장)이 일어납니다. // 그러나 let, const, class 이용한 선언문은 호이스팅이 되었지만 안된 것처럼 동작 // 이러한 현상은 일시적 사각지대(Temporal Dead Zone)에 빠지기 때문 // 중요한 포인트는 그렇다하여 호이스팅이 안된 것은 아니라는 것! // 오류가 나는 이유는 var 키워드는 선언과 함께 undefined로 초기화 // let과 const는 초기화 되지 않는 상태로 선언만 메모리 저장 console.log(add1(10, 20)); // 30 console.log(add2(10, 20)); // 30 console.log(mul1) // undefined // console.log(mul1(10, 20)); // not a function // console.log(mul2); // Cannot access 'mul2' before initialization // console.log(mul2(10, 20)); // 위와 같은 애러 // console.log(mul3) // mul3 is not defined, 호이스팅이 안되었기 때문 function add1(x, y) { return x + y; } function add2(x, y) { return x + y; } var mul1 = function (a, b) { return a * b; } let mul2 = function (a, b) { return a * b; } </script> </body> </html>
 

5.6 재귀함수

  1. 종료조건 체크
  1. 반복문으로 구현할 수 있는 것은 재귀함수로 모두 구현 가능, 재귀함수로 구현 가능한 것은 반복문으로 대부분 구현(복잡도를 증가시키면 모두) 가능합니다.
function factorial(n){ if(n <= 1) { return n } return n * factorial(n-1) } // factorial(5) == 5 * factorial(4) == 5 * 24 // factorial(4) == 4 * factorial(3) == 4 * 6 // factorial(3) == 3 * factorial(2) == 3 * 2 // factorial(2) == 2 * factorial(1) == 2 * 1 // factorial(1) == 1
function sigma(n){ if(n <= 1) { return n } return n + sigma(n-1) } // sigma(5) == 5 + sigma(4) == 5 + 10 // sigma(4) == 4 + sigma(3) == 4 + 6 // sigma(3) == 3 + sigma(2) == 3 + 3 // sigma(2) == 2 + sigma(1) == 2 + 1 // sigma(1) == 1
function reverse(text) { text += '' if(text.length <= 1) { return text } return reverse(text.slice(1)) + text[0] } // reverse('hello') == reverse('ello') + 'h' == 'olle' + 'h' // reverse('ello') == reverse('llo') + 'e' == 'oll' + 'e' // reverse('llo') == reverse('lo') + 'l' == 'ol' + 'l' // reverse('lo') == reverse('o') + 'l' == 'o' + 'l' // reverse('o') == 'o'
// 1, 1, 2, 3, 5, 8, 13, 21 function fib(n){ if(n <= 2) { return n } return fib(n-1) + fib(n-2) } // 왼쪽 function만 따라갔으니 // fib(4) == fib(3) + fib(2) // fib(3) == fib(2) + fib(1) == 3 // fib(2) == 2 // fib(1) == 1 // 오른쪽 값인 fib(2)를 다시 해야하는 상황!! // fib(2) == 2
// 호출되는 것이 메모리를 차지하고 있으므로 아래 기법을 적절히 믹싱해서 사용할 필요가 있음 // 반복문, 다이나믹 프로그래밍(메모이제이션(하향식), 타뷸레이션(상향식)) let fibo_cache = [] function fibo(n){ if (n in fibo_cache) { return fibo_cache[n] } fibo_cache[n] = n < 2 ? n : fibo(n-2) + fibo(n-1) return fibo_cache[n] } // fibo_cache = [0, 1, 1, 2, fibo(2) + fibo(3)] // fibo(4) == fibo_cache[4] == fibo(2) + fibo(3) // fibo(2) == fibo_cache[2] == fibo(0) + fibo(1) // fibo(0) == fibo_cache[0] == 0 // fibo(1) == fibo_cache[1] == 1 // fibo(3) == fibo_cache[3] == fibo(1) + fibo(2) // fibo(1) == 1 // fibo(2) == 1
// 정리시간에 한 번 해보세요! :) function comma(text) { text += '' if(text.length <= 1) { return text } return text.slice(0, 3) + ',' + comma(text.slice(3)) }
 

5.7 즉시 실행함수

  1. 즉시 실행하고 외부에서 컨트롤 할 필요가 없는 함수
  1. function scope, 메모리 효율
// 익명 즉시 실행 함수 (function () { let a = 1; let b = 2; return a + b; }()); // 기명 즉시 실행 함수 (function foo() { let a = 3; let b = 5; return a * b; }()); foo(); // ReferenceError: foo is not defined // 어차피 실행하지 못해서 의미가 없음. // 메모리 효율적으로 관리하기 위해 바로 실행해야 하는 것들을 즉시 실행함수로 관리
 

 
let data = [{ 반 : 1, 번 : 1, 이름 : "호준", 중간고사점수 : 55 }, { 반 : 1, 번 : 2, 이름 : "길동", 중간고사점수 : 60 }, { 반 : 1, 번 : 3, 이름 : "영희", 중간고사점수 : 30 }, { 반 : 1, 번 : 4, 이름 : "철수", 중간고사점수 : 20 }, { 반 : 1, 번 : 5, 이름 : "규리", 중간고사점수 : 100 }] console.log(data.map(x => x.중간고사점수)) console.log(data.map(x => [x.이름,x.중간고사점수]))
 

 
let data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; let newData = data.map(a => a.map(n => n * 2));
 

5.8 call by value, reference, sharing

  • javascript는 call by value만 존재한다. 참조타입을 넘기면 주소가 넘어가는 것이 아니라 주소값을 복사한 복사본이 넘어간다.
 
  • call by reference인 것 처럼 보이지만 js에서는 call by value (주소가 넘어가는 것이 아니라 주소가 복사가 되어 넘어감)
  • 다른 언어에서는 call by reference
  • 해당되는 자료형 : Object, Array, function
let array = [100, 200, 300]; function test(a) { a[0] = 1000; } test(array) array
 
  • 원래 call by value, js에서도 call by value
  • 재할당 되는 순간에는 다른 값을 가리킴
  • 해당되는 자료형 : Number, String, boolean, null, undefined
let v = 100; function test(a) { a = 1000; } test(v) v
 
  • 아래와 같은 특징 때문에 js에서는 call by sharing이라 얘기합니다. (C와 C++에서는 a가 1000이 됩니다.)
var a = {}; function test(b) { b = 1000; } test(a) a
 

5.8 클로저(Closure)

아래 예제에서는 add5, add10이 클로저입니다. 폐쇠된 공간 안에 데이터에 접근하기 위한 테크닉입니다.
  • 폐쇠된 공간 안에 데이터에 접근하기 위한 테크닉
  • 내부 함수의 외부 함수 접근(권한) 테크닉
그러면 왜 사용할까요? 변수 은닉과 메모리 효율, 코드 효율(또는 완전성)을 극대화하기 위해 사용합니다.
function makeAdder(x) { var y = 1; return function(z) { y = 100; return x + y + z; }; } var add5 = makeAdder(5); var add10 = makeAdder(10); //클로저에 x와 y의 환경이 저장됨 console.log(add5(2)); // 107 (x:5 + y:100 + z:2) console.log(add10(2)); // 112 (x:10 + y:100 + z:2) //함수 실행 시 클로저에 저장된 x, y값에 접근하여 값을 계산
function 제곱(x) { function 승수(y) { return y ** x } return 승수 } var 제곱2 = 제곱(2); var 제곱3 = 제곱(3); 제곱2(10) 제곱3(10)
function 제곱(x) { return function(y) { return y ** x } } var 제곱2 = 제곱(2); var 제곱3 = 제곱(3); 제곱2(10) 제곱3(10)
 

 
함수 내부에서 선언해야 합니다. 호출된 위치는 상관 없습니다.
const x = 100; function a() { const x = 1; b(); } function b() { console.log(x); } a(); // 100 b(); // 100 // 비교대상 const xx = 100; function a() { const xx = 1; function b() { console.log(xx); } b(); } a();
 

 
아래 debugger를 통해 closure 확인 가능.
 
function 제곱(x) { function 승수(y) { debugger; return y ** x; } return 승수; } var 제곱2 = 제곱(2); var 제곱3 = 제곱(3); 제곱2(10); 제곱3(10);
 

5.8 생성자 함수

 
  • 생성자 함수와 일반 함수에 기술적 차이 없음
  • 함수 이름 첫 글자는 대문자로 시작
  • 반드시 'new' 연산자를 붙여 실행
  • 모든 함수는 생성자 함수가 될 수 있기 때문에 관습을 지킵시다!
 
// 모던 자바스크립트 예제 function User(name) { this.name = name; this.isAdmin = false; } let user = new User("보라"); console.log(user.name); // 보라 console.log(user.isAdmin); // false
 
  • 둘 다 호준이 나오지만, 일반 함수는 밖에서 user.name이 안됨.
function User(name) { this.name = name; console.log(this.name); } let user = User("호준");
function User(name) { this.name = name; console.log(this.name); } let user = new User("호준");