ES6+ 향상된 함수 기능 (1) - 매개변수
ES6에서 함수의 기능을 온전하게 완성했다고 볼 수 있다.
- 매개변수에 기본값을 줄 수 있게 됨.
- 나머지 매개변수를 통해 가변 길이 매개변수를 좀 더 명시적으로 표현할 수 있음.
- Named parameter(명명된 매개변수)를 통해서 함수를 호출하는 코드의 가독성이 훨씬 좋아졌다.
- Arrow function(화살표 함수)가 추가되면서 함수 코드가 간결해졌고, this 바인딩에 대한 고민을 덜 수 있게 되었다.
1. 매개변수에 추가된 기능.
#1 매개변수 기본값
ES6부터 함수 매개변수에 기본값을 줄 수 있다.
function printLog( a = 1 ) {
console.log({ a });
}
printLog(); // { a: 1 };
또한 객체 분해 할당처럼 기본값으로 함수 호출을 넣을 수 있고, 기본값이 필요한 경우에만 함수가 호출된다.
function getDefault() {
return 'None';
}
function printText(str = getDefault()) {
console.log({ str });
}
printText(); // { str: 'None'}
undefined가 입력된 경우에만 기본값 함수가 호출된다는 특징을 이용하면 매개변수에서 필숫값을 표현할 수 있다.
function required() {
throw new Error('No parameter');
}
function printText(str = required()){
console.log({ str });
}
printText('Hello'); // { str: 'Hello' }
printText(); // 에러 발생: No parameter
#2 Rest parameter (나머지 매개변수)
함수에 입력된 인수 중에서 정의된 매개변수 개수만큼을 제외한 나머지를 배열로 만들어 준다.
이는 변수가 가변적일 때 매우 유용하다.
function printText(str1, ...rest){
console.log({ str1, rest });
}
printText('A','B','O'); //{str1:'A', rest:['B','O']}
첫 번째 인자를 제외한 나머지를 rest 변수에 할당한다.
ES5에서는 arguments 키워드가 비슷한 역할을 한다.
function printText(str) {
const rest = Array.from(arguments).slice(1);
console.log({str, rest});
}
printText('a','b',1, 2);
// { str: 'a', rest: ['b',1,2] }
arguments는 명시적으로 드러나지 않아 가독성이 좋지 않다.
그리고 arguments는 배열이 아니여서 배열처럼 사용하기 위해서는 배열로 변환해야한다.
Rest parameter ( 나머지 매개변수)를 사용하는게 낫다.
#3 Named parameter (명명된 매개변수)
명명된 매개변수는 객체 분해 할당을 이용해서 구현할 수 있다.
함수 호출 시 매개변수의 이름과 값을 동시에 적을 수 있으므로 가독성이 높다.
const numbers = [1,2,3,4,5,6,7,8];
// 1번 함수
function getValues1(numbers,greaterThan,lessThan){
return numbers.filter((x) => x<lessThan&&x>greaterThan);
}
getValues(numbers, 2, 7); // 1
getValues(numbers, null, 7); // 2
// 2번 함수
function getValues2({ numbers, greaterThan = 0,lessThan =10}) {
return numbers.filter((x) => x<lessThan&&x>greaterThan);
}
getValues2({numbers, greaterThan:2, lessThan:7}); // 3
getValues2({numbers, lessThan:7}); // 4
getValues2({numbers, greaterThan:2}); // 5
1번 함수는 매개변수의 순서를 지켜야하는 함수이다.
1번 실행에서는 2와 7이 무엇을 의미하는지 파악하기 어렵다.
2번 실행에서는 파라미터의 순서와 역할을 정확히 파악하고 필요없는 파리미터를 null로 채웠다.
반면 2번 함수는 Object 를 사용해 파라미터를 편하게 받을수 있게 하였다.
기본값도 할당이 가능하다. 객체 분해 할당 기능이 적용된다.
3번 실행 처럼 매개변수 이름을 노출 시켜 가독성을 높여준다.
4,5번 실행과 같이 Optional parameter(선택적 매개변수) 활용도를 높여준다.
여기서 함수를 호출할 떄마다 객체가 생성되기 때문에 비효율적일 것이라고 생각할 수 있다.
하지만 javascript 엔진이 최적화를 통해 새로운 객체를 생성하지 않는다고 한다. 안심하고 사용할 수 있다.
Name parameter 는 패턴이라고 할수 있다.
유용한 예를 하나 살펴보자.
function apiRequest({
endpoint,
method = 'GET',
getParams = {},
headers = ['Content-Type: text-plain'],
callback = () => {},
timeout = 0,
authRequest = true,
} = {}) {
//...
console.log(arguments[0]);
return new Promise((resolve, reject) => {
resolve("resolve");
});
}
apiRequest({
endpoint: 'products',
getParams: { category: 3 },
})
// {endpoint: "products", getParams: { category: 3 }}
외에도 apiRequest 함수의 특수 버전을 만들 수 있습니다.
아래와 같이 권한이 필요한 authApiRequest를 만들어 보자.
function authApiRequest (params) {
const token = 'whatever';
return new Promise((resolve, reject) => {
apiRequest({
...params,
headers: params.headers,
Authentication: token
})
.then(resolve)
.catch(reject)
});
}
authApiRequest({
endpoint: 'products',
getParams: { category: 3 },
});
또는 postRequest
function postRequest (params) {
return new Promise((resolve, reject) => {
apiRequest({...params, method: 'POST'})
.then(resolve)
.catch(reject)
});
}
// 실행 예제
postRequest({
endpoint: 'products',
getParams: { category: 3 },
});
똑같은 Named parameter 패턴으로 여러 변수들을 반환하는 함수를 만들어 봅시다.
function apiRequest({
endpoint,
method = 'GET',
getParams = {},
headers = ['Content-Type: text-plain'],
callback = () => {},
timeout = 0,
authRequest = true,
} = {}) {
//...
console.log(arguments[0]);
var response, error, loading
response = error = loading = null
//some amazing code...
return {
response,
error,
loading,
}
}
var { response, error, loading } = apiRequest({ endpoint: 'products' });
이런 식으로 함수의 응답을 구조화하여 다시 전후 관계와 의도를 제공 할 수 있습니다.
이것은 효과적으로 "함수에서 둘 이상의 값을 반환"하는 좋은 방법입니다.
여러분들은 이 함수가 Object를 반환하고 있지만 또 다른 의미를 이미 알고있습니다.
바로 React Hooks 처럼 배열을 사용하여 값을 저장하고 반환 할 수 있습니다.
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}