JavaScript’te Gerçekten Yapmamanız Gereken 8 Korkunç Uygulama – JSManifest

JavaScript'te Gerçekten Yapmamanız Gereken 8 Korkunç Uygulama – JSManifest

JavaScript, kod geliştirirken gerçekten esnek ancak güçlü bir dil olabilir, ancak hangi uygulamalardan kaçınmamız gerektiğini bilmek her zaman kolay değildir.

Bu yazıda JavaScript’te Gerçekten Yapmamanız Gereken 8 Uygulamadan bahsedeceğiz ve yapmamalı çok geç olmadan önce.

Bu gönderideki örneklerin bazıları (veya tümü) Might bazılarınız için eski haber olsun. Ancak, bu yazıda burada listelenenler gibi bazı kötü uygulamaları kullanan bazı insanlar gördüğümde, daha fazla kişinin (siz dahil) geceleri uyuyabilmesi için bunu tekrar ziyaret etmeye değer olduğunu düşünüyorum.

Lafı fazla uzatmadan başlayalım!

1. Derin Aramalar… doğrulamadan

Bu, TypeScript gibi bir araçla kolayca önlenebilecek uygulamalardan biridir, ancak şaşırtıcı bir şekilde geliştiriciler bugün bu hatayı yapıyor.

İşte birinin yakın zamanda üretimde yaptığı bu senaryonun gerçek dünyadan bir örneği:

if (item['name']['data']['classTag']['name'] == 'Admin') {
  docFormObj['Admin'].map((temp: any) => {
    let itemType: string = item['type']
      .toString()
      .substr(0, item['type'].toString().length - 1)

    let tempType: string = temp['type']
      .toString()
      .substr(0, temp['type'].toString().length - 1)

    if (itemType == tempType) {
      if ((item['type'] & 1) === 1) {
        item.pageName = temp['releaseJump']
      } else {
        item.pageName = temp['privateJump']
      }
    }
  })
}

Bu uygulamayla ilgili sorun şu ki, bir nesne üzerinde derin bir arama yaparsak ve ara değerlerinden biri boşsa, uygulamanızı şu şekilde çökertebilecek bir hata üretecektir:

const item = {
  name: {
    data: {
      classTag: undefined,
    },
  },
}

if (item['name']['data']['classTag']['name'] == 'Admin') {
  
}

Sonuç:

TypeError: Cannot read property 'name' of undefined
    at Object.<anonymous> (/Users/abc/def/index.js:9:37)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
    at internal/main/run_main_module.js:17:47

Nesneler üzerinde derin özellikler ararken, her zaman bir aramadan kaynaklanan veri türünün beklendiğini doğrulamak (veya en azından bir aramadan kaynaklanan her değerin her zaman olacağından emin olmak) iyi bir uygulamadır. herhangi biri beklenen veri türü olmak veya bazı falsey değeri) daha fazla ilerlemeden önce:

if (
  item['name'] &&
  item['name']['data'] &&
  item['name']['data']['classTag'] &&
  item['name']['data']['classTag']['name'] === 'Admin'
) {
  
}

İsteğe bağlı zincirleme ile:

if (item?.['name']?.['data']?.['classTag']?.['name'] === 'Admin') {
  
}

Klasör yapınızla aşırıya kaçmak

olabileceğini biliyorum Gerçekten Özellikle redux gibi zamanla ölçeklenen bir kitaplık kullanmaya başladığımızda, uygulamalarımızı geliştirmeye başladığımızda mükemmel bir şekilde başlamayı ve büyük çaba göstermeyi cezbediyor.

Evet, projenizi piyasadaki bir sonraki en büyük şey olacak şekilde hazırlamak iyidir, ancak ara vermeye veya başka bir projeye dalmaya karar verirseniz, bunu kendiniz (ve hatta başkaları için) daha da zorlaştırabilirsiniz. kodunuzu okuyacağım) gelecekte geri dönmeye çalışırsanız.

Örneğin redux’u ele alalım. Bir React uygulaması oluşturuyorsak ve klasör yapımızın nasıl olmasını istediğimizi düşünürsek (ortak bir kuralın bileşenleri kendi klasörlerine ayırmak olduğunu göz önünde bulundurarak) şuna benzer bir sonuç elde edebiliriz: Bu:

Problem şu CounterButton, GithubButton ve/veya Flex Might asla tekrar değiştirilmelidir. 4 ay sonra hızlı ileri sararsak ve depomuz, klasörler içinde bileşenleri içeren klasörler içinde düzinelerce klasör içeriyorsa, bu gereksiz yere karmaşıktır. Aradığımız bir bileşeni aramak için birkaç klasöre tıklamamıza gerek yok.

Bunun daha iyi bir yaklaşım olduğunu düşünüyorsanız ve mantıklı geliyorsa, yapın (reddit’teki biri size söylediği için değil):

tepki-redux-klasör-yapısı2.png

