자바스크립트 코딩의 기술_유연한 함수를 만들어라
자바스크립트 2021. 6. 20. 18:34(본 포스팅은 길벗의 '자바스크립트-코딩의 기술' 책을 공부하면서 작성되었습니다_내돈내산)
2. 화살표 함수로 복잡도를 낮춰라
- 화살표 함수를 사용하면, 함수선언, 괄호, return문, 중괄호 등 불필요한 정보의 제거가 가능하다.
- 기존의 기명 또는 무기명 함수에서 매개변수와 템플릿 리터럴을 제외한 모든것을 제거하고, => 화살표를 추가한다.
- 해체할당, 나머지 매개변수, 매개변수 기본값 등을 사용하는 특별한 매개변수의 경우는 여전히 괄호가 필요함.
const name = {
first: 'Lemmy',
last: 'Kilmister',
};
// 일반함수
function getName({ first, last }) {
return `${first} ${last}`;
}
// 화살표 함수: 특별한 매개변수를 쓸때는 매개변수를 괄호로 감싸준다.
const getName = ({ first, last }) => `${first} ${last}`;
// 객체를 리턴하는 경우에도 객체를 괄호로 감싸주어야 한다.
const getFullName = ({ first, last }) => ({ fullName: `${first} ${last}` })
// 괄호를 사용해서 값을 반환할 때는 코드를 여러줄에 걸쳐 작성할 수 있다.
const getNameAndLocation = ({ first, last, city, state }) => ({
fullName: `${first} ${last}`,
location: `${city}, ${state}`,
});
- 다른 함수를 반환하는 함수인 고차함수를 만드는데 용이하다.
- 고차함수의 반환값은 다른 함수이므로, 화살표 함수의 기능을 활용해서 return을 직접 작성하지 않고, 중괄호 없이 함수를 반환할 수 있다.
// 화살표 함수를 이용한 고차함수
const discounter = discount => {
return price => {
return price * (1 - discount);
};
};
// 중괄호나 return 없이 함수를 반환하는 구조
const discounter = discount => price => price * (1 - discount);
3. 부분적용 함수로 단일 책임 매개변수를 관리하라
- 고차 함수를 이용해 매개변수에 단일 책임을 부여하고, 매개변수를 집중시킨다.
- 부분 적용 함수란 n개의 인자를 받는 함수에 미리 m개의 인자만 넘겨 기억시켰다가, 나중에 n-m개의 인자를 넘기면 비로소 원래 함수의 실행 결과를 얻을 수 있게끔 하는 함수이다.
- 고차함수는 함수 실행이 완전히 끝날때까지 최소한 두 단계에 걸친 매개변수가 존재한다. 부분적용 함수를 사용할 경우 일부 매개변수를 전달하면 해단 매개변수를 잠그는 함수가 반환되어 여기 더 많은 매개변수를 사용할 수 있다.
>> 부분적용 함수를 이용하면 한 번에 전달해야 할 함수 인수의 수가 줄어드는 대신 인수를 더 전달해야 하는 함수를 반환한다.
// 일반함수
function mergeProgramInformation(building, manager, program) {
const { hours, address } = building;
const { name, phone } = manager;
const defaults = {
hours,
address,
contact: name,
phone,
};
return { ...defaults, ...program };
}
// 한번에 함수의 두부분을 모두 호출한것
function mergeProgramInformation(building, manager) {
const { hours, address } = building;
const { name, phone } = manager;
const defaults = {
hours,
address,
contact: name,
phone,
};
return program => {
return { ...defaults, ...program }; //이 함수를 실행하면 매개변수로 program 하나만 사용하는 함수를 반환한다.
};
}
// 나머지매개변수를 이용해 인수를 여러개 전달할수 있었다.
const zip = (...left) => (...right) => {
return left.map((item, i) => [item, right[i]]);
};
zip('kansas', 'wisconsin', 'new mexico')(...birds);
// [
// ['kansas', 'meadowlark'],
// ['wisconsin', 'robin'],
// ['new mexico', 'roadrunner']
// ]
4. 커링과 배열 메서드를 조합한 부분 적용 함수를 사용하라
- 함수의 부분적용을 통해 변수를 저장해두는 방법을 살펴본다.
- 고차함수를 이용하면 매개변수를 별도로 분리할 수 있지만, 함수를 분리하기 전에 함수에 필요한 인수의 수를 줄일수 있도록 인수를 분리하는 것이 훨씬 더 중요하다.
- 하나의 인수만 전달하는 메서드를 다룰 때 '커링함수(curring)' 를 사용하는것이 매우 유리하다.
const dogs = [
{
name: 'max',
weight: 10,
breed: 'boston terrier',
state: 'wisconsin',
color: 'black',
},
{
name: 'don',
weight: 90,
breed: 'labrador',
state: 'kansas',
color: 'black',
},
{
name: 'shadow',
weight: 40,
breed: 'labrador',
state: 'wisconsin',
color: 'chocolate',
},
];
// #1. 강아지 배열과 필터조건을 인수로 받은 후 결과 도출
// 강아지의 이름이 완전일치('===') 할때 filter 작동
function getDogNames(dogs, filter) {
const [key, value] = filter;
return dogs
.filter(dog => dog[key] === value)
.map(dog => dog.name);
}
// #2. filter함수에 조건을 정하는 함수를 콜백함수로 전달함
// 강아지의 기타 조건에 대한 filter 작업이 가능함.
function getDogNames(dogs, filterFunc) {
return dogs
.filter(filterFunc)
.map(dog => dog.name)
}
// #3. 커링함수를 사용해 filter 조건을 구현함
// #2의 함수의 filter 부분을 커링함수로 대체함
const weightCheck = weight => dog => dog.weight < weight;
getDogNames(dogs, weightCheck(20));
// ['max']
getDogNames(dogs, weightCheck(50));
// ['max', 'shadow']
- #1번 코드의 경우 필터함수에 제약이 있음. 필터와 각각의 강아지가 완전일치되었을때만 작동함. 어떠한 조건을 수립하는데 매우 편협하게 작동하게 됨. map( )은 filter를 통해 나온값만 인수로 받을 수 있기 때문에 유효범위내의 다른변수들을 가져올 수 없게 된다.
- #1의 문제를 해결하기 위해 #2번코드에서는 filter에 적용시킬 함수를 작성해 filter 에 콜백함수로 전달시키게 하였다. 하지만 이 경우 유효범위의 충돌이 없는지 확인이 필요하고, 변수에 접근이 가능한지 매번 점검이 필요하다.
- 마지막으로 #3번에서는 #2번의 하드코딩과 유효범위충돌의 문제를 해결하기 위해 커링함수를 이용해 조건함수를 구현하였다. 실제 비교에 사용할 기준 무게는 함수에 담기기 때문에 서로 다른 무게를 기준으로 해도 계속해서 함수를 재사용할 수 있다.
- curring은 인수가 하나만 있어야 하는 함수를 작성할 때 훌륭한 도구라는 점을 반드시 기억해주자. 복잡한 문제를 매우 간단하게 만들어준다.
5. 화살표 함수로 문맥 혼동을 피하라
- 화살표 함수를 이용해 문맥 오류를 피하는 방법을 살펴보자.
- 함수의 유효범위는 간단히 말하면 함수가 접근할 수 있는 변수, 문맥은 함수 또는 클래스에서 this 키워드가 참조하는 것으로 생각해보자. 유효범위는 [함수]와 연관되어 있고, 문맥은 [객체]와 연관되어 있다고 생각하자.
const validator = {
message: 'is invalid.',
setInvalidMessage(field) {
return `${field} ${this.message}`;
},
};
validator.setInvalidMessage('city');
// city is invalid.
- validator 객체 >> message 속성, setInvalidMessage( ) 메서드가 존재함.
- setInvalidMessage( ) 메서드는 this.message로 message 속성을 참조하고 있음.
- setInvalidMessage( ) 메서드가 호출될때, 함수에서 this 바인딩을 생성하면서 해당함수가 담긴 객체도 문맥에 포함시킴.
- 객체에서 this를 다룰 떄는 일반적으로 큰 문제가 없지만, 객체에 담긴 함수를 다른함수의 콜백함수로 사용하는 경우에는 주의가 필요하다. 예를들어 setTimeout( ), setInterval( ), map( ), filter( ) 등의 메서드는 콜백함수를 받으면서 콜백함수의 문맥까지 변경시키게 된다.
// #1. map 함수의 콜백함수에서 this를 사용하는 경우
const validator = {
message: 'is invalid.',
setInvalidMessages(...fields) {
return fields.map(function (field) {
return `${field} ${this.message}`;
});
},
};
validatorProblem.setInvalidMessages(field);
// TypeError: Cannot read property 'message' of undefined
// #2. 화살표함수를 이용해 this의 바인딩이 이루어지지 않도록 코드를 수정함.
const validator = {
message: 'is invalid.',
setInvalidMessages(...fields) {
return fields.map(field => {
return `${field} ${this.message}`;
});
},
};
validator.setInvalidMessages('city');
// ['city is invalid.]
// #3. 처음부터 화살표함수를 이용해서 함수를 구현한 경우
const validator = {
message: 'is invalid.',
setInvalidMessage: field => `${field} ${this.message}`,
};
validatorProblem.setInvalidMessages(field);
// TypeError: Cannot read property 'message' of undefined
- #1번의 경우 결과에서 this.message가 undefined가 발생한 이유는 map( ) 메서드에 콜백함수로 전달되어 map( )메서드의 문맥에서 호출되므로 이때는 this 바인딩이 validator 객체가 아니고 전역객체가 된다.
- #1번의 문제를 해결하기 위해 #2번에서는 화살표함수를 사용하였고, 화살표함수는 this바인딩을 새로 만들지 않기때문에 message속성에 접근이 가능해진다.
- #3번의 경우 처음부터 화살표함수로 되어있었으며, 새로운 this 바인딩을 만들어내지 않아 this는 전역객체에 바인딩이 되어 undefined 가 발생하게 된다.
'자바스크립트' 카테고리의 다른 글
자바스크립트 코딩의 기술_클래스로 인터페이스를 간결하게 유지하라_2 (0) | 2021.06.27 |
---|---|
자바스크립트 코딩의 기술_클래스로 인터페이스를 간결하게 유지하라_1 (0) | 2021.06.27 |
자바스크립트 코딩의 기술_매개변수와 return 문을 정리하라_2 (0) | 2021.06.20 |
자바스크립트 코딩의 기술_매개변수와 return 문을 정리하라_1 (0) | 2021.06.19 |
자바스크립트 코딩의 기술_반복문 작성의 기술_2 (0) | 2021.05.30 |