rest Operator
- 함수의 인자, 배열, 객체 중 나머지 값을 묶어 사용하도록 한다.
- 함수의 인자 중 나머지를 가리킨다.
- 배열의 나머지 인자를 가리킨다.
- 객체의 나머지 필드를 가리킨다.
함수인자 rest Operator
function findMin(...rest){
return rest.reduce((a,b) =>
a < b ? a : b)
}
findMin(7, 3, 5, 2, 4, 1)
- 함수 인자 rest operator는, 인자들을 배열로 묶는다.
- rest에는 숫자들이 배열로 담긴다.
- reduce 함수로 min 값을 리턴한다.
rest 매개변수
- python의
*args
포지션으로 변수의 개수를 정확히 알지 못 할때 사용한다.
...
는 python의 *
처럼 변수에 반드시 1개만 들어있어야 하며, 가장 마지막에 명시되어야한다.
- rest 객체는 Array 타입이어서 배열에서 사용할 수 있는 함수는 모두 사용이 가능하다.
rest VS arguments의 차이
arguments
객체는 실제 배열이 아니다. 그러나 rest
는 Array객체의 인스턴스
이므로 sort, map, forEach, pop 등의 메서드를 직접 적용할 수 있다.
- arguments 객체는 callee 속성과 같은 추가 기능을 포함합니다.
...rest
Param은 후속 매개변수만 배열에 포함하므로 ...restParam 이전에 직접 정의한 매개변수는 포함하지 않습니다. 그러나 arguments 객체는, ...restParam의 각 항목까지 더해 모든 매개변수를 포함합니다.
reduce() 함수
- reduce는 자체적으로 4개의 성질을 갖는다.
- 누산기 (acc)(accumulator) : 누적한다는 뜻으로 default 값이면 시작값 또는 index를 명시하거나 initialValue가 있다면 그것을 시작값으로 갖는다.
- 현재 값 (cur) : 현재 처리할 요소
- 현재 인덱스 (idx) : 처리할 현재 요소의 인덱스. initialValue를 제공한 경우 0, 아니면 1부터 시작합니다.
- 원본 배열 (src) : reduce()를 호출한 배열.
- 이때 반드시 필요한 변수 2가지
acc
,cur
객체 rest Operator
const o = {
name : "Daniel",
age : 23,
address : "Street",
job : "Software Engineer",
};
const{age, name, ...rest} = o;
findSamePerson(age, name);
- 객체의 rest operator는, 지정된 필드 외의 나머지 필드를 객체로 묶는다.
- age, name을 제외한 나머지 필드는, rest 변수로 할당된다.
배열 rest Operator
function sumArray(sum, arr){
if (arr.length === 0) return sum;
const[head, ...tail] = arr;
return sumArray(sum+head, tail);
}
sumArray(0, [1, 2, 3, 4, 5]);
- 위 코드를 보면 재귀함수처럼 head를 재귀적으로 계속 더하면서 tail을 반환한다.
- 배열의 rest operator는 나머지 인자를 다시 배열로 묶는다.
- sumArray의 tail 변수는, 첫 번째 원소 head를 제외한 나머지 값들을 다시 배열로 묶는다.
- tail은 하나씩 줄어들게 되며, 길이가 0이 되면 합을 반환한다.
Spread Operator
- Rest operator는 나머지 값을 하나의 객체나 배열로 묶었다면 배열이나 객체들을 반대로 "펼치는" 역할을 함. => indexing 기능 내제
- 묶인 배열 혹은 객체를 각각의 필드로 변환한다. => update 기능구현 가능
- 객체는 또 다른 객체로의 spread를 지원한다.
- 배열은 또 다른 배열의 인자, 함수의 인자로 spread를 지원한다.
let o = {
name : "Daniel",
age : 23,
address : "Street",
job : "Software Engineer",
}
let o2 = { ...o, name : "Tom", age : 24 }
let o3 = { name : "Tom", age : 24, ...o }
o2.job
o3.name
- spread operator의 등장 순서에 따라, 객체의 필드가 덮에씌워 질 수 있다. 즉, 위 코드에서 보면
...o
가 뒷부분에 나오면 앞에 아무리 바꿔도 소용이 없다.
- ...o가 뒤에 등장하면, 기존의 name 필드가 나중에 등장하여 앞의 name : "Tom"을 덮어씌운다.
function findMinInObject(o){
return Math.min(
...Object.values(o)
)
)
let o1 = { a : 1 }
let o2 = { b : 3 }
let o3 = { c : 7 }
finMinInFields(
mergeObjects(o1, o2, o3)
)
- mergeObjects는 주어진 객체들의 필드를 합친다.
- findMinInObject에서는 객체의 필드들 중 최솟값을 반환한다.
.values()
는 객체 값들의 배열을 반환한다.
- 배열 spread operator로 Math.min의 인자를 넘긴다.
JS 함수구현해보기
const RotationEncryptor = {
message : "",
rotation : 0,
encrypt : function(){
let splittedArray = this.message.split('')
let mappedArray = splittedArray.map(i => String.fromCharCde(i.charCodeAt(0)+this.rotation))
let joinedString = mappedArray.join('')
return joinedString
}
- 아래와 같이 함수들을
.
으로 묶을 수 있다. 하지만 한 번에 하는 것 보단 우선 변수를 써가면서 차례차례 만든 후 함수를 깔끔하게 줄이면 더 좋다.
const RotationEncryptor = {
message : "",
rotation : 0,
encrypt : function(){
return this.message
.split("")
.map(i => String.fromCharCode( i.charCodeAt(0) + this.rotation ))
.join("")
}
ArrayManipulator
- 문제 :
ArrayManipulator는 array를 인자로 받아, 여러 가지 작업을 실행하는 클로저입니다. 여러 작업을 메서드 체이닝 방식으로 작성할 수 있으며, 최종적으로 결과를 반환합니다.
- 즉, 배열을 CRUD할 수 있는 팩토리 함수를 만들어보자는 의미이다. 또한 이 때 최대한 spread operator를 사용해보자!
function ArrayManipulator(array) {
function addElement(element) {
return ArrayManipulator([...array, element]);
}
function removeElement(index) {
return ArrayManipulator([
...array.slice(0, index),
...array.slice(index + 1),
]);
}
function updateElement(index, element) {
return ArrayManipulator([
...array.slice(0, index),
element,
...array.slice(index + 1),
]);
}
function mapElements(func) {
return ArrayManipulator(array.map(func));
}
function filterElements(func) {
return ArrayManipulator(array.filter(func));
}
function getArray() {
return array;
}
return {
addElement,
removeElement,
updateElement,
mapElements,
filterElements,
getArray,
};
}
export default ArrayManipulator;
- 문제
Form의 역할을 하는 클로저를 구현합니다. Form은 폼의 값들을 저장하고, 검증하며, 최종적으로 하나의 formData객체를 만들어내는 역할을 합니다. 내부적으로 formState를 가지며, 클로저가 반환하는 함수들은 별도의 인자를 받지 않고 formState를 수정할 수 있습니다.
const Form = () => {
const formState = {};
function register(name, validator = value => true) {
formState[name] = { value: "", validator };
}
function validate() {
return Object.values(formState).reduce((flag, {value, validator}) => validator(value) && flag, true)
}
function getFormData() {
return Object
.entries(formState)
.reduce(
(formData, item) => {
const [key, {value, validator}] = item
formData[key] = value
return formData
},{})
}
function setValue(name, value) {
formState[name] = { ...formState[name], value };
}
return {
register,
validate,
getFormData,
setValue,
};
};
export default Form;