Sadece başka bir fonksiyonda kullanılan fonksiyonları, o fonksiyonun içine mi koymalıyım?


30

Özellikle, JavaScript ile yazıyorum.

Diyelim ki birincil işlevim İşlev A dır. İşlev A, İşlev B'ye birkaç çağrı yaparsa, ancak İşlev B başka bir yerde kullanılmazsa, İşlev B'yi İşlev A'ya yerleştirmem gerekir mi?

Bu iyi bir uygulama mı? Yoksa yine de İşlev B'yi İşlev A ile aynı kapsamda mı koymalıyım?

Yanıtlar:


32

Genelde iç içe geçmiş fonksiyonlardan, özellikle de JavaScript'ten yanayım.

  • JavaScript'te, bir işlevin görünürlüğünü sınırlamanın tek yolu, onu başka bir işlevin içine yerleştirmektir.
  • Yardımcı fonksiyon, özel bir uygulama detayıdır. Aynı kapsamda koymak, bir sınıfı 'özel işlevleri halka açık hale getirmeye benzer.
  • Daha genel kullanımda olduğu ortaya çıkarsa, taşınması kolaydır, çünkü yardımcının şu anda yalnızca bir işlev tarafından kullanıldığından emin olabilirsiniz. Başka bir deyişle, kodunuzu daha uyumlu hale getirir.
  • İşlev imzasını ve uygulamasını daha az ayrıntılı hale getiren parametreleri sıklıkla ortadan kaldırabilirsiniz. Bu değişkenleri global yapmakla aynı şey değildir. Daha çok özel bir yöntemde sınıf üyesini kullanmak gibi.
  • Yardımcı işlevlere daha iyi, daha basit adlar, çatışmalardan endişe etmeden verebilirsiniz.
  • Yardımcı işlev bulmak daha kolaydır. Evet, size yardımcı olabilecek araçlar var. Sadece gözlerinizi ekrandan biraz yukarı hareket ettirmek daha kolay.
  • Kod, doğal olarak bir tür soyutlama ağacı oluşturur: kökündeki birkaç genel işlev, birkaç uygulama detayına ayrılır. İşlev katlama / daraltma işlevine sahip bir düzenleyici kullanırsanız, yuvalama, aynı soyutlama düzeyinde yakından ilgili işlevlerin hiyerarşisini oluşturur. Bu, kodu ihtiyaç duyduğunuz seviyede incelemeyi ve ayrıntıları gizlemenizi kolaylaştırır.

Bence çoğu muhalif ya bir C / C ++ / Java geleneğinde yetiştirilmiş ya da başkası tarafından öğretilmiş. İç içe geçmiş fonksiyonlar doğal görünmez çünkü programlamayı öğrenirken onlara fazla maruz kalmadık. Bu yararlı olmadıkları anlamına gelmez.


14

Birkaç nedenden dolayı küresel kapsamda koymalısınız.

  • Bir yardımcı işlevi arayanın içine yerleştirmek arayanın uzunluğunu artırır. Fonksiyon uzunluğu neredeyse her zaman negatif bir göstergedir; Kısa fonksiyonların anlaşılması, ezberlenmesi, hata ayıklanması ve bakımı daha kolaydır.

  • Yardımcı fonksiyonun mantıklı bir adı varsa, yakındaki tanımı görmeden bu adı okumak yeterlidir. Eğer varsa yapmak arayan çok fazla yapıyor, ya da eş zamanlı soyutlama çok fazla seviyelerde çalıştığını sonra, arayan işlevini anlamak için yardımcı tanımı görmek için gereğini.

  • Yardımcının dünya genelinde erişilebilir olması, diğer işlevlerin, sonuçta genellikle yararlı olması için çevirirse, onu çağırmasını sağlar. Eğer yardımcı mevcut değilse, kesip yapıştırmanız ya da unutmanız ve yeniden yerleştirmeniz, zayıf şekilde ya da olması gerektiğinden daha uzun bir işlev daha yapmanız gerekiyor.

  • Yardımcı fonksiyonun yuvalanması, arayanın kapsamındaki değişkenleri bildirimde bulunmadan kullanma eğilimini arttırır, böylece yardımcının girdilerinin ve çıktılarının ne olduğu belirsizleşir. Eğer bir fonksiyon hangi veriler üzerinde çalıştığını ve hangi etkileri üzerinde etkilediğini açıkça belirtmiyorsa, genellikle belirsiz sorumlulukların işaretidir. Yardımcı kıçı bağımsız bir işlev olarak bildirmek, gerçekte ne yaptığını bilmenizi sağlar.

Düzenle

Bu düşündüğümden daha tartışmalı bir soru olduğu ortaya çıktı. Netleşmeştirmek:

JavaScript'te büyük dosya yayma işlevleri genellikle sınıfların rolünü yerine getirir, çünkü dil başka bir kapsam sınırlayıcı mekanizma sağlamamaktadır. Kesinlikle yardımcı fonksiyonlar dışlarında değil bu tür sınıfların içine girmelidir .

