함수를 변수에 할당하는 형태로 사용하는 방법.
이름이 없는 익명 함수를 사용할 수도 있고, 이름이 있는 명명된 함수를 사용할 수도 있음.
함수 표현식은 실행 흐름이 해당 함수 표현식에 도달했을 때 평가되어 함수가 생성됨.
이점이 함수 선언문(Function Declaration)과 다른 점이며,
함수 선언은 코드의 어디에서든 호출할 수 있는 반면, 함수 표현식은 선언 이후에만 호출할 수 있음
기본문법
익명 함수표현 : let 변수이름 = function(매개변수) { 함수 본문 };
명명된 함수표현 : let 변수이름 = function nameFunction(parameters) { 함수 본문 };
function sayHi() {
console.log("Hello");
}
console.log(sayHi);
// 함수 코드가 보임
//ƒ sayHi() {
// console.log( "Hello" );
//}
위 코드에선 함수 소스 코드가 문자형으로 바뀌어 출력됨.
자바스크립트에서는 함수는 값. 다만 sayHi()처럼 호출 할 수있는 특별한 종류의 값임.
function sayHi() { // (1) 함수 생성
console.log("Hello");
}
let func = sayHi; // (2) 함수 복사
func(); // Hello // (3) 복사한 함수를 실행(정상적으로 실행됩니다)!
sayHi(); // Hello // 본래 함수도 정상적으로 실행됩니다.
함수선언을 이용해 sayHi라는 변수에 함수값을 넣음.
func라는 변수선언후에 sayHi함수의 참조를 할당. func와 sayHi는 동일한 함수를 가리키게됨.
만약 여기서 sayHi()함수호출을 넣는다면 의미가 달라짐.
함수 그자체가 아니라 함수의 호출 결과값을 반환해서 넣어지기때문.
sayHi() 상태는 현재 어떠한 값도 return하지 않으므로 undefined임. 따라서 func에 undefined가 할당됨.
let sayHi = function() {
console.log( "Hello" );
};
let func = sayHi;
func(); // Hello
sayHi(); // Hello
함수선언문을 함수표현식으로 바꾼것. 결과는 같음.
함수 선언문 : 코드의 어느 위치에서든지 호출할 수 있음.
자바스크립트는 스크립트를 실행하기 전, 준비단계에서 전역에 선언된 함수 선언문을 찾고,
해당 함수를 생성하기때문.
함수 표현식 : 실제 실행 흐름이 해당 함수에 도달했을 때 함수를 생성.
따라서 함수 표현식으로 정의된 함수를
그 함수가 코드 상에서 선언되기 전에 호출하려고 하면 오류가 발생
//함수선언문
sayHi("John"); // Hello, John
function sayHi(name) {
console.log( `Hello, ${name}` );
}
//함수표현식
sayHi("John"); // error!
let sayHi = function(name) {
alert( `Hello, ${name}` );
};
함수선언문을 이용해 함수 선언하는것을 먼저 고려하는게 좋음.
코드구성도 자유로워지고 가독성도 좋아짐.
그럼 함수표현식은 언제 쓰는거지?
스코프(scope)?
JavaScript에서 스코프는 변수와 함수가 접근 가능한 범위를 뜻함.
함수 선언문을 사용할 때, JavaScript는 엄격 모드('use strict')에서
코드 블록 내에 선언된 함수에 대해 블록 스코프(block scope)를 적용.
=해당 함수가 선언된 블록 내에서만 접근 가능함을 의미
만약 함수가 if문, for문, 또는 다른 코드 블록 내에 선언되었다면,
그 함수는 블록 외부에서는 접근할 수 없음.
반면, 함수 표현식은 변수에 함수를 할당하는 방식으로 동작함.
밑에 예시를 보자.
let age = prompt("나이를 알려주세요.", 18);
// 조건에 따라 함수를 선언함
if (age < 18) {
function welcome() {
alert("안녕!");
}
} else {
function welcome() {
alert("안녕하세요!");
}
}
// 함수를 나중에 호출합니다.
welcome(); // Error: welcome is not defined
함수 선언문은 함수가 선언된 코드 블록 안에서만 유효하기 때문에 에러가 발생.
그럼 welcome함수를 if문 밖에서 호출 할 수있는 방법은?
let age = prompt("나이를 알려주세요.", 18);
let welcome; //전역 변수로 welcome을 선언.
if (age < 18) {
welcome = function() {
alert("안녕!");
};
} else {
welcome = function() {
alert("안녕하세요!");
};
}
welcome(); // 제대로 동작합니다.
삼항연산자로 좀더 간결하게 표현도 가능하다.
let age = prompt("나이를 알려주세요.", 18);
let welcome = (age < 18) ?
function() { alert("안녕!"); } :
function() { alert("안녕하세요!"); };
welcome(); // 제대로 동작합니다.
다른 함수에 인자로 전달되는 함수.
주로 비동기 작업이 완료된 후 실행되어야 하는 작업을 정의할 때 사용.
예를 들어, 서버로부터 데이터를 받아온 후 그 데이터를 처리해야 하는 경우,
데이터 로딩이 완료된 시점을 알 수 없기 때문에
콜백 함수를 사용하여 데이터가 성공적으로 로드된 후에 실행될 로직을 정의할 수 있음.
function doSomething(callback) {
// 무언가 작업을 수행
// ...
callback(); // 콜백 함수 호출
}
function myCallbackFunction() {
console.log('콜백 함수가 실행되었습니다.');
}
doSomething(myCallbackFunction);
두개의 함수가 정의됨. doSomething과 myCallbackFunction.
doSomething은 callback이라는 하나의 인자를 받음.
doSomething(myCallbackFunction);으로 함수가 호출되면서 callback매개변수에 myCallbackFunction
함수가 인자로 전달됨.
doSomething함수 내부에서 callback()코드에 의해 callback인자로 전달받은
myCallbackFunction함수를 실행함.
function fetchData(callback) {
const data = "데이터"; // 예시를 위한 가상의 데이터
callback(data); // 콜백 함수를 호출하며 데이터 전달
}
function processData(data1) {
console.log('받은 데이터:', data1);
}
fetchData(processData);
두개의 함수가 정의됨. fetchData와 processData.
이번엔 두개모두 각각 callback과 data1이라는 하나의 매개변수를 받음.
fetchData(processData); 호출되면 fetchData의 callback인자로 processData함수가 전달됨.
fetchData 안에서 상수 data선언이 되고 data는 콜백함수(현재processData)의 매개변수로 전달됨.
그래서 processData 매개변수(data1)로 data값("데이터")이 전달됨.
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
function showOk() {
alert( "동의하셨습니다." );
}
function showCancel() {
alert( "취소 버튼을 누르셨습니다." );
}
// 사용법: 함수 showOk와 showCancel가 ask 함수의 인수로 전달됨
ask("동의하십니까?", showOk, showCancel);
일단 컨핌(confirm)을 짚고넘어가면 내장함수중 하나로
사용자에게 대화상자를 표시하여 '확인' 또는 '취소'중 하나를 선택하게함.
사용자가 선택한 결과에 따라 불리언(boolean)값을 반환. 확인은 true를, 취소는 false를 반환함.
세개의 함수가 정의됨 ask,showOk,showCancle.
ask는 3개의 매개변수(question,yes,no)를 가지고 있음.
ask("동의하십니까?", showOk, showCancel); 호출하면 confrim으로 사용자에게 선택을 받음.
만약에 confirm으로 받은 값이 확인(true)면 yes로 받은 콜백함수 showOk가 출력되고,
confiem으로 받은 값이 취소(false)면 else를 반환, no로 받은 콜백함수 showCancel이 출력됨.
함수 표현식보다 간결하게 함수를 작성할 수 있으며, this 바인딩 방식도 다름
기본문법
(매개변수1, 매개변수2, ..., 매개변수N) => { 함수 본문 }
let func = function(arg1, arg2, ...argN) {
return expression;
};
위의 함수 표현식을 화살표함수로 바꾸면
let func = (arg1, arg2, ...argN) => expression
매개변수 arg1,arg2,argN을 받는 함수 func는
화살표 => 우측의 표현식을 평가하고 평가결과를 반환함.
this 바인딩?
function showName() {
console.log(this.name);
}
const person = {
name: '홍길동',
showName1: showName
};
person.showName1(); // "홍길동"
showName함수는 전역함수지만 person 객체의 showName1메서드의 값으로 할당됨.
person.showName1();을 호출하면 showName함수내의 this는 person객체를 가리키게 되어
홍길동을 호출함.
let showName = () => {
console.log(this.name);
}
const person = {
name: '홍길동',
showName1: showName
};
person.showName1(); // "빈문자열 or 다른결과..."
화살표 함수는 자신이 정의된 시점의 this를 상속받음.
showName은 전역 스코프에서 선언되었으므로, this는 전역 객체를 가리킴.
따라서, person.showName1()을 호출하더라도, this.name은 person 객체의 name 속성을 참조하지 않고,
전역 객체의 name 속성을 참조하게 됨.
(어렵다ㅠ)
결론
화살표 함수는 선언된 시점의 this를 캡처하는 반면, 일반 함수는 호출된 컨텍스트의 this를 사용.
따라서, 화살표 함수를 사용할 때는 this가 예상과 다르게 바인딩될 수 있으므로 주의가 필요