JavaScript işlevine bir bağımsız değişken gönderilip gönderilmediği en iyi nasıl belirlenir


236

Şimdi bir argümanın bir JavaScript işlevine geçirilip iletilmediğini belirlemek için 2 yöntem gördüm. Bir yöntemin diğerinden daha iyi olup olmadığını ya da sadece kötü bir kullanım olup olmadığını merak ediyorum.

 function Test(argument1, argument2) {
      if (Test.arguments.length == 1) argument2 = 'blah';

      alert(argument2);
 }

 Test('test');

Veya

 function Test(argument1, argument2) {
      argument2 = argument2 || 'blah';

      alert(argument2);
 }

 Test('test');

Anlayabildiğim kadarıyla, her ikisi de aynı şeyle sonuçlanır, ancak daha önce sadece ilkini üretimde kullandım.

Tom'un belirttiği başka bir seçenek :

function Test(argument1, argument2) {
    if(argument2 === null) {
        argument2 = 'blah';
    }

    alert(argument2);
}

Juan'ın yorumuna göre, Tom'un önerisini şu şekilde değiştirmek daha iyi olurdu:

function Test(argument1, argument2) {
    if(argument2 === undefined) {
        argument2 = 'blah';
    }

    alert(argument2);
}

Gerçekten aynı. Her zaman statik sayıda argümanınız varsa, ikinci yönteme geçin, aksi takdirde arguments dizisini kullanarak yineleme yapmak daha kolaydır.
Luca Matteis

7
Aktarılmayan bir argüman tanımsız olarak geliyor. Null'a karşı katı bir eşitlikle test başarısız olur. Undefined ile katı bir eşitlik kullanmalısınız.
Juan Mendes

19
Unutmayın: argument2 || 'blah';eğer 'blah' verilecektir argument2olduğunu false, bu tanımlanmamış değil sadece if (!). Eğer argument2bir boolean ve işlev geçirilir falsebunun için, bu çizgi rağmen 'blah' dönecektir argument2düzgün tanımlanmış olan .
Sandy Gifford

9
@SandyGifford: Aynı sorun varsa argument2olduğunu 0, ''ya da null.
rvighne

@rvighne Çok doğru. Javascript'in nesnelerin ve dökümün benzersiz yorumu, en iyi ve en kötü kısımlarıdır.
Sandy Gifford

Yanıtlar:


274

Bir işleve bir argümanın iletilip iletilmediğini kontrol etmenin birkaç farklı yolu vardır. (Orijinal) sorunuzda bahsettiğiniz ikiye ek olarak - varsayılan değerleri sağlamak arguments.lengthiçin ||operatörün kontrol edilmesi veya kullanılması - biri, undefinedüzerinden argument2 === undefinedveya typeof argument2 === 'undefined'paranoyak olup olmadığını bağımsız olarak açık bir şekilde kontrol edebilir (yorumlara bakın).

Kullanılması ||operatörü standart uygulama haline gelmiştir - Bugünlerde herkes bunu yapmak - ama dikkatli olun: varsayılan değer argüman değerlendirir eğer tetiklenecek falseaslında olabilir hangi araçları undefined, null, false, 0, ''(veya başka bir şey kendisi için Boolean(...)döner false).

Yani soru, hangi kontrolün ne zaman kullanılacağıdır, çünkü hepsi biraz farklı sonuçlar verir.

Kontrol arguments.lengthetme 'en doğru' davranışı gösterir, ancak birden fazla isteğe bağlı argüman varsa bu mümkün olmayabilir.

undefinedSıradaki test en iyi 'en iyi' - yalnızca işlev açıkça bir undefineddeğerle çağrılırsa başarısız olur , bu da büyük olasılıkla argümanı atlamakla aynı şekilde ele alınmalıdır.

Kullanımı ||operatörü geçerli bir argüman sunulmuş olsa bile varsayılan değer kullanımını tetikleyebilir. Öte yandan, davranışı aslında istenebilir.

Özetlemek gerekirse: Sadece ne yaptığınızı biliyorsanız kullanın!

Kanımca, ||birden fazla isteğe bağlı argüman varsa ve bir nesne değişmezi adlandırılmış parametreler için bir geçici çözüm olarak geçmek istemiyorsa , kullanma da yoludur.

Varsayılan değerleri kullanarak sağlamanın başka bir güzel yolu arguments.length, bir switch ifadesinin etiketlerinden geçerek mümkündür:

