정보실

웹학교

정보실

javascript JavaScript에서 고차 함수의 힘 (예 및 사용 사례 포함)

본문

JavaScript는 존재하는 거의 모든 JavaScript 응용 프로그램에서 함수를 사용합니다. 함수 덕분에 이 언어는 의료 분야에서 인공 지능 기능을 구축하는 것과 같은 많은 강력한 기능을 수행 할 수 있습니다.


이 기사에서 이야기 할 강력한 기능은 고차 함수라는 함수를 사용합니다. 고차 함수는 다른 함수를 인수로 사용하거나 함수를 반환 값으로 반환하는 함수입니다. 또한 강력한 예제와 사용 사례를 보여줄 것입니다. 이는 대부분의 자습서에서 누락된 것입니다. 그러나 걱정하지 마십시오.이 게시물에서 예제를 찾을 수 있습니다.


https://dev.to/jsmanifest/the-power-of-higher-order-functions-in-javascript-with-examples-and-use-cases-2hkl 


그 말로 JavaScript를 가지고 놀았다면 이미 그 용어에 대해 들어봤을 것입니다. 고차 함수는 JavaScript에서 널리 사용되며 .map, .filter, .reduce 및 .forEach와 같이 일반적으로 사용되는 함수에 존재합니다.


JavaScript를 조금 처음 접한다면, 그 메소드에서 상위 함수가 어디에 있는지 혼동 될 수 있습니다.


함수 콜백을 이러한 배열 메소드에 대한 인수로 선언하면 다음과 같이 표시됩니다.


const arr = [1, 2, 3, 4, 5, 'six', 'seven', 'eight', 'nine', 'ten']

// Duplicate the array
arr.map(function(value) {
  return value
})

// Return only the number types
arr.filter(function(value) {
  return typeof value === 'number'
})

// Log each value to the console
arr.forEach(function(value) {
  console.log(value)
})

// Add the numbers together, avoiding the string types
arr.reduce(function(acc, value) {
  if (typeof value === 'number') {
    acc += value
  }
  return acc
}, 0)

그러나 고차 함수는 .map과 같은 메소드에 전달하는 함수가 아닙니다. .map과 같은 메소드는 고차 함수입니다.


고차 함수가 다른 함수를 인수로 취하는 함수가 될 수 있다고 언급했을 때, 이것이 함수에 전달되었을 때의 일입니다.


다음은 .map 메소드와 똑같이 작동하는 구현입니다.


function map(callback) {
  const result = []
  for (let index = 0; index < this.length; index++) {
    const currentItem = this[index]
    const returnValue = callback(currentItem, index, this)
    result.push(returnValue)
  }
  return result
}


코드 스니펫을 보면 콜백 매개 변수는 앞에서 보여준 .map 메소드에 인수로 전달한 것과 동일한 함수입니다.


// Duplicate the array
arr.map(function(value) {
  return value
})


보다 정확하게 하기 위해 정확한 코드를 이름을 맵 함수 구현과 동일한 이름으로 바꾸어보다 명확하게 볼 수 있도록 하겠습니다.


const callback = function(value) {
  return value
}
// Duplicate the array
arr.map(callback)

// is the same callback used in our .map implementation:

function map(callback) {
  const result = []
  for (let index = 0; index < this.length; index++) {
    const currentItem = this[index]
    const returnValue = callback(currentItem, index, this)
    result.push(returnValue)
  }
  return result
}

처음에는 JavaScript로 코드를 작성하는 데 쓸모없는 방법처럼 보일 수 있습니다. 왜 모든 함수를 피하고 한 함수에서 모든 것을 한 번에 모두 수행 할 수 있을 때 함수를 전달하고 다른 함수를 반환해야 합니까?


고차 함수가 테이블에 가져 오는 가장 큰 이점은 재사용성과 단순성입니다. 그러나 그들은 또한 아름다운 코드를 작성함으로써 이익을 얻습니다. 예, JavaScript에는 못생긴 코드와 아름다운 코드가 있습니다.


재사용성을 염두에 두고 매우 강력한 코드 구성을 소개합니다.


코드 구성 및 강력한 예 


코드에서 고차 함수가 어떻게 보이는지 알았으므로 사용사례가 무엇이고 어디에서 빛나기 시작했는지 궁금할 것입니다.


