Index
Index5. 함수5.1 함수 5.2 지역변수 전역변수 5.3 화살표 함수5.4 함수의 다양한 형태5.5 함수의 호이스팅5.6 재귀함수5.7 즉시 실행함수5.8 call by value, reference, sharing5.8 클로저(Closure)5.8 생성자 함수
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>

함수는 기본적으로
function( ) { };
형태의 구조를 가집니다.

소괄호()내에는 매개변수와 중괄호 {}내에는 실행코드와 return(결과) 값을 가지고 있습니다. 함수를 호출 하기 위해서는 선언된 함수의 매개변수 값을 인수로 전달합니다.
myFunction으로 선언된 함수에 인수로 4, 3을 전달하면 함수내 실행코드의 결과값인 7일을 출력 할 수 있습니다.

<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 재귀함수
- 종료조건 체크
- 반복문으로 구현할 수 있는 것은 재귀함수로 모두 구현 가능, 재귀함수로 구현 가능한 것은 반복문으로 대부분 구현(복잡도를 증가시키면 모두) 가능합니다.
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 즉시 실행함수
- 즉시 실행하고 외부에서 컨트롤 할 필요가 없는 함수
- 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("호준");