Yalnızca başka bir işlevi çağıran, parametreleri olmayan bir işlevin faydası nedir?


21

Bir öğretici (Javascript için) Yapıyorum, bunun gibi bir fonksiyon yazdığımızı gösteriyor:

function sayHello() {
   //Some comments explaining the next line
   window.alert("Hello");
}

Şaşırtmaca dışında gerçek hayatta böyle bir şey yazmanın yararları var mı? Eğer öyleyse, faydaları nelerdir?


14
Muhtemelen sadece kendi fonksiyonlarınızı nasıl tanımlayacağınızı göstermeye çalışıyor.
Doval

4
Kodları asla şaşırtmayacak bir şekilde yazmam - kod, programcının çevrede olduğu gibi kolayca okuması içindir. Şaşırtma için bir gizleyici kullanın.
rhughes

32
Bunun yararı, parametreleri içeren bir işlevi sarmalamasıdır . Bu şekilde daha sonra uygulamanızı ispanyolca yapmak istiyorsanız, "Hello" yu bir yerde "Ola" olarak değiştirmeniz yeterlidir.
Pieter B

9
@PieterB aslında, "Hola"
rev

29
@PieterB - Eğer "Hola" nın yanlış yazılmış olduğunu keşfederseniz, sadece tek bir yerde düzeltmeniz gerekir.
Daniel R Hicks,

Yanıtlar:


60

Bu yanlış varsa lütfen hafızamı affet ... Javascript benim tercih ettiğim uygulama dili değil.

Birinin bir arg işlevinin başka bir işlev çağrısını kaydırmasını istememesinin birkaç nedeni vardır. Basit çağrı, window.alert("Hello");sadece bunun yerine doğrudan arayarak hayal edebileceğiniz bir şey iken sayHello().

Peki ya daha fazlası varsa? Aramak istediğiniz sayHello()ve window.alert("Hello");yerine yazmak istediğiniz bir düzine yer var . Şimdi bir şey yapmasını istiyorsun window.alert("Hello, it is now " + new Date()). Tüm bu çağrıları tamamladıysanız sayHello(), tek bir yeri değiştirirseniz. Yapmazsan bir düzine yerde değiştirirsin. Bu dokunur Kendini Tekrar Etme . Bunu yaparsınız, çünkü gelecekte bir düzine defa yapmak zorunda değilsiniz.

Geçmişte i18n / l10n kütüphanesiyle çalışmıştım , metnin istemci tarafında yerelleştirilmesi için işlevler kullandım. sayHello()Fonksiyonu düşünün . holaKullanıcı bir İspanyolca dilinde yerelleştirildiğinde yazdırılmasını sağlayabilirsiniz . Bu şuna benzeyebilir:

function sayHello() {
  var language = window.navigator.userLanguage || window.navigator.language;
  if(language === 'es') { window.alert('Hola'); }
   else { window.alert("Hello"); }
}

Yine de, kütüphane bu şekilde çalışmadı. Bunun yerine, benzeyen bir dosya kümesi vardı:

# English file
greeting = hello
# Spanish file
greeting = hola

Ardından kütüphane tarayıcı dili ayarını tespit eder ve ardından uygun lokalizasyon dosyasına dayanarak herhangi bir tartışmasız fonksiyon çağrısı için dönüş değeri olarak uygun yerelleştirmeye sahip dinamik fonksiyonlar oluşturur .

Bunun iyi ya da kötü olup olmadığını söylemek için yeterli bir Javascript kodlayıcıya yetmiyor ... sadece bunun mümkün olduğunu ve olası bir yaklaşım olarak görülebileceğini.

Çağrının, bir işlevi başka bir işleve kendi işlevi ile sarması genellikle oldukça yararlıdır ve uygulamanın modülerleşmesine yardımcı olur ve ayrıca kodun okunması daha kolay olabilir.

Bütün bunlar bir yana, bir dersten çalışıyorsun. Başlangıçta mümkün olduğunca basit şeyler tanıtmak için gereklidir. Varargs style işlev çağrısının baştan başlatılması, genel olarak kodlamaya aşina olmayan bir kişi için kafa karıştırıcı bir kodla sonuçlanabilir. Bir argümandan, argümana, varargs stiline - önceki örneklerde ve anlayışta her binada gitmek çok daha kolaydır.