function test(requiredArg, optionalArg1, optionalArg2, optionalArg3) {
    switch(arguments.length) {
        case 1: optionalArg1 = 'default1';
        case 2: optionalArg2 = 'default2';
        case 3: optionalArg3 = 'default3';
        case 4: break;
        default: throw new Error('illegal argument count')
    }
    // do stuff
}

Bu, programcının niyetinin (görsel olarak) açık olmadığı ve 'sihirli sayılar' kullanmasının dezavantajı vardır; bu nedenle muhtemelen hataya açıktır.


42
Birisinin "tanımsız" olarak tanımlaması durumunda, argeof2 === "tanımsız" türünü gerçekten kontrol etmelisiniz.
JW.

133
Bir uyarı ekleyeceğim - ama hangi hasta piçler böyle şeyler yapıyor?
Christoph

12
undefined, global alanda bir değişkendir. Bu değişkeni global kapsamda aramak, yerel kapsamdaki bir değişkenden daha yavaştır. Ama en hızlısı typeof x === "undefined" kullanmak
bazı

5
İlginç. Öte yandan, === undefined karşılaştırması dize karşılaştırmasından daha hızlı olabilir. Testlerim haklı olduğunuzu gösteriyor gibi görünüyor: x === tanımsız gerekli ~ 1.5x yazım zamanının 1.5 katı x === 'tanımsız'
Christoph

4
@Cristoph: Yorumunuzu okuduktan sonra etrafa sordum. Ben dev bir dize karşılaştırma küçük bir dize daha uzun sürdüğü için dize karşılaştırma kesinlikle (sadece) işaretçi karşılaştırma ile kanıtlamak mümkün. Bununla birlikte, iki dev dizeyi karşılaştırmak sadece birleştirme ile oluşturulduklarında gerçekten yavaştır, ancak ikincisi birinciden bir ödev olarak oluşturulduysa gerçekten hızlıdır. Muhtemelen bir işaretçi testi ve ardından harf testi ile mektup tarafından çalışıyor Yani, evet, bok doluydum :) beni aydınladığınız için teşekkürler ...
Juan Mendes

17

JQuery kullanıyorsanız, güzel bir seçenek (özellikle karmaşık durumlar için) jQuery'nin expand yöntemini kullanmaktır .

function foo(options) {

    default_options = {
        timeout : 1000,
        callback : function(){},
        some_number : 50,
        some_text : "hello world"
    };

    options = $.extend({}, default_options, options);
}

İşlevi çağırırsanız şu şekilde:

foo({timeout : 500});

Bu durumda seçenekler değişkeni şöyle olur:

{
    timeout : 500,
    callback : function(){},
    some_number : 50,
    some_text : "hello world"
};

15

Bu, testi bulduğum birkaç durumdan biri:

if(! argument2) {  

}

gayet güzel çalışıyor ve doğru sonucu sözdizimsel olarak taşıyor.

(Eşzamanlı kısıtlama ile argument2başka bir anlamı olan meşru bir null değere izin vermeyeceğim ; ama bu gerçekten kafa karıştırıcı olurdu .)

DÜZENLE:

Bu, gevşek yazılan ve güçlü yazılan diller arasındaki stilistik farkın gerçekten iyi bir örneğidir; ve javascript'in maça sağladığı stilistik bir seçenek.

Kişisel tercihim (diğer tercihler için hiçbir eleştiri yapılmadan) minimalizm. Kod ne kadar az söylemek zorundaysa, tutarlı ve özlü olduğum sürece, başka birinin anlamımı doğru bir şekilde çıkarmayı daha az kavraması gerekir.

Bu tercihin bir sonucu olarak, bir grup tip bağımlılık testi yapmak istemiyorum - yararlı bulmuyorum. Bunun yerine, kodun anlamı gibi göründüğü anlamına gelmeye çalışıyorum; ve sadece gerçekten test etmem gereken şeyleri test et.

