ㅁ 함수 작성 방법
(1) 함수 선언식
function name() { }
(2) 함수 표현식
const 변수 = function( 매개변수 ) { 실행내용 }
(3) 화살표 함수
- 함수 표현식의 간결한 대안.
- 프론트엔드를 전문적으로 쓰지 않는 회사는 잘 쓰지 않지만, 프론트엔드를 전문적으로 쓰는 회사는 무조건 화살표 함수로 쓴다.
const 변수 = ( 매개변수 ) = > { 실행내용 }
ㅁ (1) 함수 선언식
- 함수 이름을 결정해서 함수를 정의하는 방식. (기명함수)
- 함수 선언은 호이스팅(hoisting)이 되므로(최상단으로 끌어올려지므로) 선언하는 코드 line에 상관없이 언제든 호출 가능하다.
(호출) named();
(정의) function named() { 실행내용 }
(호출) named();
- 단, 동일한 이름의 함수가 다시 정의될 경우 오류가 나지 않고 마지막 함수만 존재하게 된다.
(팀원이 이미 있는 이름의 함수인지 모르고 같은 이름으로 함수를 또 작성. 그래서 함수 선언식보단 함수 표현식이나 화살표 함수를 쓰는 것이 좋다. 동일한 이름의 함수를 만들지 못하도록. 그래도 아직까진 함수 선언식을 많이 쓴다.)
ㅁ (2) 함수 표현식
- 함수를 변수에 저장하는 방식
- 주로 익명함수를 변수에 저장한다.
- 변수를 함수처럼 호출해서 사용할 수 있다.
- 함수 표현식은 hoisting되지 않는다.
(정의) const expression1 = function() { 실행내용 }
(호출) expression1();
- (정의) const expression2 = named; // (위에서 정의한) 이미 정의되어있는 기명함수를 대입.
- 기명함수도 대입이 가능하다.
이 때 주의할 점이, 괄호를 붙이면 안 된다. 그러면 호출하는 구문이 된다. 호출이 아니라 대입해야 한다.
- 함수 표현식과 화살표 함수는 동일한 이름의 함수 중복 선언이 안 된다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2>함수 선언식 vs 함수 표현식</h2>
<script>
// (1) 함수 선언식
fnDeclare();
// 함수 선언(정의) => hoisting 된다.
function fnDeclare() {
console.log("fnDeclare()");
}
// 동일한 이름의 함수를 재선언하면 마지막 함수만 남는다.
function fnDeclare() {
console.log("붕어빵");
}
console.log("==============");
console.log("==============");
////////////////////////////////////////////////
// (2) 함수 표현식
// fnExpression1(); 함수 선언 구문 이후에 호출 구문이 와야 한다.
const fnExpression1 = function() {
console.log("fnExpression1");
}
fnExpression1(); // 함수 선언 구문 이후에 호출 구문이 와야 한다.
/*
const fnExpression1 = function() {
}
오류 발생. const가 아닌 var로 선언하더라도 중복선언 안 된다.
*/
// 이미 존재하는 기명함수 대입.
const fnExpression2 = fnDeclare;
fnExpression2(); // 붕어빵
</script>
</body>
</html>
ㅁ 인자(전달값)와 매개변수
- 함수 호출시 전달하는 값을 인자[값]이라고 한다.
이때 해당 값을 받는 매개변수를 정의해둘 수 있다.
- 매개변수 선언시는 선언키워드(var, let, const)를 사용하지 않는다.
- 전개 구문(Spread Syntax) 또는 arguments 배열을 이용해서 0개 이상의 인자(여러 개의 인자값)를 처리할 수 있다.
- 인자가 전달되지 않은 경우에 사용할 디폴트값을 지정할 수 있다. (자바에선 안 됐음)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 함수 선언식 방식
/*
function fnParamTest(param) {
}
아래 방식으로도 가능하다. */
// 함수 표현식 방식
const fnParamTest = function(param) {
console.log(param);
}
</script>
<h2>인자와 매개변수</h2>
<!-- 인자로 어떤 값이든 상관 없다. 매개변수 타입에 제한두지 않았다. -->
<button onclick="fnParamTest('이춘향');">버튼1</button>
<button onclick="fnParamTest(777);">버튼2</button>
<button onclick="fnParamTest([1, 2, 3]);">버튼3</button>
<button onclick="fnParamTest(prompt('이름 입력'));">버튼4</button>
<!-- 결국 문자열 하나가 전달된다.
확인만 누르면 빈문자열이, 취소버튼을 누르면 null이 전달된다. -->
<button onclick="fnParamTest();">버튼5</button>
<!-- 자유도가 높아서 매개변수 안줘도 된다.
전달값이 없기 때문에 값이 없어서 undefined -->
<!-- 매개변수보다 더 적은 인자 전달시 매개변수는 초기화 되지 않아 undefined -->
<button onclick="fnParamTest('러끼', '모카', '온앤온');">버튼6</button>
<!-- 매개변수 수보다 더 많은 인자 전달시 초과된 값은 무시된다.-->
</body>
</html>
- 자바스크립트는 자유도가 높아서 함수를 호출할 때 매개변수 안줘도 된다. 그러면 전달값이 없으니 undefined.
- 매개변수 수보다 더 적은 인자 전달시 부족한 값은 undefined.
- 매개변수 수보다 더 많은 인자 전달시 초과된 값은 그냥 무시된다.
ㅁ 전개구문 테스트
- ...args : 전개연산자
args는 배열이다. 그래서 인덱스로 접근 가능하다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 전개구문 테스트
const fnSpreadTest = function(...args) { // ...args : 전개연산자
console.log(args); // args는 배열이다. 그래서 인덱스로 접근 가능.
for(let arg of args) {
console.log(arg);
}
}
</script>
<h2>전개 구문</h2>
<button onclick="fnSpreadTest();">버튼1</button>
<button onclick="fnSpreadTest(1, 2);">버튼2</button>
<button onclick="fnSpreadTest('유니', '칸나', '리제');">버튼3</button>
</body>
</html>
ㅁ arguments 테스트
- arguments 배열은 인자값들이 담기는 배열이다.
- 매개변수가 없는 함수라도 모든 함수마다 하나씩 존재한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// arguments 테스트
const fnArgumentsTest = function() {
console.log(arguments);
for(let arg of arguments){
console.log(arg);
}
}
// 하나씩 존재하는 arguments 배열 : 인자값들이 담기는 배열
// 사실 함수마다 하나씩 존재한다.
</script>
<h2>arguments 배열</h2>
<button onclick="fnArgumentsTest();">버튼1</button>
<button onclick="fnArgumentsTest(1, 2);">버튼2</button>
<button onclick="fnArgumentsTest('유니', '칸나', '리제');">버튼3</button>
</body>
</html>
- 처음 출력된것. 속성을 이것저것 갖고 있다.
ㅁ default 처리 테스트
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// default 처리 테스트
const fnDefaultTest = function(x, y) {
console.log("x: ", x);
console.log("y: ", y);
}
</script>
<h2>default 처리</h2>
<button onclick="fnDefaultTest();">버튼1</button>
<button onclick="fnDefaultTest(1, 2);">버튼2</button>
<button onclick="fnDefaultTest('유니', '칸나', '리제');">버튼3</button>
</body>
</html>
- 매개변수 작성하는 곳에 대입연산자를 사용해서 default값 지정해본다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// default 처리 테스트
const fnDefaultTest = function(x, y=20) {
console.log("x: ", x);
console.log("y: ", y);
}
</script>
<h2>default 처리</h2>
<button onclick="fnDefaultTest();">버튼1</button>
<button onclick="fnDefaultTest(1, 2);">버튼2</button>
<button onclick="fnDefaultTest('유니', '칸나', '리제');">버튼3</button>
</body>
</html>
ㅁ 매개변수에 this 인자 전달
- 이벤트가 발생된 요소 자체를 전달하고자 할 경우, 호출하는 함수의 인자에 this를 전달하면 된다.
- 해당 함수 내에서 현재 이벤트가 발생된 요소를 제어할 수 있다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const fnClickedBtn = function(el) {
console.log(el); // el이 곧 요소객체. DOM객체. 그럼 속성에 접근 가능.
}
</script>
<h2>this 관련 전달해보기</h2>
<button onclick="fnClickedBtn(this);">버튼1</button>
<button onclick="fnClickedBtn(this);">버튼2</button>
</body>
</html>
- this는 이 버튼 요소 객체를 의미한다.
- this로 인자값을 전달하면 현재 클릭 이벤트가 발생한 버튼 요소 객체가 전달된다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const fnClickedBtn = function(el) { // el은 곧 요소객체. DOM객체. 그럼 속성에 접근 가능.
console.log(el);
el.innerHTML = "클릭됨"; // 이벤트가 발생한 요소객체를 조작할 수 있다.
}
</script>
<h2>this 관련 전달해보기</h2>
<button onclick="fnClickedBtn(this);">버튼1</button>
<button onclick="fnClickedBtn(this);">버튼2</button>
<!-- 요소 객체가 가지고 있는 value 속성 값만 전달 -->
<!-- this(현재 이벤트가 발생되는 요소객체).property 값 전달가능 -->
<input type="button" value="버튼3" onclick="fnClickedBtn(this.value)">
<input type="button" value="버튼4" onclick="fnClickedBtn(this.value)">
</body>
</html>
- "버튼1", "버튼2"가 "클릭됨"이 되었다.
- this를 인자로 보내면 이 이벤트가 발생되는 요소 객체가 전달된다.
DOM객체이므로 함수에서 받은 매개변수로 속성에 접근가능하다.
- 요소 객체가 가지고 있는 value 속성 값만 전달할 수도 있다.
ㅁ 반환 (return)
- 반환값이 존재하더라도 자바처럼 함수에 반환타입은 작성하지 않는다.
- (값을 반환하면서 함수 종료) return 값;
- (함수 강제 종료) return;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const fnReturnRanNum = function() {
// 1부터 10사이의 정수 랜덤값 반환
// 자바 : (int)(Math.random() * 10 + 1)
return parseInt(Math.random() * 10 + 1);
}
const fnOneToRanNum = function() {
// 1부터 랜덤수까지 매번 1씩 증가되는 값 출력
let random = fnReturnRanNum();
for(let i=1; i<=random; i++) {
console.log(i);
}
}
</script>
<h2>함수의 리턴</h2>
<button onclick="fnOneToRanNum();">버튼1</button>
</body>
</html>
- parseInt는 부동 소수점 숫자를 정수로 변환한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 함수도 반환 가능
const fnReturnFunc = function() {
console.log("fnReturnFunc이 호출되었다.");
return function() {
console.log("fnReturnFunc호출시 반환되는 함수가 실행되었다.");
}
}
</script>
<h2>함수의 리턴</h2>
<button onclick="fnReturnFunc();">버튼2</button>
</body>
</html>
- 함수가 반환되긴 했지만 반환된 함수가 실행되진 않았음.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 함수도 반환 가능
const fnReturnFunc = function() {
console.log("fnReturnFunc이 호출되었다.");
return function() {
console.log("fnReturnFunc호출시 반환되는 함수가 실행되었다.");
}
}
</script>
<h2>함수의 리턴</h2>
<button onclick="fnReturnFunc()();">버튼2</button>
</body>
</html>
- 반환되는 함수를 실행시키고자한다면 괄호를 한번더 열고 닫으면 된다.
ㅁ 익명함수 실행시키기
function() {
console.log("익명함수입니다.");
}
- script에 익명함수만 덜렁 둘 순 없다. 익명함수는 어딘가에 대입하거나 전달하거나 반환할 때 사용해야 한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 익명함수 자체를 실행시키고자 한다면 괄호 열고닫고 또 괄호열고 닫기.
( function() {
console.log("익명함수입니다.");
} ) ( );
</script>
</body>
</html>
- 그런데 이렇게 괄호로 감싸고 또 괄호로 열고 닫으면 익명함수를 바로 실행시켜볼 수 있다.
ㅁ 함수의 중첩
- 자바에서는 메소드 안에 메소드 못 쓰지만, 자바스크립트에서는 함수 안에 함수를 선언할 수 있다.
- 함수 내부에서 사용할 또다른 함수를 선언할 수 있다.
- 외부함수는 내부함수의 변수를 사용할 수 없다.
내부함수는 외부함수의 변수를 사용할 수 있다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function fnOuter(a) {
console.log("fnOuter()", a); // 문자열이다.
fnInner(a+1);
// 함수 내에서 자주 사용할 구문을 함수로 선언해두기
function fnInner(b) { // hoisting되어서 fnOuter 내에서는 어디서든 fnInner함수 호출 가능하다.
console.log("fnInner()", a, b); // 내부함수에서는 외부함수의 변수를 쓸 수 있다.
}
// console.log(b); // 오류. b is not defined. 외부함수에서는 내부함수의 변수 사용 불가능.
}
</script>
<h2>함수의 중첩</h2>
<button onclick="fnOuter(10);">버튼</button>
</body>
</html>
ㅁ (3) 화살표 함수
- 이걸 몰라도 웹개발하는데 크게 문제가 되진 않지만 요즘 트렌드다.
- 람다 함수라고도 표현한다.
- 함수 표현식의 간결한 대안 (기존에 작성했던 익명함수를 화살표 함수로 표현 가능)
- 가독성을 높이고 간단하게 표현이 가능하다.
- 화살표 함수에서는 arguments(배열)를 지원하지 않는다.
const arrow = ( 매개변수 ) = > { 실행내용 }
- 단일 매개변수일 경우 소괄호( ) 생략 가능
- 단일 실행문일 경우 중괄호{ } 생략 가능
- 별도의 실행내용 없이 결과값 반환만 존재할 경우 { }, return 생략 가능
- 예시
( ) => 단일실행문
param => 단일실행문
(param) => return할 값 // 소괄호 없어도 됨. return도 없어도 됨
(param1, param2) => { 실행내용 return 결과값; } // 매개변수 여러개면 반드시 괄호로 묶어야 함.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 기존 익명함수를 통한 함수 표현식
const fnExp1 = function() { console.log("fnExp1"); }
const fnExp2 = function(a) {
console.log("fnExp2");
console.log(a);
}
const fnExp3 = function(a, b) {
console.log("fnExp3");
console.log(a, b);
return a+b;
}
const fnExp4 = function(a, b) { return a+b; }
// 위의 내용들을 화살표 함수로 작성
const fnArrow1 = () => console.log("fnArrow1"); // 단일실행문은 { } 생략가능
const fnArrow2 = a => { // 단일 매개변수는 ( ) 생략가능
console.log("fnArrow2");
console.log(a);
}
const fnArrow3 = (a, b) => {
console.log("fnExp3");
console.log(a, b);
return a+b;
}
const fnArrow4 = (a, b) => a+b;
</script>
<h2>화살표 함수</h2>
<button onclick="fnArrow1();">fnArrow1</button>
<button onclick="fnArrow2(10);">fnArrow2</button>
<button onclick="fnArrow3(10, 5);">fnArrow3-1</button>
<button onclick="console.log(fnArrow3(10, 5));">fnArrow3-2</button>
<button onclick="fnArrow4(10, 5);">fnArrow4-1</button>
<button onclick="console.log(fnArrow4(10, 5));">fnArrow4-2</button>
</body>
</html>
- return한 값을 콘솔에 출력하고 싶다면 onclick="console.log( fnArrow3(10,5) );"
- 4-1은 버튼 눌러도 콘솔에 아무것도 안 뜸.
ㅁ 화살표 함수는 arguments(배열) 사용 불가
- 전개 연산자 ...agrs 써야 한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 화살표함수 사용시에는 arguments 사용 불가 (전개연산자를 사용해야 한다)
const fnArrow5 = () => console.log(arguments);
const fnArrow6 = (...args) => console.log(args);
</script>
<h2>화살표 함수</h2>
<button onclick="fnArrow5(1, 2, 3);">fnArrow5</button> // 오류 발생
<button onclick="fnArrow6(1, 2, 3);">fnArrow6</button>
</body>
</html>