JavaScript’te Yüksek Dereceli İşlevlerin Gücü – JSManifest

JavaScript'te Yüksek Dereceli İşlevlerin Gücü – JSManifest

JavaScript, var olan hemen hemen her JavaScript uygulamasındaki işlevleri kullanır. İşlevler sayesinde dil, sağlık hizmetlerinde yapay zeka işlevselliği oluşturmak gibi birçok güçlü şeyi yapabilir.

Bu makalede bahsedeceğim güçlü bir özellik, a adı verilen işlevleri kullanır. üst düzey fonksiyon. Daha yüksek dereceli bir işlev, argüman olarak başka bir işlevi alan veya dönüş değeri olarak bir işlev döndüren bir işlevdir. Ayrıca bazı güçlü örnekler göstereceğim ve bunları kullanan vakaları kullanacağım, ki çoğu öğreticide bu eksik. Ama merak etmeyin, bu yazıda örnekler bulacaksınız.

Bununla birlikte, JavaScript ile oynuyorsanız, muhtemelen bu terimi daha önce duymuşsunuzdur. JavaScript’te daha yüksek dereceli işlevler yaygın olarak kullanılır ve bunlar, aşağıdakiler gibi yaygın olarak kullanılan işlevlerde bulunur: .map, .filter, .reduce ve .forEach.

JavaScript konusunda biraz yeniyseniz, kafanız karışmış olabilir. nerede bu yüksek dereceli işlevler bu yöntemlerdedir.

Bu dizi yöntemlerinin argümanları olarak işlev geri çağrılarını bildirdiğinizde bunları görürsünüz:

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


arr.map(function(value) {
  return value
})


arr.filter(function(value) {
  return typeof value === 'number'
})


arr.forEach(function(value) {
  console.log(value)
})


arr.reduce(function(acc, value) {
  if (typeof value === 'number') {
    acc += value
  }
  return acc
}, 0)

Ancak daha yüksek dereceli işlev, aşağıdaki gibi yöntemlere ilettiğiniz işlev değildir. .map. gibi yöntemler .map dır-dir daha yüksek dereceli fonksiyon.

Daha yüksek mertebeden fonksiyonların, argüman olarak başka bir fonksiyonu alan fonksiyonlar olabileceğinden bahsettiğimizde, bir fonksiyona geçtiğinizde tam olarak yaptığı şey buydu.

İşte tam olarak aşağıdaki gibi çalışan bir uygulama .map yöntem şunları yapar:

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
}

Kod parçacığına bakıldığında, callback parametresi, argüman olarak ilettiğimiz işlevin tamamen aynısıdır. .map daha önce gösterdiğim yöntem:


arr.map(function(value) {
  return value
})

Daha kesin olmak gerekirse, tam kod parçasını bizimkiyle aynı adla yeniden adlandırmama izin verin. map daha net görebilmeniz için işlev uygulaması:

const callback = function(value) {
  return value
}

arr.map(callback)



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
}

İlk başta, JavaScript’te kod yazmanın işe yaramaz bir yolu gibi görünebilir. Tüm bunlardan kaçınıp her şeyi aynı anda tek bir işlevde yapmak varken, neden bir işlevi geçip başka bir işlevi döndürmekle uğraşasınız ki?

Üst düzey işlevlerin masaya getirdiği en büyük fayda, yeniden kullanılabilirlik ve basitliktir. Ama aynı zamanda güzel kod yazmaktan da faydalanırlar. Evet, JavaScript’te çirkin kod ve güzel kod gibi şeyler vardır.

Yeniden kullanılabilirlik göz önünde bulundurularak, bazı çok güçlü kod kompozisyonları.

Kod Oluşturma ve Güçlü Örnekler

Artık kodda üst düzey işlevlerin nasıl göründüğünü bildiğimize göre, bazı kullanım durumlarının neler olduğunu ve nerede parlamaya başladıklarını merak ediyor olabilirsiniz.

Diyelim ki bir kurbağa listemiz var:

const frogsList = [
  
  {
    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,
  },
]

Kurbağaları belirli bir cinsiyet türüne göre filtrelemek için olmadan daha yüksek dereceden bir işlev, şöyle bir şey yapmamız gerekirdi:

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


const maleFrogs = filterGender('Male', frogsList)

Bu gayet iyi. Ancak, bir uygulamada birden çok kez kullanılırsa hantal olabilir. Kurbağalar hakkında devasa bir uygulamamız olsaydı, filterGender defadan fazla kullanılabilir.

İkinci Bir Adım Daha İleriye Götürmek