Diğer bazı insanların kodlarında bulduğum şiddetlerden biri, daha geniş bağlamda, test ettikleri vakalara gerçekten girip girmeyeceğini beklemek zorunda. Ya da mümkün olan her şeyi test etmeye çalışıyorlarsa, bağlamı yeterince tahmin etmeme şansı ile. Bu da, herhangi bir şeyi güvenle yeniden düzenlemeden veya değiştirmeden önce her iki yönde de kapsamlı bir şekilde izlemem gerektiği anlamına gelir. Bu çeşitli testleri uygulamaya koyma ihtimalinin yüksek olduğunu düşünüyorum çünkü ihtiyaç duyulacakları (ve genellikle benim için belirgin olmayan) koşulları öngörüyorlardı.

(Bu kişilerin dinamik dilleri kullanma biçiminde ciddi bir dezavantaj olduğunu düşünüyorum. Çoğu zaman insanlar tüm statik testlerden vazgeçmek ve taklit etmek istemiyorlar.)

Ben en göze batan kapsamlı ActionScript 3 kodunu zarif javascript koduyla karşılaştırırken gördüm. AS3, j'lerin büyüklüğünün 3 veya 4 katı olabilir ve şüphelendiğim güvenilirlik, sadece alınan kodlama kararlarının sayısı (3-4X) nedeniyle en azından daha iyi değildir.

Dediğiniz gibi Shog9, YMMV. : D


1
if (! argument2) argument2 = 'default' argument2 = argument2 || 'default' - İkinci versiyonu görsel olarak daha hoş buluyorum ...
Christoph

5
Ve onu daha ayrıntılı ve dikkat dağıtıcı buluyorum; ama bu kişisel tercih, eminim.
dkretz

4
@ le dorfier: 0 ve boolean false gibi boş dizelerin kullanılmasını da engeller.
Shog9

@le dorfier: estetiğin ötesinde, önemli bir fark vardır: ikincisi, dikkatsiz bakıcıları varsayılan bir değerin basit atamasının ötesinde davranış eklemeye teşvik edebilecek etkili bir şekilde ikinci bir yürütme yolu oluşturur. YMMV, elbette.
Shog9

3
parametre2 bir boole ise === false; veya {return false;} işlevi?
fresko

7

Önemli farklılıklar var. Bazı test senaryoları oluşturalım:

var unused; // value will be undefined
Test("test1", "some value");
Test("test2");
Test("test3", unused);
Test("test4", null);
Test("test5", 0);
Test("test6", "");

Açıkladığınız ilk yöntemle varsayılan değeri yalnızca ikinci test kullanacaktır. İkinci yöntem JS dönüştürecektir olarak (her şeyden önce ancak varsayılan olarak undefined, null, 0, ve ""boolean içine falseTom'un yöntemi kullanmak olsaydı. Ve sadece dördüncü testi varsayılan kullanacağız!

Hangi yöntemi seçtiğiniz gerçekten amaçladığınız davranışa bağlıdır. Değerler dışındaki undefineddeğerlere izin veriliyorsa argument2, ilkinde büyük olasılıkla bir miktar değişiklik isteyeceksinizdir; sıfır olmayan, boş olmayan, boş olmayan bir değer isteniyorsa, ikinci yöntem idealdir - gerçekten de, genellikle bu kadar geniş bir değer aralığını dikkate almak için sıklıkla kullanılır.


7
url = url === undefined ? location.href : url;

Çıplak kemikler cevap verir. Bazı açıklamalar incitmezdi.
Paul Rooney

Kısaca şunu söyleyen üçlü bir operatördür: URL tanımsızsa (eksikse), url değişkenini location.href (geçerli web sayfası) olarak ayarlayın, aksi takdirde url değişkenini tanımlanan url olarak ayarlayın.
rmooney

5

ES6'da (ES2015) Varsayılan parametreleri kullanabilirsiniz

function Test(arg1 = 'Hello', arg2 = 'World!'){
  alert(arg1 + ' ' +arg2);
}

Test('Hello', 'World!'); // Hello World!
Test('Hello'); // Hello World!
Test(); // Hello World!


Bu cevap gerçekten ilginç ve op için faydalı olabilir. Bu soruya gerçekten cevap vermese de
Ulysse BN

Gördüğüm gibi - tanımlanmamışsa arg tanımlamak istiyor, bu yüzden bazı yararlı bilgiler yayınladım
Andriy2

Demek istediğim, JavaScript işlevine bir bağımsız değişken gönderilip gönderilmeyeceğini en iyi nasıl belirleyeceğinize yanıt vermiyorsunuz . Ama soru olabilir varsayılan argümanlar yanıt bulunamayan: Örneğin size olan argümanlar adlandırma "default value"ve değer gerçekten olup olmadığını kontrol "default value".
Ulysse BN

4

Üzgünüm, hala yorum yapamam, bu yüzden Tom'un cevabını cevaplamak için ... Javascript (undefined! = Null) == false Aslında fonksiyon "null" ile çalışmaz, "undefined" kullanmalısınız


1
Ve Tom yanlış bir cevap için iki oy aldı - bu topluluk sistemlerinin ne kadar iyi çalıştığını bilmek her zaman güzel;)
Christoph