3
window.alertayrıca, geliştirme sırasında hoş bir modal / popup tasarlanıp / uygulanana kadar sık ​​sık bir yer tutucu olarak kullanılır, bu nedenle, dil sorunuyla aynı şekilde çok daha kolay bir şekilde açılabilir. Veya zaten bir tanesine sahipseniz, hattın birkaç yıl aşağısındaki bir tasarım güncellemesi benzer değişiklikler gerektirebilir.
Izkata

34

Uygulamayı gizlemek için bazen yararlı olduğunu düşünüyorum.

 function sayHello() {
  window.alert("Hello");
 }

Ve bu size daha sonra değiştirme esnekliği verir.

 function sayHello() {
  console.log("Hello");
 }

19

Şaşırtmaca dışında gerçek hayatta böyle bir şey yazmanın yararları var mı? Eğer öyleyse, faydaları nelerdir?

  • merkezileşme: Uygulama tek bir satır uzunluğunda olmasına rağmen, sık sık değişen bir hat ise, muhtemelen söylenenden daha tek bir yerde değiştirmeyi tercih edersiniz.

  • Bağımlılıkların en aza indirilmesi / gizlenmesi: Müşteri kodunuzun artık bir pencere nesnesi olduğunu bilmesi gerekmiyor ve müşteri kodunu etkilemeden tüm uygulamayı bile değiştirebilirsiniz

  • sözleşmenin yerine getirilmesi: müşteri kodu sayHello işlevine sahip bir modül bekleyebilir. Bu durumda, önemsiz olsa bile, işlev orada olmalıdır.

  • soyutlama seviyelerinin tutarlılığı: Eğer müşteri kodu yüksek seviyeli işlemler kullanıyorsa, müşteri kodunu pencere nesneleri yerine 'sayHello, sayBye' ve diğer bazı 'sayXXX' (ler) terimleriyle yazmak sizin yararınızadır. Infact, müşteri kodunda 'pencere' nesnesi diye bir şey olduğunu bilmek bile istemeyebilirsiniz.


Bu cevabı beğendim. Genelde tasarım, bu işlevlerin en başta gelen nedenidir, özellikle davranıştan sorumlu nesnelerin belirli davranışlarla diğer nesnelerin işlevlerini yürütmesini istediğiniz OO tasarımı. Arabanızı görüntülerken, daha çok vites değiştiriyorsunuz. Vites kolunuzu, vites çubuğunuzu yukarı kaydırmasını "söyleyerek" yükseltin. Sırayla bu çağrıyı vites kutunuza yönlendirir. Ancak ek olarak ilk kontrolleri geçerli konumunuzdan yukarı çekebilirsiniz.
Eric

3
Diğer nedenler de soyutlama seviyelerinden bahsetmek için +1. Net soyutlamalar ve iyi fonksiyon isimleri kullanmak, eski kodların okunmasını ve korunmasını çok daha kolay hale getirebilir. Sayello () 'nun çağrıldığı noktada, mutlaka nasıl uygulandığı ile ilgilenmiyorsunuz, sadece bu kod satırının amacının ne olduğunu anlamak istiyorsunuz. Ve sayHello () gibi bir fonksiyon ismi bunu açıklığa kavuşturur.
kkrambo

Ayrıca soyutlama seviyelerinden bahsetmek için +1: bir soyutlama seviyesindeki bir fonksiyonun uygulanmasının, düşük bir soyutlama seviyesinin bir başka fonksiyonuna yapılan bir çağrıdan oluşması olabilir. Ne olmuş yani?
Giorgio

7

Şaşırtıcı olmayan bir başkasının testten bahsetmemesi şaşırtıcı.

Seçtiğiniz "sarılmış" çizgi window.alert('hello'), aslında bunun mükemmel bir örneği. windowNesneyi içeren her şey test etmek için gerçekten çok acı vericidir. Uygulamanızda 1000 kez ile çarpın ve geliştiricilerin sonunda testten vazgeçeceğini garanti ediyorum. Öte yandan, sayHellobir casus ile sadece işlevini gizlemek ve çağrıldığı test etmek oldukça kolaydır .

