Javscript

JavaScript’te İşlev Oluşturma – JSManifest

JavaScript’i uygulama yazarken en sevdiğim dil yapan şey, sonunda çalışan bir programa yol açabilecek pek çok farklı türde işlevi bir araya getirme yetenekleridir.

Bunu farklı şekillerde gösteren JavaScript kodunu her yerde görüyoruz.

İşlevleri birlikte oluşturmak, özellikle çalıştıklarında son derece eğlenceli hale gelebilir. Ne yazık ki bunu başarmak her zaman kolay bir şey değildir çünkü birleştirilmiş kod yazmak hatasız bir şekilde yapılmalıdır, aksi takdirde çalışmayacaktır.

JavaScript’te, işlevler gibi şeyleri birlikte oluşturmanın kuralları vardır.

Bu makalede, JavaScript’te bazı besteleme örneklerinin üzerinden geçeceğiz ve beste yaparken her zaman akılda tutulması gereken önemli kavramlardan bahsedeceğiz.

bestelemek ne demek?

Beste yapmak oluşturmak için birden fazla şeyi birleştirmek anlamına gelir. daha büyük şey. İki veya daha fazla işlevi yepyeni bir işlevde birleştirdiğiniz matematikte genel bir kavramdır. Çoğumuz okulda büyürken bu kavramla şuna benzer bir şey şeklinde çalışıyoruz. f(g(x)) “f of g of x” olarak telaffuz edilir.

JavaScript’te şöyle görünebilir:

const f = console.log
const g = (str) => `Hello, ${str}`
const sayWord = (x) => f(g(x))

sayWord('bryan') 

Kompozisyon fonksiyonları hakkında konuşalım. Fonksiyonları birlikte oluşturduğumuzda, asıl amaç bir fonksiyon alıp onu başka bir fonksiyonla birleştirmek–böylece ikisi bir arada olduğunda bize istediğimiz değeri üretmeye yardımcı olan daha gelişmiş bir fonksiyon verir. İnsanların, kodu küçültmek ve daha uygun yeniden kullanılabilir bir kod parçası sağlamak gibi işlevler oluşturmayı tercih etmelerinin birçok iyi nedeni vardır.

JavaScript’te, işlevler birinci sınıf olarak kabul edilirler, yani etrafta dolaşabilirler ve tıpkı dizeler, sayılar, booleanlar, nesneler vb. gibi bir “değer” kılığına girebilirler. Bunun anlamı, işlevlerin diğer işlevleri argüman olarak al ve hatta olabilir dönüş fonksiyonları. JavaScript’i çok güçlü bir dil yapan şey budur çünkü onları istediğiniz yere atabilirsiniz.

Ekleyen bir fonksiyon örneğine bakalım 'hello' bir dizeye:

function append(str) {
  return `hello ${str}
}

Bu işlevi kullanmak ve aşağıdaki gibi bir dize almak kolaydır:

const result = append('Gary') 

Ancak az önce öğrendiğimiz gibi, fonksiyonlar fonksiyon alabilir, bu yüzden sadece ikinci argümanı kullanalım ve fonksiyona bir fonksiyon argümanı ekleyerek neler yapabileceğimizi test edelim:

function append(str, modify) {
  return `hello ${str}
}

Tamam, şimdi burada bir şeyler yapmak için ikinci argüman için bir boşluk bıraktık. Sadece bu basit değişikliği yaparak, örneğin bunun gibi bazı ek işlevler için açıldı:

function append(str, modify = (s) => s) {
  return `hello ${modify(str)}`
}

function capitalize(value) {
  return value.toUpperCase()
}

const result = append('boss', capitalize) 

JavaScript’in yukarıda gördüğümüz gibi ne kadar esnek olabileceğinden dolayı, JavaScript’te işlevlerin nasıl oluşturulacağını öğrenmek, JavaScript uygulamaları geliştirirken edinilmesi gereken en önemli becerilerden biridir!

Beste yapmak neden önemlidir?

Daha önce de belirtildiği gibi, insanların işlevler oluşturmasının birçok iyi nedeni vardır.

Şu senaryoya bakalım:

function doubleTheNums(obj) {
  const keys = Object.keys(obj)
  for (let index = 0; index < keys.length; index++) {
    const key = keys[index]
    const innerObj = obj[key]
    const innerObjKeys = Object.keys(innerObj)
    for (let innerIndex = 0; innerIndex < innerObjKeys.length; innerIndex++) {
      const innerObjKey = innerObjKeys[innerIndex]
      const innerObjKeyValue = innerObj[innerObjKey]
      if (typeof innerObjKeyValue === 'number') {
        innerObj[innerObjKey] = innerObj[innerObjKey] * 2
      }
    }
  }
  return obj
}

const results = {
  game1: {
    lakers: 40,
    celtics: 40,
    overtime: {
      lakers: 48,
      celtics: 58,
    },
  },
  game2: {
    lakers: 40,
    celtics: 21,
  },
  game3: {
    lakers: 12,
    celtics: 29,
  },
}

