İsteğe bağlı geri aramalar için JavaScript stili


93

Ara sıra (her zaman değil) geri arama alacak ve çalıştıracak bazı işlevlerim var. Geri aramanın tanımlı olup olmadığını / çalışıp çalışmadığını kontrol etmek iyi bir stil mi yoksa daha iyi bir yol var mı?

Misal:

function save (callback){
   .....do stuff......
   if(typeof callback !== 'undefined'){
     callback();
   };
};

modern tarayıcılarda kullanabilirsiniz, typeof callback !== undefinedbu yüzden'
Snickbrack

1
ve eğer sadece ararsan save()? Bir argüman eksik olduğu için bu bir hata veya tüylenme uyarısı vermez mi? Ya da tamamen tamam ve geri arama basit undefinedmi?
João Pimentel Ferreira

Yanıtlar:


140

Şahsen tercih ederim

typeof callback === 'function' && callback();

typeofKomut ancak tehlikeli ve sadece kullanılması gerektiğini "undefined"ve"function"

İle ilgili sorun typeof !== undefined, kullanıcının bir işlev değil , tanımlanmış bir değeri geçmesidir.


3
typeoftehlikeli değil. Bazen belirsiz, ama ben buna tehlikeli demem. Yine de, geri aramayı bir işlev olarak arayacaksanız, bunun bir sayı değil, aslında bir işlev olup olmadığını kontrol etmenin en iyisi olduğu konusunda hemfikiriz. :-)
TJ Crowder

1
@TJCrowder tehlikeli yanlış kelime olabilir, iyi tanımlanmış ancak boks ve "object"zamanın% 95'ini geri getirmesi nedeniyle işe yaramaz .
Raynos

1
typeofboksa neden olmaz. typeof "foo"olduğu "string"değil "object". Aslında bu, bir ilkel veya Stringnesne ile mi uğraştığınızı anlamanın tek gerçek yoludur . (Belki de düşünüyorsunuz Object.prototype.toString, bu çok kullanışlı , ancak boksa neden oluyor.)
TJ Crowder

4
Bu arada harika deyimsel kullanımı &&.
TJ Crowder

@TJCrowder Bir fikriniz var, dize ilkelleri ile kutulu String nesnelerini karşılaştırmanın değerini bilmiyorum. Ayrıca katılıyorum .toStringbulmak için güzel [[Class]].
Raynos

50

Ayrıca şunları da yapabilirsiniz:

var noop = function(){}; // do nothing.

function save (callback){
   callback = callback || noop;
   .....do stuff......
};

callbackBirkaç yerde kullanıyorsanız özellikle yararlıdır .

Ek olarak eğer kullanıyorsanız jQuery, zaten böyle bir fonksiyona sahipsiniz, buna $ .noop denir


4
Benim görüşüme göre bu en zarif çözüm.
Nicolas Le Thierry d'Ennequin

2
Kabul. Bu aynı zamanda testi kolaylaştırır çünkü eğer şartı yoktur.

6
ama bu tür sorununu ele almıyor değil mi? Ya bir diziyi geçersem? veya bir String?
Zerho

1
Basitleştirincallback = callback || function(){};
NorCalKnockOut

