Maison  >  Article  >  interface Web  >  Introduction aux fonctions d'ordre supérieur en JavaScript (exemples de code)

Introduction aux fonctions d'ordre supérieur en JavaScript (exemples de code)

不言
不言avant
2019-03-05 14:51:252202parcourir

Cet article vous présente une introduction aux fonctions d'ordre supérieur en JavaScript (exemples de code), qui ont une certaine valeur de référence. Les amis dans le besoin peuvent se référer. j'espère que cela vous sera utile.

Une fonction peut recevoir une autre fonction en tant que paramètre. En bref, les paramètres de la fonction peuvent recevoir d'autres fonctions. De telles fonctions sont appelées fonctions d'ordre supérieur.

Les fonctions JavaScript d'ordre supérieur sont similaires. aux fonctions d'ordre supérieur de Swift

Les fonctions courantes d'ordre supérieur sont : Mapper, Réduire, Filtrer, Trier

Les fonctions d'ordre supérieur font référence à des fonctions qui répondent à au moins l'un des éléments suivants conditions

1 : Les fonctions peuvent être transmises en tant que paramètres

2 : Les fonctions peuvent être générées en tant que valeurs de retour

Les fonctions dans le langage JavaScript satisfont évidemment à des exigences supérieures. Fonctions d'ordre Conditions, explorons le charme des fonctions d'ordre supérieur de JavaScript.

Les fonctions d'ordre supérieur implémentent l'AOP

La fonction principale de l'AOP (programmation orientée aspect) est d'extraire certaines fonctions qui n'ont rien à voir avec la logique métier de base module, puis utilisez la méthode " "Tissage dynamique" intégrée aux modules métier. Ces fonctions incluent généralement les statistiques de journaux, le contrôle de sécurité, la gestion des exceptions, etc. AOP est au cœur de l'architecture Java Spring. Explorons comment implémenter AOP en JavaScript
L'implémentation d'AOP en JavaScript fait référence au "tissage dynamique" d'une fonction dans une autre fonction. Il existe de nombreuses technologies d'implémentation spécifiques pour ce faire. Le code est le suivant

/**
* 织入执行前函数
* @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 (currying)

La première chose dont nous devons parler à propos du curry est de savoir ce qu'est le curry fonctionnel.

le curring est également appelé évaluation partielle. Une fonction curring accepte d'abord certains paramètres.Après avoir accepté ces paramètres, la fonction n'évalue pas immédiatement, mais continue de renvoyer une autre fonction.Les paramètres qui viennent d'être transmis sont enregistrés dans la fermeture formée par la fonction. Lorsque la fonction doit réellement être évaluée, tous les paramètres transmis auparavant sont utilisés pour l'évaluation en même temps.

Ce n'est pas facile de comprendre le concept de manière rigide, regardons l'exemple suivant
Nous avons besoin d'une fonction pour calculer la consommation pendant 12 mois dans une année, et nous devons la calculer au fin de chaque mois Combien d’argent a été dépensé. Le code normal est le suivant

// 未柯里化的函数计算开销
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个月的花销

Pour résumer, il n'est pas difficile de constater que si l'on veut calculer la consommation totale pour un an, il n'est pas nécessaire de la calculer 12 fois. Nous n'avons besoin d'effectuer qu'un seul calcul à la fin de l'année. Ensuite, nous curons partiellement cette fonction pour nous aider à comprendre

// 部分柯里化完的函数
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()

Ensuite, nous écrivons un curry général et une fonction qui sera curry . Le code est le suivant

// 通用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()

Limitation des fonctions
La plupart des fonctions en JavaScript sont activement déclenchées par les utilisateurs. Généralement, il n'y a pas de problème de performances, mais dans certains cas particuliers, elles ne sont pas directement contrôlées par l'utilisateur. . Il est facile qu'un grand nombre d'appels entraîne des problèmes de performances. Après tout, les opérations DOM sont très coûteuses. Certains de ces scénarios sont répertoriés ci-dessous :

  • événement window.resise.
  • Souris, saisie et autres événements.
  • Progression du téléchargement

Utilisons des fonctions d'ordre supérieur pour implémenter la limitation des fonctions

/**
* 节流函数
* @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)

points La fonction time

La fonction de limitation nous fournit une solution pour limiter la fréquence des appels de fonctions. Ensuite, nous rencontrerons un autre problème. Certaines fonctions sont activement appelées par les utilisateurs, mais pour des raisons objectives, ces opérations affecteront sérieusement les performances de la page. Pour le moment, nous devons utiliser une autre méthode pour le résoudre.

Si nous devons insérer un grand nombre de nœuds DOM dans la page dans un court laps de temps, cela sera évidemment écrasant pour le navigateur. Cela peut provoquer le blocage du navigateur, nous devons donc exécuter des fonctions de partage de temps et insérer par lots.

/**
* 分时函数
* @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()

Fonctions de chargement paresseux

Dans le développement Web, un certain travail de détection est toujours inévitable en raison des différences entre certains navigateurs.

En raison des différences entre les navigateurs, nous devons souvent résoudre divers problèmes de compatibilité. Prenons un exemple très simple et couramment utilisé : les fonctions de liaison d'événements qui peuvent être utilisées universellement dans différents navigateurs.
Une façon courante de l'écrire est comme ceci :

// 常用的事件兼容
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)
 }
 }
})()

De cette façon, nous pouvons renifler avant que le code ne soit chargé, puis renvoyer une fonction. Mais si nous le mettons dans une bibliothèque publique et ne l'utilisons pas, c'est un peu redondant. Ensuite, nous utilisons des fonctions paresseuses pour résoudre ce problème :

// 惰性加载函数
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;)
})

Une fois entrée dans la branche, l'implémentation de la fonction est modifiée à l'intérieur de la fonction. Après réécriture, la fonction est la fonction que nous attendons, et elle ne le sera pas. être utilisé la prochaine fois que nous entrerons dans la fonction. Il y a à nouveau une instruction de branchement conditionnelle.

Enfin

Afin de vous aider à rendre l'apprentissage plus facile et plus efficace, je partagerai avec vous gratuitement une grande quantité d'informations pour vous aider à devenir un ingénieur de pile ou même architecte. Il y a de nombreux obstacles sur la route. Ici, je recommande un cercle d'apprentissage et d'échange front-end full-stack pour tout le monde : 866109386 Tout le monde est invité à rejoindre le groupe pour discuter, apprendre et progresser ensemble.

Lorsque vous commencerez réellement à apprendre, vous ne saurez inévitablement pas par où commencer, ce qui entraînera une faible efficacité et affectera votre confiance pour continuer à apprendre.

Mais le plus important c'est qu'on ne sait pas quelles technologies il faut maîtriser, et qu'on tombe souvent dans des pièges lors de l'apprentissage, ce qui au final fait perdre beaucoup de temps, il faut donc quand même avoir des outils efficaces ressources.

Enfin, je souhaite à tous les programmeurs front-end qui rencontrent des goulots d'étranglement et ne savent pas quoi faire, et je vous souhaite tout le meilleur dans votre futur travail et vos entretiens.


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer