Funkce vyššího řádu v JavaScriptu Made Simple

Funkce vyššího řádu jsou jedním z témat, která mohou být těžko pochopitelná. Tento článek vám pomůže pochopit, co jsou funkce vyššího řádu a jak s nimi pracovat. Dozvíte se také o rozdílu mezi funkcemi vyššího řádu a funkcí prvního řádu a o funkcích vyššího řádu zabudovaných v JavaScriptu.

JavaScript a funkce první třídy

V JavaScriptu se s funkcemi zachází jako s prvotřídními občany. To znamená, že v JavaScriptu, jiných funkčních programovacích jazycích, jsou funkce ve skutečnosti objekty. Jsou speciálním typem Function objektů. To znamená, že všechny věci, které můžete dělat s jinými typy, jako je objekt, řetězec nebo číslo, můžete dělat také s funkcemi.

Přiřazení funkcí proměnným

Přiřazení funkcí proměnným je běžná věc, kterou s nimi můžete dělat. To se také nazývá vytváření výrazů funkcí. Důvodem tohoto názvu je, že vytváříte funkci uvnitř výrazu. Tento výraz pak přiřadíte proměnné. Od této chvíle můžete používat název proměnné k odkazování a volání této funkce.

// Create function with function expression
// and assign it to a variable
const myFunc = function() {
  return 'Hello'
}

Jedna věc, kterou si musíte pamatovat, když používáte výraz funkce, je, že nejsou zvednuté. To znamená, že nemůžete používat funkční výrazy, než je deklarujete. To není problém, pokud používáte deklaraci funkce pomocí function klíčové slovo. Funkce definované pomocí jsou zvednuty a můžete je použít předtím, než je deklarujete.

// This doesn't work:
// Try to use function
// created with function expression
// before it is declared
myFunc()
// myFunc is not defined

const myFunc = function() {
  return 'Hello'
}


// This works:
// Try to use function
// created with function declaration
// before it is declared
myFunc()
// 'Hello'

function myFunc() {
  return 'Hello'
}

Předávání funkcí jako argumentů

Jedna věc, kterou jste možná viděli, je předávání funkcí jako argumentů jiným funkcím. Tyto předané funkce jsou obvykle předány jako poslední argument a později použity jako zpětná volání. Zpětné volání je funkce, která se provede po dokončení všech operací. Toto je běžná praxe.

Funguje to díky tomu, že JavaScript je jednovláknový programovací jazyk. To znamená, že v daný okamžik lze provést pouze jednu operaci. Když tedy předáte funkci zpětného volání a vyvoláte ji na konci, bude vyvolána po dokončení všech předchozích operací.

Zpětná volání byla velmi populární před sliby a async/wait. Bohužel často vedly k něčemu, čemu se říká peklo zpětného volání.

// Create a function that takes another function
// as a parameter and uses that function
// as a callback
function myFunction(text, callbackFunc) {
  console.log(text)
  callbackFunc()
}

// Create callback function
function myCallbackFunc() {
  console.log('I am a callback function')
}

// Invoke "myFunction()" function
// passing some text and callback function
myFunction('This will show before invoking callback.', myCallbackFunc)
// 'This will show before invoking callback.'
// 'I am a callback function'

Jednou situací, kdy jsou funkce často předávány jako argumenty, je situace, kdy pracujete s posluchači událostí. addEventListener metoda přebírá tři parametry:typ události k poslechu, objekt nebo funkci a možnosti. Druhý parametr, funkce, je zpětné volání. Při konkrétním addEventListener je spuštěna tato funkce zpětného volání.

// Find button in the DOM
const button = document.querySelector('#btn')

// Create function to handle the event
function handleButtonClick() {
  // Show log on click
  console.log('click on: ', this)
}

// Create event listener for click event on button
// and pass "handleButtonClick" function as a callback function
button.addEventListener('click', handleButtonClick)


// Or
// Find button in the DOM
const button = document.querySelector('#btn')

// Create event listener for click event on button
// and pass a callback function directly
button.addEventListener('click', function() {
  // Show log on click
  console.log('click on: ', this)
})

Poznámka:V prvním příkladu jste předali funkci „handleButtonClick“ podle názvu, bez závorek. To znamená, že předáváte samotný objekt funkce. Pokud byste tuto funkci předali se závorkami, znamenalo by to, že funkci okamžitě vyvoláte a předáte výsledek provedení této funkce.

Vrácení funkcí

Další věc, kterou můžete s funkcemi udělat, je, že je můžete vrátit z jiných funkcí. To je něco očekávaného, ​​protože funkce jsou typem objektů a objekty můžete vracet v JavaScriptu. To může být užitečné, když chcete použít funkci k vytvoření šablon pro nové funkce.

// Create function that returns function
// a template for new functions
function changeText(word, replacement, text) {
  // Return a new function
  // that will be later assigned to a variable
  return function(text) {
    return text.replace(word, replacement)
  }
}

// Create new function for changing text
// to positive mood using the "changeText" function
// This invokes and "changeText" function
// and stores returned function in a variable
const makePositive = changeText(/bad/g, 'good')

// Create new function for changing text
// to negative mood using the "changeText" function
// This invokes and "changeText" function
// and stores returned function in a variable
const makeNegative = changeText(/good/g, 'bad')

// Call the "makePositive" function
// This invokes the returned function
// stored in the variable after calling
// the "changeText" function
makePositive('Everything that happened is bad and everything that will happen is also bad.')
// 'Everything that happened is good and everything that will happen is also good.'

// Call the "makePositive" function
// This invokes the returned function
// stored in the variable after calling
// the "changeText" function
makeNegative('Everything that happened is good and everything that will happen is also good.')
// 'Everything that happened is bad and everything that will happen is also bad.'

Funkce vyššího řádu:Základy

Možná se divíte, co mají tyto tři věci společného s funkcemi vyššího řádu. Ten první o proměnných nic moc. Nicméně, druhý a třetí, předávání funkcí jako argumenty a vracející funkce, hodně. Tady jde o to, že funkce vyššího řádu jsou funkce, které berou jinou funkci jako argument a/nebo vrací jinou funkci.

Ve všech příkladech, kde jste předávali funkci jako argument nebo vraceli funkci, jste ve skutečnosti pracovali s funkcemi vyššího řádu. Asi jste čekali něco složitějšího než tohle. Zejména kvůli tomu, kolik vývojářů JavaScriptu mluví o funkcích vysokého řádu. Nicméně je to opravdu tak jednoduché.

// High-order function no.1:
// Function that takes a function as a argument
function myHighOrderFuncOne(myFunc) {
  // some code
}

// High-order function no.2:
// Function that returns a function
function myHighOrderFuncTwo() {
  // some code

  // Return a function
  return function() {
    // some code
  }
}

// High-order function no.3:
// Function that takes a function as a argument
// and also returns a function
function myHighOrderFuncThree(myFunc) {
  // some code

  // Return a function
  return function() {
    // some code
  }
}

Funkce vyššího řádu vs funkce prvního řádu

V JavaScriptu existují dva typy funkcí, funkce vyššího řádu a funkce prvního řádu. Jediný rozdíl mezi těmito dvěma je v tom, že funkce prvního řádu neberou funkci jako argument a/nebo nevrací funkci.

// Example of high-order function:
function myHighOrderFunc(myFunc) {
  // some code
}

// Example of first-order function:
function myFirstOrderFunc() {
  // some code
}

Nativní funkce vyššího řádu JavaScript

Jedna zajímavá věc na funkcích vysokého řádu je, že v JavaScriptu jsou ve skutečnosti některé vestavěné funkce vyššího řádu. Je pravděpodobné, že s některými z nich již pracujete. Posluchači událostí, kde jeden z nich. Tyto tři se používají nejčastěji. Poznámka:pravděpodobně pro jednoduchost se tyto funkce vyššího řádu často používají s funkcemi šipek.

map()

První z vestavěných funkcí vyššího řádu je map() . No, technicky je to metoda. Každopádně map() je funkce nebo metoda, kterou můžete použít na pole k iteraci nad nimi. Během této iterace můžete pracovat s jednotlivými položkami uvnitř pole. map() vezme jeden argument, funkci, která bude použita jako zpětné volání.

Tato funkce zpětného volání vám umožňuje pracovat s položkami uvnitř pole. Během každé iterace je do této funkce zpětného volání předána jedna položka spolu s indexem položky a celým zdrojovým polem.

// Create an array of numbers
const myArray = [1, 5, 7, 9]


// map example no.1: using regular function
// Create callback function for map()
function toThirdPower(item /* index, array */) {
  // Raise the item to the third power
  return item ** 3
}

// Use map to iterate over items in myArray array
// passing the toThirdPower() function as a callback function
myArray.map(toThirdPower)
// [ 1, 125, 343, 729 ]


// map example no.2: using anonymous function
myArray.map(function(item /* index, array */) {
  // Raise the item to the third power
  return item ** 3
})
// [ 1, 125, 343, 729 ]


// map example no.3: using arrow function
myArray.map((item /* index, array */) => {
  // Raise the item to the third power
  return item ** 3
})
// [ 1, 125, 343, 729 ]


// Or, a shorter version of arrow function
myArray.map((item) => item ** 3)

Nyní se podívejme, jak by stejná úloha vypadala například s for smyčka.

// Alternative to map
// Create an array of numbers
const myArray = [1, 5, 7, 9]

// Prepare new empty array
let myNewArray = []

// Loop through myArray array
for (let idx = 0; idx < myArray.length; idx++) {
  // Raise each number the the third power
  // and store it inside myNewArray array
  myNewArray.push(myArray[idx] ** 3)
}

// Log the value of myNewArray
console.log(myNewArray)
// [ 1, 125, 343, 729 ]

filtr()

