함수 표현식보다 단순하고 간결한 문법으로 함수를 만들 수 있는 방법이 존재한다.
바로 화살표 함수(arrow function)를 사용하는 것이다. 화살표 함수라는 이름은 문법의 생김새를 차용해 지어졌다. 직관적으로 이해하면 된다.
let func = (arg1, arg2, ...argN) => expression
이렇게 코드를 작성하면 인자 arg1..argN를 받는 함수 func이 만들어진다. 함수 func는 화살표(=>) 우측의 표현식(expression)을 평가하고, 평가 결과를 반환하게 된다.
아래 함수의 축약 버전이라고 할 수 있는 것이다. parameters와 expression!
let func = function(arg1, arg2, ...argN) {
return expression;
};
let sum = (a, b) => a + b;
/* 위 화살표 함수는 아래 함수의 축약 버전입니다.
let sum = function(a, b) {
return a + b;
};
*/
alert( sum(1, 2) ); // 3
보다시피 (a, b) => a + b는 매개변수 a와 b를 받는 함수이다. (a, b) => a + b는 실행되는 순간 표현식 a + b를 평가하고 그 결과를 반환하게된다.
인수가 하나밖에 없다면 인수를 감싸는 괄호를 생략할 수 있다.
괄호를 생략하면 코드 길이를 더 줄일 수 있다.
ex)
let double = n => n * 2;
// let double = function(n) { return n * 2 }과 거의 동일합니다.
alert( double(3) ); // 6
인수가 하나도 없을 땐 괄호를 비워놓으면 된다. 다만, 이 때 괄호는 생략할 수 없다!
let sayHi = () => alert("안녕하세요!");
sayHi();
화살표 함수는 삼항 연산자와 같이 결합하여 사용할 수 있다.
아래 예시와 같이 함수를 동적으로 만들 수 있다.
let age = prompt("나이를 알려주세요.", 18);
let welcome = (age < 18) ?
() => alert('안녕') :
() => alert("안녕하세요!");
welcome();
화살표 함수를 처음 접하면 가독성이 떨어지게 느껴진다. 익숙하지 않기 때문이다. 하지만 문법이 눈에 익기 시작하면 적응할 수 있다.
함수 본문이 한 줄인 간단한 함수는 화살표 함수를 사용해서 만드는 게 편리하다. 타이핑을 적게 해도 함수를 만들 수 있다는 장점이 있다. 지속적인 연습만이 살 길이다!
위에서 작성한 화살표 함수들은 => 왼쪽에 있는 인수를 이용해 => 오른쪽에 있는 표현식을 평가하는 함수들이었다
그런데 평가해야 할 표현식이나 구문이 여러개인 함수가 있을 수도 있다. 이 경우 역시 화살표 함수 문법을 사용해 함수를 만들 수 있다. 다만, 이때는 중괄호 안에 평가해야 할 코드를 넣어주어야 한다! 그리고 return 지시자를 사용해 명시적으로 결괏값을 반환해 줘야 한다.
예시)
let sum = (a, b) => { // 중괄호는 본문 여러 줄로 구성되어 있음을 알려줍니다.
let result = a + b;
return result; // 중괄호를 사용했다면, return 지시자로 결괏값을 반환해주어야 합니다.
};
alert( sum(1, 2) ); // 3
화살표 함수는 본문이 한 줄인 함수를 작성할 때 유용하다.
중괄호 없이 작성: (...args) => expression – 화살표 오른쪽에 표현식을 둔다. 함수는 이 표현식을 평가하고, 평가 결과를 반환한다.
중괄호와 함께 작성: (...args) => { body } – 본문이 여러 줄로 구성되었다면 중괄호를 사용해야한다. 다만, 이 경우는 반드시 return 지시자를 사용해 반환 값을 명시해 주어야 한다.
함수와 메서드의 차이점은 호출 방식에 따라 다르다고 할 수 있다.
함수를 호출하는 객체가 있는 경우 메서드라고 말하며, 함수를 호출하는 객체가 없는 경우 함수라고 말한다.
예제)
let obj = {
show1: function() {
console.log('show1() 메서드 호출');
}
}
function show2() {
console.log('show2() 함수 호출');
}
obj.show1(); // 메서드
show2(); // 함수
위 예제에서 show1() 함수는 객체 obj의 프로퍼티이며, obj 객체를 통해 호출했으므로 메서드이다. 반면에 show2() 함수는 객체를 생성하지 않고 직접 호출했으므로 함수이다.
위 예제에서 show2() 함수는 객체 없이 호출되는 것처럼 보이지만, 사실 show2() 함수를 호출하는 객체가 존재한다. 전역 범위에서 함수가 선언되는 경우 전역 객체인 window의 프로퍼티가 된다.
따라서, show2() 함수를 전역 범위에서 선언하는 경우 다음 예제처럼 window 객체로 호출할 수 있다.
function show2() {
console.log('show2() 함수 호출');
};
show2();
window.show2();
Chrome 개발자 도구의 콘솔 탭에서 위 예제를 실행한 결과이다. 위 예제를 보고 아래와 같은 생각을 할 수 있다.
전역 객체인 window 객체로 show2() 함수를 호출했으므로 show2() 함수는 결국은 메서드가 아닌가?
JavaScript에서 메서드라는 개념은 사용자가 정의한 객체의 프로퍼티가 함수인 경우이다. 따라서 show2() 함수는 메서드가 아니라 함수이다.
JavaScript에서 함수는 변수에 할당할 수 있으므로 함수를 변수처럼 사용할 수 있다. 즉, 메서드도 변수에 할당할 수 있다는 의미이다.
다음 예제는 obj 객체의 메서드를 변수에 할당하는 것이다.
let obj = {
show1: function() {
console.log('show1() 메서드 호출');
}
}
obj.show1(); // 메서드
let funcCall = obj.show1;
funcCall(); // 함수
변수 funcCall에 obj 객체의 show1() 메서드를 할당하였다. 따라서, funcCall은 함수처럼 사용할 수 있다.
funcCall에 메서드를 할당했지만, funcCall을 호출하는 객체가 존재하지 않으므로 funcCall은 함수이다.
함수와 메서드의 차이를 정리해보면 다음과 같다.
자바스크립트 Array.prototype
배열에서 원하는 값 또는 식별자를 찾아내는 메서드
배열을 순차 반복
find 는 인자로 받은 판별 함수를 만족하는 첫 번째 요소를 반환
findIndex 는 인자로 받은 판별 함수를 만족하는 첫 번째 식별자를 반환
indexOf 는 인자로 요소를 받아 만족하는 첫 번째 식별자를 반환
arr.find(callback(element[, index[, array]])[, thisArg])
find() 함수는
배열에서 특정 값을 찾는 조건을 callback 함수를 통해 전달하여,
조건에 맞는 값 중 첫번째 값을 리턴하게 된다.
만약 배열에 조건을 만족하는 값이 없으면 undefined를 리턴한다.
파라미터
callback(element, index, array) 함수는
조건을 비교할 callback 함수이고, 다음 3개의 파라미터가 전달된다.
callback 함수에서 사용자가 테스트할 조건을 정의하고,
만약 배열의 값이 조건에 부합하여 true를 리턴하면,
해당 배열의 값이 find() 함수의 리턴 값이 되게 된다.
조건에 부합하는 값을 찾으면, 그 이후의 배열값은 테스트되지 않는다.
element : 현재 처리중인 배열의 element입니다.
index : 현재 처리중인 배열의 index입니다. (optional)
array : find() 가 호출된 배열입니다. (optional)
리턴값
callback 함수에 정의한 조건에 부합하는 배열의 첫 번째 값을 리턴합니다.
조건에 부합하는 배열 값이 없을 경우 undefined를 리턴합니다.
const arr = [
{name: 'apple', price : 1000},
{name: 'banana', price : 2000},
{name: 'apple', price: 3000}
];
function isApple(element) {
if(element.name === 'apple') {
return true;
}
}
const apple = arr.find(isApple);
document.writeln(apple.name); // apple
document.writeln(apple.price); // 1000
find() 함수에 isApple()이라는 callback 함수를 전달하였다.
isApple() 함수는 파라미터로 입력받은 객체(element)의 name이 'apple'이면 true를 리턴하게된다.
find() 함수는 파라미터로 전달된 callback 함수가 true를 리턴하면
해당 배열의 값을 리턴하고, 더 이상 나머지 배열의 값은 callback 함수로 전달하지 않는다.
결국, find() 함수는 callback 함수에 정의된 조건에 부합하는 배열의 첫 번째 값을 리턴하는 것이다!
그래서, 위 예제에서 find() 함수는
arr 배열의 여러 객체 중, name === 'apple'인
arr[0]의 값을 리턴한 것이다.
arr.filter(callback(element[, index[, array]])[, thisArg])
filter() 함수는
find() 함수가 특정 조건에 부합하는 배열의 첫번째 값만을 리턴한다고 한다면,
filter() 함수는 특정 조건에 부합하는 배열의 모든 값을 배열 형태로 리턴한다.
파라미터
find() 함수와 동일하다.
리턴값
callback 함수에 정의한 조건에 부합하는 배열의 모든 값을 새로운 배열로 리턴한다.
조건에 부합하는 배열 값이 없을 경우 빈 배열을 리턴한다.
const arr = [
{name: 'apple', price : 1000},
{name: 'banana', price : 2000},
{name: 'apple', price: 3000}
];
function isApple(element) {
if(element.name === 'apple') {
return true;
}
}
const apples = arr.filter(isApple);
document.writeln(apples.length); // 2
document.writeln('<br>');
document.writeln(apples[0].name + ',' + apples[0].price); // apple, 1000
document.writeln(apples[1].name + ',' + apples[1].price); // apple, 3000
filter() 함수에 isApple 함수를 callback 함수로 전달하였다.
filter() 함수는 arr 배열에서 object의 name === 'apple'인 모든 객체를 찾아서
새로운 배열로 생성하여 리턴한다.
따라서, 위의 예제에서
filter() 함수가 리턴하는 apples는 length가 2인 배열이고,
배열의 2개의 값은 arr[0], arr[2]의 값과 같다는 것을 확인할 수 있다.