>  기사  >  웹 프론트엔드  >  JavaScript의 고차 함수 소개(코드 예제)

JavaScript의 고차 함수 소개(코드 예제)

不言
不言앞으로
2019-03-05 14:51:252330검색

이 글은 JavaScript의 고차 함수(코드 예제)를 소개합니다. 필요한 친구들이 참고할 수 있기를 바랍니다.

함수는 다른 함수를 매개변수로 받을 수 있습니다. 간단히 말해서, 함수의 매개변수는 다른 함수를 받을 수 있습니다.

JavaScript의 고차 함수는 Swift의 고차 함수와 유사합니다.

일반적인 고차 함수는 Map, Reduce, Filter, Sort입니다.

고차 함수는 다음 조건 중 하나 이상을 충족하는 함수를 나타냅니다.

1: 함수는 다음과 같이 전달될 수 있습니다. 매개변수

2: 함수는 반환 값 출력으로 전달될 수 있습니다.

JavaScript 언어의 함수는 분명히 고차 함수의 조건을 충족합니다. JavaScript에서 고차 함수의 매력을 살펴보겠습니다.

고차 함수는 AOP를 구현합니다

AOP(관점 지향 프로그래밍)의 주요 기능은 핵심 비즈니스 로직 모듈과 관련이 없는 일부 함수를 추출한 후 "를 통해 비즈니스 모듈에 통합하는 것입니다. 동적 직조". 이러한 기능에는 일반적으로 로그 통계, 보안 제어, 예외 처리 등이 포함됩니다. AOP는 Java Spring 아키텍처의 핵심입니다. JavaScript에서 AOP를 구현하는 방법을 살펴보겠습니다. 이는 함수를 다른 함수에 "동적으로 엮는" 것을 의미합니다. 여기서는 이를 수행하기 위해 Function.prototype을 사용합니다. 코드는 다음과 같습니다

/**
* 织入执行前函数
* @param {*} fn 
*/
Function.prototype.aopBefore = function(fn){
 console.log(this)
 // 第一步:保存原函数的引用
 const _this = this
 // 第四步:返回包括原函数和新函数的“代理”函数
 return function() {
 // 第二步:执行新函数,修正this
 fn.apply(this, arguments)
 // 第三步 执行原函数
 return _this.apply(this, arguments)
 }
}
/**
* 织入执行后函数
* @param {*} fn 
*/
Function.prototype.aopAfter = function (fn) {
 const _this = this
 return function () {
 let current = _this.apply(this,arguments)// 先保存原函数
 fn.apply(this, arguments) // 先执行新函数
 return current
 }
}
/**
* 使用函数
*/
let aopFunc = function() {
 console.log('aop')
}
// 注册切面
aopFunc = aopFunc.aopBefore(() => {
 console.log('aop before')
}).aopAfter(() => {
 console.log('aop after')
})
// 真正调用
aopFunc()

currying(커링)

커링에 관해 가장 먼저 이야기해야 할 것은 커링이 어떤 기능인지 입니다.

커링은 부분평가라고도 합니다. curring 함수는 먼저 일부 매개변수를 수락한 후 즉시 평가하지 않고 계속해서 다른 함수를 반환합니다. 방금 전달된 매개변수는 함수에 의해 형성된 클로저에 저장됩니다. 실제로 함수를 평가해야 하는 경우 이전에 전달된 모든 매개변수가 한 번에 평가에 사용됩니다.

직접 보면 개념을 이해하기 쉽지 않습니다. 다음 예를 살펴보겠습니다.

1년에 12개월 동안의 소비량을 계산하는 함수가 필요합니다. 우리가 얼마나 많은 돈을 소비했는지 계산해 보세요. 일반 코드는 다음과 같습니다

// 未柯里化的函数计算开销
let totalCost = 0
const cost = function(amount, mounth = '') {
 console.log(`第${mounth}月的花销是${amount}`)
 totalCost += amount
 console.log(`当前总共消费:${totalCost}`)
}
cost(1000, 1) // 第1个月的花销
cost(2000, 2) // 第2个月的花销
// ...
cost(3000, 12) // 第12个月的花销

요약하자면, 1년 동안의 총 소비량을 계산하려면 12번을 계산할 필요가 없다는 것을 찾는 것은 어렵지 않습니다. 연말에 계산만 하면 됩니다. 다음은 이해를 돕기 위해 함수를 부분적으로 커링합니다.