Daha pratik bir örnek - çünkü gerçekten, window.alert(...)üretim kodunda kim kullanıyor ? - sistem saatini kontrol ediyor. Örneğin, bu DateTime.Now, .NET'te, time(...)C / C ++ veya System.currentTimeMillis()Java'da kaydırılıyor olabilir . Sen gerçekten onlar sadece (neredeyse) alay etmek imkansız / sahte, çünkü, enjekte edilebilir bir bağımlılık olanlar sarmak istiyorum onlar salt okunur ve non-deterministik . Sistem saati işlevini doğrudan kullanan bir işlevi veya yöntemi kapsayan herhangi bir test, aralıklı ve / veya rasgele arızalardan etkilenir.

Gerçek sarıcı 1 satırlık bir işlevdir - return DateTime.Now- ancak kötü tasarlanmış, test edilemeyen bir nesneyi alıp temiz ve test edilebilir bir nesne elde etmek için tek ihtiyacınız olan şey budur. Paketleyici için sahte bir saatin yerini alabilir ve saatini istediğiniz zaman ayarlayabilirsiniz. Sorun çözüldü.


2

Doval'ın dediği gibi, bu örnek muhtemelen sadece sizi işlevleri tanıtmaya çalışıyor. Ben generalim, yine de faydalı. Özellikle bazılarını belirterek fakat hepsini argümanları yaparak ve diğerlerini geçerek, daha genel bir işlevden daha büyük / küçük harfe özgü bir işlev yapabilirsiniz. Biraz önemsiz bir örnek olarak, sıralamak için bir dizi ve sıralamak için bir karşılaştırıcı işlevi olan bir sıralama işlevini düşünün. Sayısal değerle karşılaştıran bir karşılaştırıcı işlev belirleyerek, sortByNumericalValue işlevini yapabilirim ve bu işleve yapılan çağrıları çok daha net ve özlü olur.


2

Sorunuzun ardındaki düşünce şöyle görünüyor: "Neden alert("Hello");doğrudan doğrudan yazmıyorsunuz ? Oldukça basit."

Gerçekten aramak istemiyorum çünkü cevap, kısmen, alert("Hello")- sadece merhaba demek istiyorum.

Veya: Telefon numaralarını yalnızca telefon numaralarını arayabildiğiniz zaman neden telefonunuza kaydedin? Çünkü tüm bu sayıları hatırlamak istemiyorsunuz; çünkü arama numaraları sıkıcı ve hataya açık; çünkü sayı değişebilir, ama diğer ucunda hala aynı kişi. Çünkü insanları aramak istiyorsun , numaraları değil.

Soyutlama, aktarma, "uygulama detaylarını gizleme" ve hatta "etkileyici kod" gibi terimlerle anlaşılan budur.

Aynı akıl yürütme, her yere ham değerler yazmak yerine sabitleri kullanmak için de geçerlidir. Sen olabilir sadece yazma 3.141592...sen tt gerekir her zaman, ama neyse ki orada Math.PI.

alert()Kendisine de bakabiliriz . Bu uyarı iletişim kutusunu nasıl oluşturup gösterdiği kimin umurunda? Sadece kullanıcıyı uyarmak istiyorsun. Siz yazarken alert("Hello")ekranınızdaki pikseller değişiyorsa, derin, derin bir kod ve donanım yığını vardır, her katman bir sonraki istediğini söyler ve bir sonraki katman mümkün olan en derin katman bazı bitleri çevirene kadar ayrıntılara dikkat eder. video belleği.

Sadece merhaba demek için hepsini kendin yapmak zorunda değilsin.

Programlama - peki, herhangi bir görev, gerçekten - hepsi karmaşık sorunları yönetilebilir parçalara bölmekle ilgilidir. Her bir parçayı çözmek size bir yapı taşı verir ve yeterince basit yapı taşları ile büyük şeyler yapabilirsiniz.

Cebir.


-1

Değerlerin (ifadelerin) hesaplanmasının eylemlerin uygulanmasından (ifadeler) ayrı tutulması iyi bir fikirdir . Eylemlerin nerede ve ne zaman gerçekleştirileceğine (mesajların gösterilmesi gibi) kesin kontrol istiyoruz, ancak değerleri hesaplarken daha soyut bir seviyede çalışmayı tercih ediyoruz ve bu değerlerin nasıl hesaplandığına dikkat etmek zorunda değiliz .