console.log(doubleTheNums(results))

sonuç:

{
  "game1": {
    "lakers": 80,
    "celtics": 80,
    "overtime": {
      "lakers": 48,
      "celtics": 58
    }
  },
  "game2": {
    "lakers": 80,
    "celtics": 42
  },
  "game3": {
    "lakers": 24,
    "celtics": 58
  }
}

bu doubleTheNums işlev, bir nesneye bakmaktan ve eğer bir nesneyse sayı değerini ikiye katlamaktan sorumludur. number tip. Bunun yerine neden bunu oluşturulmuş bir işleve dönüştürmeliyiz? Önce mevcut fonksiyonun yaşadığı bazı problemlere bakalım:

  1. Geçirilen nesne derin bir şekilde iç içe geçmişse, kod garip bir şekilde bir ağaç şekli gibi aşağı doğru itilmeye devam edecektir. Ama kimsenin böyle bir şey için zamanı yok.
  2. İçeri aktarılan nesne derin bir şekilde iç içe geçmişse, içsel değişkenleri adlandırmak için fikirlerin tükendiği değerli beyin enerjisini gereksiz yere kaybederiz (innerObjKey, innerObjKeyValue yol açabilir deeplyInnerObjKey, deeplyInnerObjKeyValue, innerInnerInnerObjKey, innerInnerInnerObjKeyValuevb)
  3. Kod zamanla tekrar eder. Bu kafamızı karıştırabilir ve kimse karıştırılmak istemez.
  4. Dosya boyutu artıyor

Tanrıya şükür, kolayca işlevler atabilir ve buna bir gün diyebiliriz:

function doubleTheNums(obj) {
  const keys = Object.keys(obj)
  for (let index = 0; index < keys.length; index++) {
    const key = keys[index]
    const value = obj[key]
    if (typeof value === 'number') {
      obj[key] = obj[key] * 2
    } else if (value && typeof value === 'object') {
      doubleTheNums(obj[key])
    }
  }
  return obj
}

const results = {
  game1: {
    lakers: 40,
    celtics: 40,
    overtime: {
      lakers: 48,
      celtics: 58,
    },
  },
  game2: {
    lakers: 40,
    celtics: 21,
  },
  game3: {
    lakers: 12,
    celtics: 29,
  },
}

console.log(doubleTheNums(results))

sonuç:

{
  "game1": {
    "lakers": 80,
    "celtics": 80,
    "overtime": {
      "lakers": 96,
      "celtics": 116
    }
  },
  "game2": {
    "lakers": 80,
    "celtics": 42
  },
  "game3": {
    "lakers": 24,
    "celtics": 58
  }
}

Az önce kullandığımız tekniğin adı özyineleme Bu, daha önce ortaya koyduğumuz tüm sorunları çözen çok kullanışlı bir tekniktir.

Mesele şu ki, JavaScript’te fonksiyonları bu kadar özgürce kullanabilmemiz, fonksiyonları oluşturmayı bir çok önemli konu! Ancak, programlama konusunda yeniyseniz, daha gelişmiş, karmaşık işlevler oluşturmak için işlevler oluşturmanın herhangi bir programlama dilinde yaygın bir yardımcı program olduğunu burada belirtmekte fayda var. Ancak JavaScript’e odaklanacağız çünkü açıkçası bu yazı JavaScript hakkında.

JavaScript kitaplıklarının kaynak kodlarına baktıysanız, muhtemelen işlev oluşturmada gerçekten başarılı olan çok sayıda kod örneğine maruz kalmışsınızdır. Ayrıca, bu oluşturulmuş işlevlerin çoğunun çok daha küçük, modüler işlevlerden oluştuğunu fark etmiş olabilirsiniz.

Şimdi hiçbir şey yapmayan bir fonksiyona bakalım:

function doNothing(obj) {
  return obj ? obj : obj
}

const result = doNothing({ name: 'Bob' })

bir oluşturabiliriz compose Aynı şekilde kullanılabilecek bir işlev daha oluşturmak için bir dizi işlev alan işlev:

const compose = (...fns) => (arg) =>
  fns.reduceRight((acc, fn) => (fn ? fn(acc) : acc), arg)

Şimdi aynı işlevselliği korurken bir çok işe yaramaz işlevi aynı anda alabiliriz!

function doNothing(obj) {
  return obj ? obj : obj
}

function doSomethingButNothingStill(obj) {
  if (obj) {
    obj = obj
  }
  return obj ? obj : obj
}

const evaluateSomething = compose(
  doSomethingButNothingStill,
  doNothing,
)

const result = evaluateSomething({
  name: 'Bob',
  lastName: 'Lopez
})

Gerçek bir dünya senaryosunda faydalıdır çünkü nihai bir değer üretmek için aynı imzaya sahip birden çok işlevi almanız gerekebilir. Birden çok işlev aynı imzaya sahipse ve hepsi aynı değer üzerinden çağrılacaksa, örneğin, o zaman oluşturucuyu kullanmanın tam zamanı:

