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;