1
Ayrıca, bildirimde varsayılan bir değer vererek isteğe bağlı bir bağımsız değişken yapabilirsiniz:function save (callback=noop) { ...
Keith

40

Basitçe yap

if (callback) callback();

Ne tür olursa olsun, sağlanırsa geri aramayı aramayı tercih ederim. Sessizce başarısız olmasına izin vermeyin, böylece uygulayıcı yanlış bir argümandan geçtiğini bilir ve düzeltebilir.


12

ECMAScript 6

// @param callback Default value is a noop fn.
function save(callback = ()=>{}) {
   // do stuff...
   callback();
}

3

Geri aramayı isteğe bağlı yapmak yerine, bir varsayılan atayın ve ne olursa olsun çağırın

const identity = x =>
  x

const save (..., callback = identity) {
  // ...
  return callback (...)
}

Kullanıldığında

save (...)              // callback has no effect
save (..., console.log) // console.log is used as callback

Böyle bir stile devamlılık geçiş stili denir . İşte combinationsArray girdisinin tüm olası kombinasyonlarını oluşturan gerçek bir örnek

const identity = x =>
  x

const None =
  Symbol ()

const combinations = ([ x = None, ...rest ], callback = identity) =>
  x === None
    ? callback ([[]])
    : combinations
        ( rest
        , combs =>
            callback (combs .concat (combs .map (c => [ x, ...c ])))
        )

console.log (combinations (['A', 'B', 'C']))
// [ []
// , [ 'C' ]
// , [ 'B' ]
// , [ 'B', 'C' ]
// , [ 'A' ]
// , [ 'A', 'C' ]
// , [ 'A', 'B' ]
// , [ 'A', 'B', 'C' ]
// ]

Çünkü combinationsdevamıdır geçen tarzda tanımlanmıştır, yukarıda belirtilen arama etkili bir şekilde aynıdır

combinations (['A', 'B', 'C'], console.log)
// [ []
// , [ 'C' ]
// , [ 'B' ]
// , [ 'B', 'C' ]
// , [ 'A' ]
// , [ 'A', 'C' ]
// , [ 'A', 'B' ]
// , [ 'A', 'B', 'C' ]
// ]

Sonuçla başka bir şey yapan özel bir devamı da geçebiliriz

console.log (combinations (['A', 'B', 'C'], combs => combs.length))
// 8
// (8 total combinations)

Devam eden stil, şaşırtıcı derecede zarif sonuçlarla kullanılabilir

const first = (x, y) =>
  x

const fibonacci = (n, callback = first) =>
  n === 0
    ? callback (0, 1)
    : fibonacci
        ( n - 1
        , (a, b) => callback (b, a + b)
        )
        
console.log (fibonacci (10)) // 55
// 55 is the 10th fibonacci number
// (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...)


1

Aynı pasajı tekrar tekrar görmekten o kadar yoruldum ki şunu yazdım:

  var cb = function(g) {
    if (g) {
      var args = Array.prototype.slice.call(arguments); 
      args.shift(); 
      g.apply(null, args); 
    }
  };

Gibi şeyler yapan yüzlerce işleve sahibim

  cb(callback, { error : null }, [0, 3, 5], true);

ya da her neyse...

"İşe yaradığından emin olun" stratejisine şüpheyle yaklaşıyorum. Tek meşru değerler bir işlev veya yanlıştır. Birisi sıfır olmayan bir sayı veya boş olmayan bir dizge girerse, ne yapacaksınız? Problemi görmezden gelmek onu nasıl çözer?


İşlev, ilk bağımsız değişken olarak bazı değerleri, ilk bağımsız değişken olarak işlevi veya her iki parametreyi kabul edecek şekilde aşırı yüklenmiş olabilir. Bunun bir işlev olup olmadığını kontrol etmek için bir kullanım durumu vardır. Ayrıca, yanlış parametreyi yok saymak ve daha sonra işlevsiz bir işlemi gerçekleştirmek için bir hata atmak daha iyidir
Raynos

@Raynos - Bu çok, çok özel bir kullanım durumu. Zayıf bir şekilde yazılmış olan JavaScript türleri ayırt etmede iyi değildir ve türleri ayırt etmeye ve arayanın ne istediğini tahmin etmeye çalışmaktan genellikle adlandırılmış parametreleri iletmek daha iyidir:save( { callback : confirmProfileSaved, priority: "low" })
Malvolio

Katılmıyorum, yeterli tip kontrol yeteneği var. Yöntemin aşırı yüklenmesini tercih ederim, ama bu kişisel tercih. Bu jQuery'nin çok yaptığı şeydir.
Raynos

@Raynos - Yanlış parametreyi görmezden gelmek ve daha sonra işlev dışı bir işlevi yürütmek için bir hata atmak daha kötüdür . Tipik bir durumu düşünün: kütüphane işlevi bazı eşzamansız faaliyetler gerçekleştiriyor ve çağıran işlevin bildirilmesi gerekiyor. Bu nedenle, bilgisiz bir kullanıcı, görmezden gelmek ve başarısız olmak aynı görünür: faaliyet asla tamamlanamaz. Bununla birlikte, deneyimli bir kullanıcıya (örneğin, orijinal programcı), bir başarısızlık bir hata mesajı ve doğrudan soruna işaret eden bir yığın izi verir; parametrenin yok sayılması "hiçbir şeyin" olmamasına neyin sebep olduğunu belirlemek için zahmetli analiz anlamına gelir.
Malvolio

yine de yapılacak bir değiş tokuş var. Bir hata fırlatmak çalışma zamanını çökertecek, ancak bunun yok sayılması etrafındaki diğer kodun normal şekilde çalışmasına izin verecektir.
Raynos

1

Geçerli bir işlev, İşlev prototipine dayanır, şunu kullanın:

if (callback instanceof Function)

geri aramanın bir işlev olduğundan emin olmak için


0

Geri aramayı çalıştırmanın ölçütü tanımlı olsun ya da olmasın, o zaman sorun yok. Ayrıca, ek olarak gerçekten bir işlev olup olmadığını kontrol etmenizi öneririm.


0

Kahve senaryosuna geçtim ve varsayılan argümanların bu sorunu çözmenin güzel bir yolu olduğunu öğrendim.

doSomething = (arg1, arg2, callback = ()->)->
    callback()

0

ArgueJS ile kolaylıkla yapılabilir :

function save (){
  arguments = __({callback: [Function]})
.....do stuff......
  if(arguments.callback){
    callback();
  };
};
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.