Bu nedenle, basit olmalı ve şu anda üzerinde çalıştığınız proje için doğru hissettirmeli, Dan Abramov’un (filmin yaratıcısı) yaptığı gibi. redux) diyor ki:

dan-abramov-tepki-dosya-klasörü-bileşen-yapı-ipuçları-javascript-web-apps

3. Bir kutu içinde düşünmek

İnsanların okuyacağı bir kod yazıyorsak (örneğin, takım arkadaşlarınızla sorunları çözerken) yapma bir kutunun içinde düşün!

Fonksiyonları hızlı ve doğrudan yazmanın cazip olduğunu biliyorum. Kendimi çoğu zaman bu çoğunlukta yakalayabilmeme rağmen, zaman zaman bunu yapmaktan hala suçlu olduğumu kabul ediyorum.

Aşağıdaki örneğe bir göz atın:

if (serviceError) {
	resolve(
		new Response({
			code: serviceResponse?.getCode() || -1,
			data: {
				...responseData,
				error: serviceError,
			},
		}),
	)
} else if (serviceResponse) {

Her şey yolunda ama daha yakından baktığınızda neyin ne olduğunu nereden biliyorsunuz? serviceResponse?.getCode() geri dönücek? Ya dönerse 0? Bazı geleneksel uygulamalarda bize şunu öğrettiler: 0 başarı için bir koddur (her ne kadar diller onu yanlış olarak yorumlasa da, ama benim anlatmak istediğim bu), bu yüzden uygulamalarımızı dikkatli bir şekilde yazmayı düşünmeliyiz çünkü insanlar aklımızı okuyamayacak ve kodun ne yaptığını net bir şekilde anlayamayacak. Peki ya dönerse 1veya 5, 9? Bu noktada, koda dokunmamak ve geliştiriciyi açıklamak için avlamak en iyisidir.

Bunu daha insan tarafından okunabilir bir şekilde yazmak için iyi bir çözüm, kodları sabit değişkenlere değerler olarak atamaktır. betimlemek kodu ve ardından bunları projemiz boyunca kullanın.

Gibi birçok kütüphanede yaygın olarak göreceğiniz yararlı bir uygulamadır. Twilio-video örneğin:

module.exports.DEFAULT_ICE_GATHERING_TIMEOUT_MS = 15000
module.exports.DEFAULT_SESSION_TIMEOUT_SEC = 30

module.exports.DEFAULT_NQ_LEVEL_LOCAL = 1
module.exports.DEFAULT_NQ_LEVEL_REMOTE = 0
module.exports.MAX_NQ_LEVEL = 3

module.exports.ICE_ACTIVITY_CHECK_PERIOD_MS = 1000
module.exports.ICE_INACTIVITY_THRESHOLD_MS = 3000

4. Döngüler Sırasında Tünel Görüntüleme

Döngüler, işi hızlı bir şekilde tamamladıklarında güzel olabilir, ancak koşul karşılanmadığında hesaba katılmadıklarında inanılmaz derecede yıkıcıdır!

Aşağıdaki örneğe bir göz atalım:

let startCount = 0

while (startCount < numComponents) {
  const _component = components[startCount]
  const _node = getByElementId(_component)

  if (!_node) {
    log(
      `Tried to redraw a ${_component.type} component node from the DOM but the DOM node did not exist`,
      { component: _component, node: _node },
    )
  } else {
    const ctx = {} as any
    if (isListConsumer(_component)) {
      const dataObject = findListDataObject(_component)
      dataObject && (ctx.dataObject = dataObject)
    }
    const ndomPage = pickNDOMPageFromOptions(options)
    const redrawed = app.ndom.redraw(_node, _component, ndomPage, {
      context: ctx,
    })

    startCount++
  }
}

Buradaki sorun, oranı artırmak değil. startCount için başarısız durum:

if (!_node) {
  log(
    `Tried to redraw a ${_component.type} component node from the DOM but the DOM node did not exist`,
    { component: _component, node: _node },
  )
}

Bu, while döngüsünün asla bitmeyeceği anlamına gelir çünkü startCount eğer asla artmaz numComponents artıştan ulaşıldı startCount altındaki blokta.

Birinin bunu nasıl unutacağını anlayabiliyorum.

Birincisi, belki de geliştirici, başarısız vakanın basit bir günlüğe kaydedilmesiyle kodu işlemeye alışmıştır (ki bu aslında karşılaştığımız sorunların çoğu için yeterlidir) ve yanlışlıkla programlarının hala çalışacağını varsaymış olabilir.

Şimdi ikinci düşüncem için, kod yazarken, genellikle doğası gereği, her koşulda bir değişkeni artırma veya güncelleme ile sonuçlanırız. geçer (çünkü daha fazla bir şey yapmamıza gerek yok):

let currElem

while (currElem) {
  if (currElem.children.length) {
    currElem = currElem.firstChild
  } else {
    
  }
}

Bu nedenle, önceki örnekteki geliştiricinin nasıl olduğu anlaşılabilir. tünel görüşlü geçen koşulun bloğu.

5. @ts-ignore

TypeScript’i zaten kullanıyorsanız ve kodunuzdaki can sıkıcı hataları görmezden gelmek için bunu kullandığınızı düşünüyorsanız, inanın bana böyle bir uygulama yapılmaz!

daha güçlüsü var ve daha güvenli TypeScript’in linting hatalarını kapatmak için sağladığı anahtar kelime.

Kullanarak @ts-expect-error aynı şekilde çalışır @ts-ignore yapar (veya eslint-disable-next-line ESLint’te) dışında, size bir linting hatası verir. artık bunu bir hata olarak görmüyor o olmadan.

Olmadan @ts-expect-error TypeScipt hatasında:

typescript-linting-error-kullanmadan-ts-expect-error

kullanma @ts-expect-error TypeScipt hatasında

typescript-linting-error-using-ts-expect-error

kullanma @ts-expect-error geçerli olduğunda:

typescript-valid-javascript-using-ts-expect-error-safe-raporting

peki neden kullanmıyorsun @ts-expect-error yerine yaklaşmak? Sizi ve çevrenizdeki insanları korur.

6. Geçersiz değerler için varsayılan parametreleri başlatma

bu konuya bir sekilde bahsetmiştim önceki makale, ama bu, kasvetli bir Cuma günü dikkatsiz bir geliştiriciyi kandırabilecek o tüyler ürpertici “kaçırmalardan” biri! Sonuçta, uygulamalar çöküyor şaka değil–herhangi bir tür çökme, doğru şekilde ele alınmazsa, herhangi bir zamanda para kaybına neden olabilir.

Bir zamanlar buna benzer bir hata ayıklamak için çok fazla zaman harcamaktan suçluydum:

function init(value = {}) {
  console.log(value.hello)
}

init(null)

İçeri initeğer value falsey olur, ile başlatılır null.

Eğer benim gibiyseniz, içgüdülerimiz bize bunu söylüyor. value falsey değeriyse, varsayılan olarak boş bir nesne hazır bilgisine başlatılmalıdır. Ancak değer falsey olduğunda uygulamamız çökecek çünkü value dır-dir null. Ne?

Varsayılan işlev parametreleri, aşağıdaki durumlarda adlandırılmış parametrelerin varsayılan değerlerle başlatılmasına izin verir: değersiz veya undefined geçti!

Bizim durumumuzda, her ne kadar null falsey, bu hala bir değer!

Yani bir dahaki sefere varsayılan bir değer ayarladığınızda hükümsüzbunu yaparken iki kere düşünmeyi unutma.

Yaygın bir uygulama sadece şunu yapmaktır:

function init(value = {}) {
  if (value === null) return
  
  console.log(value.hello)
}

Kısadır ve yapılması yalnızca bir satır sürer. Ayrıca, endişelenecek bir veri türünüz daha az olduğundan, işlevin alabileceği beklenen veri türü hakkında biraz daha bilgi sağlar.

7. instanceof ne zaman olduğunu bilmeden yapmaz

Daha önce bunun kurbanı oldum ve JavaScript’te yeniyseniz, bunu bilmiyor olabilirsiniz. instanceof çalışmayacak olan nesnelerde kullanırsanız ayrı bir yürütme ortamında oluşturulan (farklı tarayıcı bağlamları, genel nesneler, vb.).

bu mdn belgeleri pratikte bu davranışın oldukça güzel bir örneğini ortaya koyuyor:

Örneğin, [] pencere örneği.çerçeveler[0].Array false döndürür, çünkü Array.prototype !== window.frames[0].Array.prototype ve diziler öncekinden miras alır

Bu dikkat edilmesi gereken bir şeydir, çünkü herhangi bir hata bildirmez, sessizce koşulda başarısız olur ve devam eder, hata ayıklamayı zorlaştırır. TypeScript olacak olumsuzluk bunu da yakala, yani bu sefer tek başınasın!

8. async forEach içinde

Son zamanlarda birinin bunu yaptığını gördüm ve bu gerçekten çok önemli yapmamak çünkü sen bu hatayı yapmamaktan sorumludur.

Basit ifadeyle, async içeride kullanıldığında beklediğimiz şeyi yapmaz forEach aramalar:

function getAllResponses(...urls) {
  const responses = []

  urls.forEach(async (url) => {
    const resp = await fetch(url)
    const data = await resp.json()
    responses.push(data)
  })

  return responses
}

const responses = getAllResponses()

Bu işlevi çalıştırmak sadece boş bir dizi döndürür çünkü asenkron çağrıların bitmesini beklemez. BT alışkanlık getirmeyi atla ama bunun yerine sadece olmayacak Bekle aramaların bitmesi için herhangi bir sonuç döndürülmesin.

Çözüm

Ve bu yazının sonu burada bitiyor! Umarım bunu değerli bulmuşsunuzdur ve gelecekte daha fazlasını ararsınız!

Bir cevap yazın

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