Yalnızca verilen değeri kullanarak yalnızca bir dönüş değeri hesaplayan fonksiyona saf denir .

Bir eylem gerçekleştiren bir "işlev" aslında bir etkiye sahip olan bir prosedürdür .

Bir değerin hesaplanması sırasında ortaya çıkan herhangi bir etki , yan etki olarak adlandırılır ve mümkün olan yerlerde bunlardan kaçınmak daha iyidir ("Ben sadece o dizgeye ihtiyacım vardı, veritabanını çekiçleyeceğini bilmiyordum!").

Yan etki olasılığını en aza indirmek için prosedürlerimize çok fazla veri göndermekten veya bunlara herhangi bir hesaplama yapmaktan kaçınmalıyız; Bazı hesaplamaların önceden yapılması gerekiyorsa, bunu saf fonksiyonda ayrı yapmak genellikle daha iyidir, o zaman prosedüre sadece istenen sonucu verin. Bu, işlemin amacını açık tutar ve bir hesaplama işleminin parçası olarak daha sonra tekrar kullanılabilme olasılığını azaltır (bunun yerine saf işlev yeniden kullanılabilir).

Aynı sebepten dolayı, bir prosedür içinde sonuçları işlemekten kaçınmalıyız. Sonucumuzu (eğer varsa) eylemimizden döndürmek ve daha sonraki işlemleri saf fonksiyonlarla yapmak daha iyidir.

Bu kuralları uygularsak, sayHelloherhangi bir veriye ihtiyaç duymayan ve bir sonucu olmayan bir prosedürle sonuçlanabiliriz. Dolayısıyla bunun için en iyi arayüz, argümanlara sahip olmamak ve bir değer döndürmemek. Bu, örneğin, bazı hesaplamaların ortasında "console.log" u çağırmak için tercih edilir.

Hesaplama sırasında efekt ihtiyacını azaltmak için, prosedürleri geri getiren hesaplamalara sahip olabiliriz ; Örneğin. Eğer yapılacak bir eyleme karar vermemiz gerekirse, doğrudan uygulamak yerine, bir prosedür seçip onu geri döndürmek için saf bir işleve sahip olabiliriz.

Benzer şekilde, prosedürler sırasında hesaplama gereksinimini azaltmak için prosedürlerin parametre olarak (muhtemelen bir fonksiyonun sonucu) başka prosedürler almasını sağlayabiliriz; Örneğin. Bir dizi prosedür almak ve birbiri ardına çalıştırmak.


Burada temel prensibin “söyle, sorma” olduğu OOP'a karşı savunuculuk yapıyor gibi görünüyorsunuz. Buradaki tavsiyeye göre, normalde işe yaramaz "getFoo", "setFoo" ve "execute" çağrıları ile ilgili bir kod yol açar. OOP veri ve davranışları birleştirmekle ilgilidir , ayırmakla değil
Aarona

@Aaronaught OOP'a karşı olduğum doğrudur, ancak setFoodeğişken veri anlamına geldiğinden kesinlikle aramaları tavsiye etmem . Değişkenlerin / özelliklerin içeriğini değiştirmek, bu verileri kullanan tüm hesaplamaların geçersiz hale gelmesine neden olan bir etkidir. Ben tavsiye etmem executese başına aramaları, ama olur tavsiye runFooonların argümanları dayalı eylemlerin uygulanması için prosedürler.
Warbo

-2

@MichaelT ve @Sleiman Jneidi tarafından verilen cevapların bir birleşimi olduğunu söyleyebilirim.

Muhtemelen kodda, kullanıcıyı bir Merhaba mesajı ile selamlamak istediğiniz birçok yer vardır, bu nedenle bu fikri bir yöntemle paketleyin. Bu yöntemde daha uzun bir metni görüntüleyerek çevirebilir veya basit bir 'Merhaba' üzerinde genişletebilirsiniz. Ayrıca bir uyarı yerine hoş bir JQuery iletişim kutusu kullanmak isteyebilirsiniz.

Mesele şu ki, uygulama tek bir yerde. Sadece kodu tek bir yerde değiştirmeniz gerekiyor. (SayHello () belki de çok basit bir örnek)


@ downvoter (lar) - bilginizi bizlerle paylaşmaya özen gösterin. Görevim yanlış mı, yanlış yazılmış mı yoksa ne?
Paul
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.