3

Neden !!operatörü kullanmıyorsunuz ? Değişkenin önüne yerleştirilen bu operatör, bir boole'ye (iyi anladıysam) çevirir, böylece !!undefinedve !!null(ve hatta !!NaNoldukça ilginç olabilir) geri döner false.

İşte bir örnek:

function foo(bar){
    console.log(!!bar);
}

foo("hey") //=> will log true

foo() //=> will log false

Boolean true, zero ve empty dize ile çalışmaz. Örneğin, foo (0); yanlış günlüğe kaydedilecek, ancak foo (1) doğru günlüğe kaydedilecek
rosell.dk

2

İsteğe bağlı özelliklerin bir Nesnesi ile işlevinizi uyandırarak bağımsız değişken algılamaya yaklaşmak uygun olabilir:

function foo(options) {
    var config = { // defaults
        list: 'string value',
        of: [a, b, c],
        optional: {x: y},
        objects: function(param){
           // do stuff here
        }
    }; 
    if(options !== undefined){
        for (i in config) {
            if (config.hasOwnProperty(i)){
                if (options[i] !== undefined) { config[i] = options[i]; }
            }
        }
    }
}

2

Bir Orada iyi bulmak için zor yolu parametresi bir işlev ya da değil geçirilir olsun, . Aşağıdaki örneğe bir göz atın:

this.setCurrent = function(value) {
  this.current = value || 0;
};

Bu gerekli, değeri valueyoksa / iletilmezse - 0 olarak ayarlayın.

Çok havalı ha!


1
Bu aslında "eğer valueeşdeğerse false, 0'a ayarlayın " anlamına gelir. Bu ince ama çok önemli bir ayrım.
Charles Wood

@CharlesWood Değer iletilmedi / mevcut değil yalnızca yanlıştır
Mohammed Zameer

1
Tabii, eğer bu sizin fonksiyonunuza uyuyorsa. Ancak, örneğin, parametreniz boole ise trueve falsegeçerli değerler ise ve parametre hiç iletilmediğinde üçüncü bir davranışa sahip olmak isteyebilirsiniz (özellikle işlevin birden fazla parametresi varsa).
Charles Wood

1
Ve bunun bilgisayar biliminde büyük bir argüman olduğunu ve sadece bir fikir meselesi olabileceğini kabul etmeliyim: D
Charles Wood

@CharlesWood partiye geç kaldığım için üzgünüm. Bunları düzenleme seçeneğiyle cevaba eklemenizi öneririm
Mohammed Zameer

1

Bazı durumlarda, özellikle işlevi alıcı ve ayarlayıcı olarak kullanıyorsanız, türü denetlemek de isteyebilirsiniz. Aşağıdaki kod ES6'dır (EcmaScript 5 veya daha eski sürümlerde çalışmaz):

class PrivateTest {
    constructor(aNumber) {
        let _aNumber = aNumber;

        //Privileged setter/getter with access to private _number:
        this.aNumber = function(value) {
            if (value !== undefined && (typeof value === typeof _aNumber)) {
                _aNumber = value;
            }
            else {
                return _aNumber;
            }
        }
    }
}

0
function example(arg) {
  var argumentID = '0'; //1,2,3,4...whatever
  if (argumentID in arguments === false) {
    console.log(`the argument with id ${argumentID} was not passed to the function`);
  }
}

Çünkü diziler miras alır Object.prototype. Dünyayı daha iyi hale getirmek için ⇑ düşünün.


-1

fnCalledFunction (Param1, Param2, pencere.OptionalParameter)

Yukarıdaki fonksiyon birçok yerden çağrılmışsa ve ilk 2 parametrenin her yerden geçtiğinden eminseniz, ancak 3. parametreden emin değilseniz, pencereyi kullanabilirsiniz.

window.param3, arayan yönteminden tanımlı değilse işlem yapar.

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.