개구리 목록이 있다고 가정 해 봅시다.


const frogsList = [
  // Yes, these frogs are intelligent. They know how to use email
  {
    name: 'bobTheFrog',
    email: 'froggy@gmail.com',
    age: 2,
    gender: 'Male',
    widthOfTongue: 3,
  },
  {
    name: 'hippoTheFrog',
    email: 'hippo@gmail.com',
    age: 10,
    gender: 'Male',
    widthOfTongue: 11,
  },
  {
    name: 'sally',
    email: 'sallyLipstick@gmail.com',
    age: 5,
    gender: 'Female',
    widthOfTongue: 4,
  },
  {
    name: 'george',
    email: 'georgeRoseBowl@gmail.com',
    age: 11,
    gender: 'Male',
    widthOfTongue: 3,
  },
  {
    name: 'lisa',
    email: 'lisaLovesGeorgeForever@gmail.com',
    age: 19,
    gender: 'Female',
    widthOfTongue: 15,
  },
  {
    name: 'kentucky',
    email: 'frogInKentucky@yahoo.com',
    age: 18,
    gender: 'Male',
    widthOfTongue: 13,
  },
]

고차 함수 없이 개구리를 특정 성별 유형으로 필터링 하려면 다음과 같이해야 합니다.


function filterGender(gender, frogs) {
  return frogs.filter(function(frog) {
    return frog.gender ==== gender
  })
}

// filterGender in use
const maleFrogs = filterGender('Male', frogsList)

이것은 완벽합니다. 그러나 응용 프로그램에서 여러 번 사용하면 번거로울 수 있습니다. 개구리에 관한 거대한 앱이 있다면 filterGender를 두 번 이상 사용할 수 있습니다.


두 번째 단계로 나아 가기 


다른 개구리 목록을 가져 오려면 filterGender를 다시 호출하고 성별을 새 목록을 필터링하는 첫 번째 인수로 다시 선언해야 합니다.


function getFrogs() {
  // some logic and returns a new list of frogs
}

const newFrogs = getFrogs()
const moreMaleFrogs = filterGender('Male', newFrogs) // Shucks, I have to write 'Male' again?

DRY 원리에 대해 들어 본 적이 없다면 이해하는 것이 좋습니다. 코드 스니펫은 첫 번째 인수 때문에 이 규칙을 위반합니다. 우리는 그보다 더 잘할 수 있습니다.


이 문제를 해결하기 위해 고차 함수 개념을 사용할 수 있습니다.


function filterGender(gender) {
  return function(frogs) {
    return frogs.filter(function(frog) {
      return frog.gender === gender
    })
  }
}


그리고 이제는 이렇게 성별 필터를 변수에 할당하면 개구리를 필터링 할 때 더 이상 같은 성별을 선언 할 필요가 없습니다!


const filterFemaleFrogs = filterGender('Female')
const femaleFrogs = filterFemaleFrogs(frogsList)


하지만, 그게 다가 아닙니다. 우리가 그것들을 구성함으로써 얻을 수 있는 추가적인 이점이 있습니다. 암컷 개구리 용 필터를 다시 작성하지 않아도 되는 이점을 얻을 수 있을 뿐만 아니라 반환 된 함수를 재사용하여 다른 개구리 목록에서 동일한 성별을 필터링 할 수 있습니다.


이제 많은 코드를 작성하지 않고도 여러 개구리 목록에서 암컷을 필터링 할 수 있습니다.


const frogsList = [
  // Yes, these frogs are intelligent. They know how to use email
  {
    name: 'bobTheFrog',
    email: 'froggy@gmail.com',
    age: 2,
    gender: 'Male',
    widthOfTongue: 3,
  },
  {
    name: 'hippoTheFrog',
    email: 'hippo@gmail.com',
    age: 10,
    gender: 'Male',
    widthOfTongue: 11,
  },
  {
    name: 'sally',
    email: 'sallyLipstick@gmail.com',
    age: 5,
    gender: 'Female',
    widthOfTongue: 4,
  },
  {
    name: 'george',
    email: 'georgeRoseBowl@gmail.com',
    age: 11,
    gender: 'Male',
    widthOfTongue: 3,
  },
  {
    name: 'lisa',
    email: 'lisaLovesGeorgeForever@gmail.com',
    age: 19,
    gender: 'Female',
    widthOfTongue: 15,
  },
  {
    name: 'kentucky',
    email: 'frogInKentucky@yahoo.com',
    age: 18,
    gender: 'Male',
    widthOfTongue: 13,
  },
]