const compose = (...fns) => (arg) =>
  fns.reduceRight((acc, fn) => (fn ? fn(acc) : acc), arg)

const add = (num1) => (num2) => num1 + num2
const multiply = (num1) => (num2) => num1 * num2
const subtract = (num1) => (num2) => num1 - num2

const composedOperations = compose(add(5), multiply(2), subtract(3))

const compute = (arr, initialNum = 0) =>
  arr.reduce((acc, val) => composedOperations(acc), initialNum)

console.log(compute([-10, 25, 55, 22], 6))

Son örnekte, birkaç matematik işlemi kullanmamız gerekirse, nihai değeri üretmek için birden çok matematik operatör işlevi oluşturmaya karar verdik. Bu, onu biraz daha uygun hale getirdi, çünkü sonuçta yine de aynı argümanı, sayı dizisinde dolaşırken işlevlere iletmiş olacaktık.

Mevcut olanlarla birlikte kullanılacak geri aramaları enjekte etme

İşlevleri oluşturmak için iyi kullanım olanakları sonsuzdur. Ancak bu makaleyi tamamlamak için, çeşitli senaryolar elde etmek için işlevlerin nasıl oluşturulabileceğini daha iyi anlayabilmeniz için başka bir yararlı kullanım örneğini gözden geçireceğiz.

Sırada bir tepki uygulaması için bir senaryoya bakacağız.

Bir düğme bileşeni oluşturduğumuzu hayal edin. bir sahip olacak onClick olay dinleyicisi, böylece kullanıcılar tıkladığında olayı alacak ve name arasında currentTarget tıklanan öğe:

import React from 'react'

function MyButton({ children, ...rest }) {
  return (
    <button onClick={(e) => window.alert(e.currentTarget.name)} {...rest}>
      {children}
    </button>
  )
}

function App() {
  return (
    <div>
      <MyButton name="alerter">Alert</MyButton>
    </div>
  )
}

export default App

Daha sonra bir ek eklemek istersek ne olur? onClick ek davranış için dışarıdan aynı düğmeye işleyici? Bunu yaparak bu hedefe kolayca ulaşabiliriz:

import React from 'react'

function MyButton({ children, onClick: onClickProp, ...rest }) {
  return (
    <button
      onClick={(e) => {
        window.alert(e.currentTarget.name)
        if (onClickProp) {
          onClickProp(e)
        }
      }}
      {...rest}
    >
      {children}
    </button>
  )
}

function App() {
  function onClick(e) {
    console.log('Here is the event object', e)
  }
  return (
    <div>
      <MyButton name="alerter" onClick={onClick}>
        Alert
      </MyButton>
    </div>
  )
}

export default App

Ancak bu iyi bir çözüm değil çünkü bu işlevselliğe ihtiyaç duyan başka bileşenlerimiz olsaydı bu işlemi tekrarlamamız gerekirdi. Ayrıca, işleyiciyi daha sonra gerçekten garip hale getirir.

Birden çok oluşturan bir işlev onClick oluşturmak için işlevler geliştirilmiş onClick işlevi muhtemelen daha iyi bir fikirdir çünkü onu aşağıdaki gibi diğer olay işleyiciler için yeniden kullanabilirsiniz. onMouseOver, onMouseLeavevb. Son sorunu çözmek için kullanabileceğimiz bir fonksiyon:

function callAll(...fns) {
  return (...args) => fns.forEach((fn) => fn && fn(...args))
}

Şimdi onu çirkin çözümümüzü zarif bir çözümle değiştirmek için kullanabiliriz:

import React from 'react'
import callAll from '../utils/callAll'

function MyButton({ children, onClick: onClickProp, ...rest }) {
  function onClick(e) {
    window.alert(e.currentTarget.name)
  }
  return (
    <button onClick={callAll(onClick, onClickProp)} {...rest}>
      {children}
    </button>
  )
}

function App() {
  function onClick(e) {
    console.log('Here is the event object', e)
  }
  return (
    <div>
      <MyButton name="alerter" onClick={onClick}>
        Alert
      </MyButton>
    </div>
  )
}

export default App

Temelde aynı şeyi başarır. Ancak, işlevleri oluştururken çoğu zaman oluşturduğunuz işlevlerin imzasının farkında!

örneğin bizim callAll Oluşturduğumuz fonksiyonların hiçbirine ilk argüman olarak tamamen farklı bir değer verilme olasılığının olmamasını sağlamalıydık. Daha önceki örneğimizde compose, her işlevin sonucu ardışık düzendeki bir sonraki işleve ilk argüman olarak iletildiği için durum böyleydi. İçinde callAlla .forEach ardışık düzendeki her işlevin her seferinde olay nesnesini almasını sağladı, çünkü tanım gereği arayan kişiye bir tane döndürmeye çalışsa bile hiçbir şey döndürmez.

İlgili Makaleler

Bir cevap yazın

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

Başa dön tuşu