Ve bir altprogram eğer daha kolay yeniden önceden varsayar hakkında noktası yok olmak daha yaygın olarak kullanılan, tümüyle yerin dışarı taşımak ve uygun yere, örneğin bir dize yarar kütüphanede veya global konfigürasyon kayıt koymak hazırız. Kodunuzu böyle sıralamak istemiyorsanız, alt yordamı, daha normal bir Yöntem Nesnesinde olduğu gibi daha "bloklu" bir dilde yapacağınız gibi yerleştirebilirsiniz .


Teşekkürler, hepsi çok iyi noktalar. Bir yandan notta, işlevlerimi genel olarak nasıl sıralamalıyım? Mesela şu anda küçük programlarla sadece alfabetik olarak sıralıyorum. Fakat yardımcı ve arayan işlevlerini birlikte gruplamalı mıyım? Sanırım en azından uygulamanın hangi kısımlarına başvurduğuna bağlı olarak işlevlerimi çözmeliyim?
Gary

Uzun zamandır sipariş metodu tanımlarını rahatsız etmedim. Herhangi bir profesyonellik derecesi ile program yaparsanız, herhangi bir tanımlamaya yine de birkaç tuşa basarak atlamanızı sağlayan bir ortamınız olmalıdır. Bu nedenle kısa yöntemler kullanışlıdır, ancak kısa ve hatta iyi düzenlenmiş sınıf dosyaları çok az değer katar. (Tabii ki, JavaScript, tanımların kullanımlarının üzerine yerleştirilmesini gerektiriyordu ya da sonuç teknik olarak tanımlanamayan davranış olurdu - yine de böyle olup olmadığını hatırlayamıyorum.)
Kilian Foth

2
Bu harika bir cevap. Kırık kapsülleme sorunu, iç fonksiyonları kullanırken pek kimsenin göz önünde bulundurmadığı bir şeydir.
sbichenko

2
Globals bir kod kokusu vardır. Yeniden yapılanmayı engelleyen gereksiz eşleşmeye neden olurlar, isim çatışmalarına neden olurlar, uygulama detaylarını ortaya çıkarırlar, vs. yaygın olarak bulunan bir modül sistemi veya "let" in yaygın olarak bulunabilen bir uygulaması. Bu kadar düşmanca bir ortamda, sahip olduğumuz tek savunma stratejisi tek seferlik fonksiyonların içinde kapsüllemedir.
Warbo,

1
“Sınıfların rolünü yerine getirmek”, JS'yi başka bir şeymiş gibi yazmaya çalışıyor. "Sınıfların rolü" nedir? Tip-kontrol? Modülerlik? Aşamalı derleme? Kalıtım? Soru kapsamayı içerir, bu yüzden sınıfların kaba kapsamı kurallarını kastediyorsunuzdur. Bu sadece para kazanıyor: sınıflar nasıl ele alınmalı ? PHP onları küreselleştiriyor, bu da kapsülleme yapmıyor. Python, sınıfları sözcüksel olarak kapsamlar, ancak sözcüksel olarak kapsamlı bir bloğun içindeyseniz, neden her şeyi başka bir sınıf kapsamındaki bloğa sarmalısınız? JS'nin artık fazlalığı yok: İhtiyacınız kadar sözcüksel kapsam kullanın.
Warbo,

8

Her iki işlevi de kapatmaya yerleştirmek için üçüncü bir yol önereceğim. Şunun gibi olurdu:

var functionA = (function(){
    function functionB() {
        // do stuff...
    }

    function functionA() {
        // do stuff...
        functionB();
        // do stuff...
    }

    return functionA;
})();

Her iki fonksiyonun bildirimini bir IIFE'ye sararak kapatmayı yaratırız . IIFE'nin dönüş değeri, fonksiyonun isminin bir değişkeninde saklanan genel fonksiyondur. Kamusal işlev, tam da küresel bir işlev olarak bildirildiği gibi çağrılabilir functionA(). Dönen değerin , işlev çağrısı değil, sonuçta parens olmadığını gösteren işlev olduğunu unutmayın.

İki işlevi bu şekilde sararken functionB, şimdi tamamen özeldir ve kapağın dışından erişilemez, ancak yalnızca görülebilir functionA. Global ad alanını karıştırmıyor ve tanımını da karıştırmıyor functionA.


0

A fonksiyonunda B fonksiyonunun tanımlanması, A fonksiyonunun B değişkenine A fonksiyonuna erişim sağlar.

Bu nedenle, bir A işlevinde tanımlanan bir B işlevi, B'nin A'nın yerel değişkenlerini kullandığı veya değiştirdiği izlenimini (veya en azından olasılığını) verir. B'yi A dışında tanımlarken, B'nin yapmadığını açıkça belirtir.

Bu nedenle, kodun netliği için B'yi A içinde yalnızca B'nin A'nın yerel değişkenlerine erişmesi gerekiyorsa tanımlarım. B'nin A'dan bağımsız açık bir amacı varsa, kesinlikle A'nın dışında tanımlarım.


-1

Yuvalamamalısınız, aksi halde dışa aktarma işlevini her çağırdığınızda iç içe geçmiş işlev yeniden oluşturulur.


-3

B işlevi başka hiçbir yerde kullanılmadığı için, A işlevinde yalnızca içsel bir işlev haline getirebilirsiniz çünkü bunun tek nedeni budur.


1
Bu, önceki 3
cevapta
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.