JS ES6 rest, Spread Operator

강정우·2022년 10월 8일
0

JavaScript

목록 보기
17/53
post-thumbnail

rest Operator

  • 함수의 인자, 배열, 객체 중 나머지 값을 묶어 사용하도록 한다.
  • 함수의 인자 중 나머지를 가리킨다.
  • 배열의 나머지 인자를 가리킨다.
  • 객체의 나머지 필드를 가리킨다.

함수인자 rest Operator

function findMin(...rest){
	return rest.reduce((a,b) =>
    	a < b ? a : b)
}

findMin(7, 3, 5, 2, 4, 1)  // 1
  • 함수 인자 rest operator는, 인자들을 배열로 묶는다.
  • rest에는 숫자들이 배열로 담긴다.
  • reduce 함수로 min 값을 리턴한다.

rest 매개변수

  • python의 *args 포지션으로 변수의 개수를 정확히 알지 못 할때 사용한다.
  • ... 는 python의 * 처럼 변수에 반드시 1개만 들어있어야 하며, 가장 마지막에 명시되어야한다.
  • rest 객체는 Array 타입이어서 배열에서 사용할 수 있는 함수는 모두 사용이 가능하다.

rest VS arguments의 차이

  1. arguments 객체는 실제 배열이 아니다. 그러나 rest는 Array객체의 인스턴스이므로 sort, map, forEach, pop 등의 메서드를 직접 적용할 수 있다.
  2. arguments 객체는 callee 속성과 같은 추가 기능을 포함합니다.
  3. ...rest Param은 후속 매개변수만 배열에 포함하므로 ...restParam 이전에 직접 정의한 매개변수는 포함하지 않습니다. 그러나 arguments 객체는, ...restParam의 각 항목까지 더해 모든 매개변수를 포함합니다.

reduce() 함수

  • reduce는 자체적으로 4개의 성질을 갖는다.
  1. 누산기 (acc)(accumulator) : 누적한다는 뜻으로 default 값이면 시작값 또는 index를 명시하거나 initialValue가 있다면 그것을 시작값으로 갖는다.
  2. 현재 값 (cur) : 현재 처리할 요소
  3. 현재 인덱스 (idx) : 처리할 현재 요소의 인덱스. initialValue를 제공한 경우 0, 아니면 1부터 시작합니다.
  4. 원본 배열 (src) : reduce()를 호출한 배열.
  • 이때 반드시 필요한 변수 2가지 acc,cur

객체 rest Operator

const o = {
	name : "Daniel",
    age : 23,
    address : "Street",
    job : "Software Engineer",
};

const{age, name, ...rest} = o;  // 여기선 rest가 배열이 아니라 객체이다! 그래서 rest.함수 이런식으로도 쓰일 수 있다!!!!!!!!!
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  // Software Engineer
o3.name  // Daniel
  • spread operator의 등장 순서에 따라, 객체의 필드가 덮에씌워 질 수 있다. 즉, 위 코드에서 보면 ...o 가 뒷부분에 나오면 앞에 아무리 바꿔도 소용이 없다.
  • ...o가 뒤에 등장하면, 기존의 name 필드가 나중에 등장하여 앞의 name : "Tom"을 덮어씌운다.
function findMinInObject(o){
	return Math.min(
    ...Object.values(o)  // => [1, 3, 7]
    )
)

let o1 = { a : 1 }
let o2 = { b : 3 }
let o3 = { c : 7 }

finMinInFields(
	mergeObjects(o1, o2, o3)
)  // 1
  • 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) {
    // 변환된 배열을 `ArrayManipulator`의 인자로 넘겨 리턴합니다.
    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의 역할을 하는 클로저를 구현합니다. Form은 폼의 값들을 저장하고, 검증하며, 최종적으로 하나의 formData객체를 만들어내는 역할을 합니다. 내부적으로 formState를 가지며, 클로저가 반환하는 함수들은 별도의 인자를 받지 않고 formState를 수정할 수 있습니다.
const Form = () => {
  const formState = {};

  function register(name, validator = value => true) {
      // 이 경우는 콜백함수를 받지 않았을 때의 경우이다. 
    // register시, state에 필드를 등록합니다.
    // 필드 등록 객체는 { value, validator } 입니다.
    // value는 빈 문자열로 초기화됩니다.
    formState[name] = { value: "", validator };
  }

  function validate() {
    // state의 전체 필드를 검사합니다.
    // validator(value) 로 value가 유효한지 검사할 수 있습니다.
    // 전체 필드가 유효해야만 폼이 유효합니다.
//         username : { value, validator },
//         password : { value, validator }
//   }
  return Object.values(formState).reduce((flag, {value, validator}) => validator(value) && flag, true)
  }

  function getFormData() {
    // state의 각 필드에 있는 value를 모아 하나의 객체로 리턴합니다.
    // { name : 'Kim', age: 30 } 의 형식으로 리턴해야 합니다.
    
    // return Object
    //     .entries(formState)
    //     .reduce(
    //         (formData, [key, {value, validator}]) => ({...formData,[key]:value})
    //         ,{})
    return Object
        .entries(formState)
        .reduce(
            (formData, item) => {
                const [key, {value, validator}] = item
                formData[key] = value
                return formData
            },{})
  }

  function setValue(name, value) {
    // name으로 찾은 필드의 value를 설정합니다.
    // name에 해당하는 상태는 반드시 있다고 가정합니다.
    formState[name] = { ...formState[name], value };
  }

  return {
    register,
    validate,
    getFormData,
    setValue,
  };
};

export default Form;
profile
智(지)! 德(덕)! 體(체)!

0개의 댓글