Farklı bir kurbağa listesi getirseydin, araman gerekirdi. filterGender tekrar ve cinsiyetinizi yeni listeyi filtrelemek için ilk argüman olarak yeniden beyan edin:

function getFrogs() {
  
}

const newFrogs = getFrogs()
const moreMaleFrogs = filterGender('Male', newFrogs) 

Eğer hiç duymadıysanız KURU Prensip olarak, bunu anlamanızı şiddetle tavsiye ederim. Kod parçacığımız, ilk argüman nedeniyle bu kuralı ihlal ediyor. Biz daha iyisini yapabiliriz.

Bu sorunu çözmek için daha yüksek dereceli fonksiyonlar kavramını kullanabiliriz.

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

Ve şimdi, aynen böyle, bu cinsiyet filtreleyiciyi bir değişkene atayabiliriz ve artık kurbağaları filtrelerken asla aynı cinsiyeti bildirmek zorunda kalmayacağız!

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

Ama bekleyin, hepsi bu değil. Onları bestelemekten elde ettiğimiz ek bir fayda var. Sadece bir daha asla dişi kurbağalar için bir filtre yazmak zorunda kalmamanın avantajını sağlamakla kalmıyoruz, aynı zamanda aynı cinsiyeti farklı kurbağa listelerinden filtrelemek için döndürülen işlevi yeniden kullanma yeteneğine de sahibiz!

Artık çok sayıda kod yazmak zorunda kalmadan birden fazla kurbağa listesinden dişileri filtreleyebiliriz:

const frogsList = [
  
  {
    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)

Üçüncü Adımı Daha İleriye Taşımak

Eğer sen hala yeterince ikna olmadı JavaScript dilinde yüksek dereceli işlevlerin ne kadar güçlü olduğuna dair örnekle devam edelim. daha da genel bir işlev daha yüksek düzeyde yeniden kullanılabilirlik oluşturmak için:

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

Daha önce bir kurbağanın cinsiyeti için yeniden kullanılabilir bir işlev yapma yeteneğimiz vardı. Ancak, işin mantığını soyutlayarak daha da ileri gidebiliriz. filter işlevi, böylece şimdi oluşturup yeniden kullanabiliriz farklı filtre fonksiyonları!

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)
})

Vay!

Daha önce, bir daha aynı cinsiyet türünü beyan etmek zorunda kalmadan bir cinsiyet filtreleme işlevini yeniden kullanma konusunda inanılmaz bir yeteneğe sahiptik, ancak şimdi kurbağaların nasıl filtrelenmesini istiyoruz! Harika!

Hatta hepsini aynı anda kullanabiliriz:

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)

Son Bir Kez Daha İleriye Götürmek

Bizim applyAllFilters işlevi işi oldukça iyi yapıyor. Bununla birlikte, devasa kurbağa listeleri için, çalıştığı için ağır bir görev haline gelebilir. filter nihai sonucu elde etmek için birden çok kez.

Basit, yeniden kullanılabilir yüksek dereceli bir fonksiyon yapmak için yüksek dereceli fonksiyonlar kavramını tekrar kullanabiliriz. bir filtreleri aynı anda uygulayarak tüm kurbağa listesini gözden geçirin.

Daha açık olmak için, bir göz atın döngü için kodlayın ve perde arkasında gerçekte neler olduğunu görmeye çalışın:

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
  }
}

Bakmanı istediğim satır şu:

newFrogs = filter(newFrogs)

Bu kod satırı, aynı kod satırıdır. return frogs.filter(filter) bu fonksiyonda:

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

Bu bir sorundur, çünkü filtre yöntemi yeni bir dizi oluşturur. Bunu yazdığımızda:

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

Filtre yöntemini 4 farklı kez çağırıyoruz. Başka bir deyişle, nihai sonucu elde etmek için JavaScript’in bellekte dört farklı dizi oluşturmasını sağlıyoruz.

Peki JavaScript’i nasıl sadece bir sonunda aynı sonucu elde etmek için dizi?

Tahmin ettin. Daha yüksek dereceli işlevleri kullanma!



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)
}


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) {
    
    return frogs.filter(combineFilters(...fns))
  }
}

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

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

const allFilteredFrogs = applyFrogFilterers(combinedFrogsList)

console.log(allFilteredFrogs)

Çözüm

Umarım üst düzey fonksiyonların ne kadar güçlü olduğuna ikna olmuşsunuzdur ve bu makaleyi okuyarak bu kavramın kullanım durumları hakkında biraz daha fikir edinmişsinizdir! Gelecekte daha fazlasını görün!

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.