const frogsList2 = [
  {
    name: 'abc',
    email: 'froggy@gmail.com',
    age: 2,
    gender: 'Male',
    widthOfTongue: 1,
  },
  {
    name: '123',
    email: 'hippo@gmail.com',
    age: 10,
    gender: 'Male',
    widthOfTongue: 4,
  },
  {
    name: 'joe',
    email: 'sallyLipstick@aol.com',
    age: 5,
    gender: 'Female',
    widthOfTongue: 6,
  },
  {
    name: 'jennifer',
    email: 'georgeRoseBowl@aol.com',
    age: 11,
    gender: 'Female',
    widthOfTongue: 10,
  },
]

const frogsList3 = [
  {
    name: 'professorHammick',
    email: 'froggy@gmail.com',
    age: 2,
    gender: 'Female',
    widthOfTongue: 1,
  },
  {
    name: 'macintosh',
    email: 'hippo@gmail.com',
    age: 10,
    gender: 'Female',
    widthOfTongue: 6,
  },
  {
    name: 'frogger',
    email: 'sallyLipstick@gmail.com',
    age: 5,
    gender: 'Female',
    widthOfTongue: 4,
  },
  {
    name: 'frogNation',
    email: 'georgeRoseBowl@gmail.com',
    age: 11,
    gender: 'Female',
    widthOfTongue: 4,
  },
]

function gatherFemaleFrogsEverywhere(...frogLists) {
  const allFemaleFrogs = []
  const filterFemaleFrogs = filterGender('Female')

  frogLists.forEach(function(list) {
    allFemaleFrogs.push(...filterFemaleFrogs(list))
  })

  return allFemaleFrogs
}

const females = gatherFemaleFrogsEverywhere(frogsList, frogsList2, frogsList3)


세 번째 단계로 나아 가기 


JavaScript 언어의 고차 함수가 얼마나 강력한 지 여전히 충분히 확신하지 못한다면, 예제를 계속 사용하여 더 일반적인 함수를 만들어 더 높은 수준의 재사용성을 만듭니다.


function filterFrogs(filter) {
  return function(frogs) {
    return frogs.filter(filter)
  }
}


이전에는 개구리의 성별에 대해 재사용 가능한 기능을 만들 수 있었습니다. 그러나 필터 기능의 논리를 추상화 하여 다른 필터 기능을 작성하고 재사용 할 수 있습니다.


const filterMaleFrogs = filterFrogs(function(frog) {
  return frog.gender === 'Male'
})

const filterAdultFrogs = filterFrogs(function(frog) {
  return frog.age >= 10
})

const filterFrogNamesThatStartWithHippo = filterFrogs(function(frog) {
  return frog.name.toLowerCase().startsWith('hippo')
})

const filterGmailEmails = filterFrogs(function(frog) {
  return /gmail.com/i.test(frog.email)
})


이전에는 동일한 성별 유형을 다시 선언 할 필요 없이 성별 필터 기능을 재사용 할 수 있는 놀라운 기능이 있었지만 이제는 개구리를 필터링 하는 방법에 대한 기능을 작성하고 재사용 할 수 있는 추가 기능이 있습니다! 놀랄 만한!


한 번에 모두 사용할 수도 있습니다.


function applyAllFilters(...filters) {
  return function(frogs) {
    let newFrogs = [...frogs]

    for (let index = 0; index < filters.length; index++) {
      const filter = filters[index]
      newFrogs = filter(newFrogs)
    }

    return newFrogs
  }
}

const applyFrogFilterers = applyAllFilters(
  filterMaleFrogs,
  filterAdultFrogs,
  filterFrogNamesThatStartWithHippo,
  filterGmailEmails,
)

const combinedFrogsList = [...frogsList, ...frogsList2, ...frogsList3]

const filteredFrogs = applyFrogFilterers(combinedFrogsList)