Další často používanou vestavěnou funkcí vyššího řádu je filter() metoda. Tato metoda vám pomůže iterovat pole a vytvořit nové pole pouze s položkami, které splňují určitá kritéria. Podobně jako map() , filter() také přebírá jeden argument, funkci zpětného volání. Při každé iteraci předá do této funkce zpětného volání jednu položku.

Předá také index položky a celé zdrojové pole. Funkce zpětného volání se používá k určení podmínky nebo testu, kterým musí každá položka projít. Výsledek tohoto testu musí být booleovský, true pro předání a false za selhání.

// Create an array of strings
const myArray = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']


// filter example no.1: using regular function
// Create callback function for filter()
function testTheWord(word /* index, array */) {
  // Remove all words which length is not an even number
  return word.length % 2 === 0
}

// Use filter to iterate over items in myArray array
// passing the testTheWord() function as a callback function
myArray.filter(testTheWord)
// [ 'Monday', 'Thursday', 'Friday' ]


// filter example no.2: using anonymous function
myArray.filter(function(word /* index, array */) {
  // Remove all words which length is not an even number
  return word.length % 2 === 0
})
// [ 'Monday', 'Thursday', 'Friday' ]


// filter example no.3: using arrow function
myArray.filter((word /* index, array */) => {
  // Remove all words which length is not an even number
  return word.length % 2 === 0
})
// [ 'Monday', 'Thursday', 'Friday' ]


// Or, a shorter version of arrow function
myArray.filter((word) => word.length % 2 === 0)

Zkusme znovu provést stejnou úlohu s for smyčka.

// Alternative to map
// Create an array of strings
const myArray = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']

// Prepare new empty array
let myNewArray = []

// Loop through myArray array
for (let idx = 0; idx < myArray.length; idx++) {
  // Test each string if it's length is an even number
  if (myArray[idx].length % 2 === 0) {
    // and store it inside myNewArray array
    myNewArray.push(myArray[idx])
  }
}

// Log the value of myNewArray
console.log(myNewArray)
// [ 'Monday', 'Thursday', 'Friday' ]

reduce()

Poslední, reduce() , je metoda, která vám pomůže zredukovat pole na jednu položku. Jako argument bere funkci zpětného volání. Ve funkci zpětného volání předává čtyři argumenty:akumulovanou hodnotu, hodnotu aktuální položky, index aktuální položky a celé zdrojové pole. Můžete také zadat počáteční hodnotu jako druhý argument po funkci zpětného volání.

// Create an array of test scores
const myArray = [
  {
    name: 'tom',
    score: 42
  },
  {
    name: 'jessica',
    score: 78
  },
  {
    name: 'jacob',
    score: 92
  },
  {
    name: 'cindy',
    score: 38
  },
  {
    name: 'timothy',
    score: 83
  }
]


// reduce example no.1: using regular function
// Create callback function for reduce()
function sumScores(acc, curVal) {
  // Sum all scores by adding
  // the value of score in each object
  // to the accumulated value
  return acc + curVal.score
}

// Use reduce to iterate over items in myArray array
// passing the sumScores() function as a callback function
// and setting the initial value to 0
myArray.reduce(sumScores, 0)
// 333


// reduce example no.2: using anonymous function
myArray.reduce(function(acc, curVal) {
  // Sum all scores
  return acc + curVal.score
}, 0) // set the initial value to 0
// 333


// reduce example no.3: using arrow function
myArray.reduce((acc, curVal) => {
  // Sum all scores
  return acc + curVal.score
}, 0) // set the initial value to 0
// 333


// Or, a shorter version of arrow function
myArray.reduce((acc, curVal) => acc + curVal.score, 0)
// 333

Ještě jednou zkuste for smyčka namísto reduce() metoda.

const myArray = [
  {
    name: 'tom',
    score: 42
  },
  {
    name: 'jessica',
    score: 78
  },
  {
    name: 'jacob',
    score: 92
  },
  {
    name: 'cindy',
    score: 38
  },
  {
    name: 'timothy',
    score: 83
  }
]

// Prepare variable for total
let total = 0

// Loop through myArray array
for (let idx = 0; idx < myArray.length; idx++) {
  // and store it inside myNewArray array
  total += myArray[idx].score
}

// Log the value of total
console.log(total)
// 333

Závěr:Funkce vyššího řádu v JavaScriptu Made Simple

V tomto článku jste se dozvěděli, jak JavaScript zachází s funkcemi a co to znamená. Také jste se naučili, že funkce můžete předávat jako argumenty a vracet je z jiných funkcí. Dále jste se dozvěděli, co jsou funkce vyššího řádu, co je odlišuje od funkcí prvního řádu a jak fungují.

Nakonec jste se dozvěděli o vestavěných funkcích vysokého řádu JavaScriptu a o tom, jak je používat. Těch bylo map() , filter() a reduce() . Doufám, že vám tento článek pomohl pochopit funkce vyššího řádu. Tímto vám děkuji za váš čas.