// 部分柯里化完的函数
const curringPartCost = (function() {
 // 参数列表
 let args = []
 return function (){
 /**
 * 区分计算求值的情况
 * 有参数的情况下进行暂存
 * 无参数的情况下进行计算
 */
 if (arguments.length === 0) {
  let totalCost = 0
  args.forEach(item => {
  totalCost += item[0]
  })
  console.log(`共消费:${totalCost}`)
  return totalCost
 } else {
  // argumens并不是数组,是一个类数组对象
  let currentArgs = Array.from(arguments)
  args.push(currentArgs)
  console.log(`暂存${arguments[1] ? arguments[1] : '' }月,金额${arguments[0]}`)
 }
 }
})()
curringPartCost(1000,1)
curringPartCost(100,2)
curringPartCost()

다음은 일반 커링과 커링될 함수를 작성합니다. 코드는 다음과 같습니다

// 通用curring函数
const curring = function(fn) {
 let args = []
 return function () {
 if (arguments.length === 0) {
  console.log('curring完毕进行计算总值')
  return fn.apply(this, args)
 } else {
  let currentArgs = Array.from(arguments)[0]
  console.log(`暂存${arguments[1] ? arguments[1] : '' }月,金额${arguments[0]}`)
  args.push(currentArgs)
  // 返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文,这有利于匿名函数的递归或者保证函数的封装性
  return arguments.callee
 }
 }
}
// 求值函数
let costCurring = (function() {
 let totalCost = 0
 return function () {
 for (let i = 0; i < arguments.length; i++) {
  totalCost += arguments[i]
 }
 console.log(`共消费:${totalCost}`)
 return totalCost
 }
})()
// 执行curring化
costCurring = curring(costCurring)
costCurring(2000, 1)
costCurring(2000, 2)
costCurring(9000, 12)
costCurring()

Function throttling

JavaScript의 대부분의 기능은 사용자에 의해 능동적으로 실행됩니다. 일반적으로 성능 문제는 없지만 일부 특별한 경우에는 사용자가 직접 제어하지 않습니다. 많은 호출로 인해 성능 문제가 발생하기 쉽습니다. 결국 DOM 작업은 매우 비쌉니다. 이러한 시나리오 중 일부는 다음과 같습니다:

    window.resise 이벤트.
  • 마우스, 입력 및 기타 이벤트.
  • 업로드 진행
고차 함수를 통해 조절 기능을 구현해보자

/**
* 节流函数
* @param {*} fn 
* @param {*} interval 
*/
const throttle = function (fn, interval = 500) {
 let timer = null, // 计时器 
  isFirst = true // 是否是第一次调用
 return function () {
 let args = arguments, _me = this
 // 首次调用直接放行
 if (isFirst) {
  fn.apply(_me, args)
  return isFirst = false
 }
 // 存在计时器就拦截
 if (timer) {
  return false
 }
 // 设置timer
 timer = setTimeout(function (){
 console.log(timer)
 window.clearTimeout(timer)
 timer = null
 fn.apply(_me, args)
 }, interval)
 }
}
// 使用节流
window.onresize = throttle(function() {
 console.log(&#39;throttle&#39;)
},600)

시간 공유 기능

조절 기능은 계획이라고 불리는 함수의 빈도를 제한하는 솔루션을 제공합니다. 다음에는 또 다른 문제에 직면하게 되는데, 일부 기능은 사용자에 의해 적극적으로 호출되지만, 이러한 작업은 페이지 성능에 심각한 영향을 미칠 수 있으므로 이를 해결하려면 다른 방법을 사용해야 합니다.

단기간 내에 많은 수의 DOM 노드를 페이지에 삽입해야 한다면 분명히 브라우저에 부담이 될 것입니다. 브라우저가 정지될 수 있으므로 시분할 기능을 수행하고 일괄적으로 삽입해야 합니다.

/**
* 分时函数
* @param {*创建节点需要的数据} list 
* @param {*创建节点逻辑函数} fn 
* @param {*每一批节点的数量} count 
*/
const timeChunk = function(list, fn, count = 1){
 let insertList = [], // 需要临时插入的数据
  timer = null // 计时器
 const start = function(){
 // 对执行函数逐个进行调用
 for (let i = 0; i < Math.min(count, list.length); i++) {
  insertList = list.shift()
  fn(insertList)
 }
 }
 return function(){
 timer = setInterval(() => {
  if (list.length === 0) {
  return window.clearInterval(timer)
  }
  start()
 },200)
 }
}
// 分时函数测试
const arr = []
for (let i = 0; i < 94; i++) {
 arr.push(i)
}
const renderList = timeChunk(arr, function(data){
 let p =document.createElement(&#39;p&#39;)
 p.innerHTML = data + 1
 document.body.appendChild(p)
}, 20)
renderList()

함수 지연 로딩

웹 개발에서는 일부 브라우저의 차이로 인해 일부 스니핑 작업이 항상 불가피합니다.

브라우저의 차이로 인해 종종 다양한 호환성 문제가 발생할 수 있습니다. 매우 간단하고 일반적으로 사용되는 예를 들어보겠습니다. 모든 브라우저에서 보편적으로 사용할 수 있는 이벤트 바인딩 기능입니다.

일반적인 작성 방법은 다음과 같습니다:

// 常用的事件兼容
const addEvent = function(el, type, handler) {
 if (window.addEventListener) {
 return el.addEventListener(type, handler, false)
 }
 // for IE
 if (window.attachEvent) {
 return el.attachEvent(`on${type}`, handler)
 }
}
这个函数存在一个缺点,它每次执行的时候都会去执行if条件分支。虽然开销不大,但是这明显是多余的,下面我们优化一下, 提前一下嗅探的过程:
const addEventOptimization = (function() {
 if (window.addEventListener) {
 return (el, type, handler) => {
  el.addEventListener(type, handler, false)
 }
 }
 // for IE
 if (window.attachEvent) {
 return (el, type, handler) => {
  el.attachEvent(`on${type}`, handler)
 }
 }
})()

이 방법을 사용하면 코드가 로드되기 전에 스니핑을 수행한 다음 함수를 반환할 수 있습니다. 하지만 공공 도서관에 두고 사용하지 않는다면 약간 중복될 것입니다. 다음으로 이 문제를 해결하기 위해 게으른 함수를 사용합니다.

// 惰性加载函数
let addEventLazy = function(el, type, handler) {
 if (window.addEventListener) {
 // 一旦进入分支,便在函数内部修改函数的实现
 addEventLazy = function(el, type, handler) {
  el.addEventListener(type, handler, false)
 }
 } else if (window.attachEvent) {
 addEventLazy = function(el, type, handler) {
  el.attachEvent(`on${type}`, handler)
 }
 }
 addEventLazy(el, type, handler)
}
addEventLazy(document.getElementById(&#39;eventLazy&#39;), &#39;click&#39;, function() {
 console.log(&#39;lazy &#39;)
})

일단 분기에 들어가면 함수 내부에서 함수 구현이 수정됩니다. 다시 작성한 후에 함수는 우리가 기대하는 함수가 되며 더 이상 조건 분기 문이 없습니다. 다음에 함수가 입력될 때.

마지막으로

모두가 더 쉽고 효율적으로 학습할 수 있도록 많은 정보를 무료로 공유해 풀 스택 엔지니어, 심지어 아키텍트가 되기까지의 장애물을 극복하는 데 도움을 드리겠습니다. . 여기서는 모두를 위한 프론트엔드 풀스택 학습 및 교류 서클을 추천합니다:

866109386 누구나 그룹에 참여하여 함께 토론하고 배우고 발전할 수 있습니다.

실제로 학습을 시작하면 어디서부터 시작해야 할지 필연적으로 알 수 없게 되어 효율성이 낮아지고 학습 지속에 대한 자신감에 영향을 미치게 됩니다.

하지만 가장 중요한 것은 어떤 기술을 터득해야 할지 모르고, 학습할 때 함정에 빠지는 경우가 많아 결국 많은 시간을 낭비하게 되므로 여전히 효율적인 자원 확보가 필요합니다.

마지막으로, 병목 현상에 직면하고 무엇을 해야 할지 모르는 모든 프런트엔드 프로그래머 여러분의 앞으로의 작업과 인터뷰에서 최선을 다하길 바랍니다.


위 내용은 JavaScript의 고차 함수 소개(코드 예제)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제