console.log(filteredFrogs)

/*
      result:
        {
          age: 10,
          email: "hippo@gmail.com",
          gender: "Male",
          name: "hippoTheFrog",
          widthOfTongue: 11
        }
*/


마지막으로 더 나아 가기 


applyAllFilters 함수는 작업을 잘 수행합니다. 그러나 개구리의 거대한 목록의 경우 최종 결과를 얻기 위해 여러 번 필터를 실행하기 때문에 많은 작업이 될 수 있습니다.


필터를 동시에 적용하여 전체 개구리 목록을 통과 할 수 있는 간단하고 재사용 가능한 고차 함수를 만들기 위해 고차 함수 개념을 다시 사용할 수 있습니다.


더 명확하게, for 루프 코드를 살펴보고 실제로 뒤에서 일어나는 일을 확인하십시오.


function applyAllFilters(...filters) {
  return function(frogs) {
    let newFrogs = [...frogs]

    for (let index = 0; index < filters.length; index++) {
      const filter = filters[index]
      newFrogs = filter(newFrogs)
    }

    return newFrogs
  }
}

내가 보고 싶은 줄은 다음과 같습니다.


newFrogs = filter(newFrogs)


이 코드 줄은 이 함수에서 return frogs.filter (filter)와 같은 코드 줄입니다.


function filterFrogs(filter) {
  return function(frogs) {
    return frogs.filter(filter)
  }
}

필터 방법이 새로운 배열을 생성하기 때문에 이것은 문제입니다. 우리가 이것을 썼을 때 :


const applyFrogFilterers = applyAllFilters(
  filterMaleFrogs,
  filterAdultFrogs,
  filterFrogNamesThatStartWithHippo,
  filterGmailEmails,
)


우리는 필터 메소드를 4 번 다른 방식으로 호출합니다. 즉, 우리는 최종 결과를 얻기 위해 JavaScript가 메모리에 4 개의 다른 배열을 생성하게 합니다.


그렇다면 어떻게 JavaScript를 하나의 배열로 만들어서 결국 같은 결과를 얻을 수 있습니까?


당신은 그것을 추측했다. 고차 함수 사용!


// NOTE: The filter functions are now individual functions (not wrapped with filterFrogs)

const filterMaleFrogs = function(frog) {
  return frog.gender === 'Male'
}

const filterAdultFrogs = function(frog) {
  return frog.age >= 10
}

const filterFrogNamesThatStartWithHippo = function(frog) {
  return frog.name.toLowerCase().startsWith('hippo')
}

const filterGmailEmails = function(frog) {
  return /gmail.com/i.test(frog.email)
}

// Credits to: SerjoA
function combineFilters(...fns) {
  return function(val) {
    for (let i = 0; i < fns.length; i++) {
      const filter = fns[i]
      const passes = filter(val)
      if (passes) {
        continue
      } else {
        return false
      }
    }
    return true
  }
}

function composeFrogFilterers(...fns) {
  return function(frogs) {
    // Credits to: SerjoA
    return frogs.filter(combineFilters(...fns))
  }
}

const applyFrogFilterers = composeFrogFilterers(
  filterMaleFrogs,
  filterAdultFrogs,
  filterFrogNamesThatStartWithHippo,
  filterGmailEmails,
)

const combinedFrogsList = [...frogsList, ...frogsList2, ...frogsList3]

const allFilteredFrogs = applyFrogFilterers(combinedFrogsList)

console.log(allFilteredFrogs)

/*
      result:
        {
          age: 10,
          email: "hippo@gmail.com",
          gender: "Male",
          name: "hippoTheFrog",
          widthOfTongue: 11
        }
*/

또한 마지막 예제의 훌륭한 해결 방법에 대한 @serjoa 덕분에!


결론 


고차 함수가 얼마나 강력하고 이 기사를 읽음으로써 이 개념의 사용 사례에 대해 더 많은 통찰력을 얻었음을 확신하기를 바랍니다. 앞으로 더 많은 것을 찾아보십시오!



  • 트위터로 보내기
  • 페이스북으로 보내기
  • 구글플러스로 보내기
  • 카카오톡으로 보내기

페이지 정보

조회 28회 ]  작성일19-10-02 18:35

웹학교