Pertanyaan Apakah ada cara yang lebih baik untuk melakukan parameter fungsi opsional di JavaScript? [duplikat]


Pertanyaan ini sudah memiliki jawaban di sini:

Saya selalu menangani parameter opsional di JavaScript seperti ini:

function myFunc(requiredArg, optionalArg){
  optionalArg = optionalArg || 'defaultValue';

  // Do stuff
}

Apakah ada cara yang lebih baik untuk melakukannya?

Apakah ada kasus di mana menggunakan || seperti itu akan gagal?


756
2017-09-29 14:27


asal


Jawaban:


Logika Anda gagal jika optionalArg dilewatkan, tetapi mengevaluasi sebagai salah - coba ini sebagai alternatif

if (typeof optionalArg === 'undefined') { optionalArg = 'default'; }

Atau idiom alternatif:

optionalArg = (typeof optionalArg === 'undefined') ? 'default' : optionalArg;

Gunakan idiom mana pun yang berkomunikasi dengan niat terbaik untuk Anda!


1012
2017-09-29 14:30



Saya menemukan ini menjadi cara paling sederhana, paling mudah dibaca:

if (typeof myVariable === 'undefined') { myVariable = 'default'; }
//use myVariable here

Jawaban Paul Dixon (menurut pendapat saya) kurang bisa dibaca daripada ini, tetapi itu tergantung pada preferensi.

Jawabannya jauh lebih maju, tetapi jauh lebih berguna untuk fungsi-fungsi besar!

EDIT 11/17/2013 9:33 pm: Saya telah membuat paket untuk Node.js yang membuatnya lebih mudah untuk fungsi "overload" (metode) dipanggil parametrik.


125
2017-11-14 21:23



Di ECMAScript 2015 (alias "ES6") Anda dapat mendeklarasikan nilai argumen default dalam deklarasi fungsi:

function myFunc(requiredArg, optionalArg = 'defaultValue') {
    // do stuff
}

Lebih banyak tentang mereka di artikel ini di MDN (meskipun judul artikel, mereka disebut "argumen," bukan "parameter," di JavaScript).

Ini saat ini hanya didukung oleh Firefox, tetapi karena standar telah selesai, mengharapkan dukungan untuk meningkat dengan cepat.


119
2018-02-19 13:13



Jika Anda perlu membuang secara harfiah NULL di, maka Anda bisa memiliki beberapa masalah. Terlepas dari itu, tidak, saya pikir Anda mungkin berada di jalur yang benar.

Metode lain yang dipilih beberapa orang adalah mengambil serangkaian variabel assoc iterating melalui daftar argumen. Kelihatannya sedikit lebih rapi tapi saya membayangkan itu sedikit (sangat sedikit) sedikit lebih banyak proses / memori yang intensif.

function myFunction (argArray) {
    var defaults = {
        'arg1'  :   "value 1",
        'arg2'  :   "value 2",
        'arg3'  :   "value 3",
        'arg4'  :   "value 4"
    }

    for(var i in defaults) 
        if(typeof argArray[i] == "undefined") 
               argArray[i] = defaults[i];

    // ...
}

44
2017-09-29 14:34



Idealnya, Anda akan refactor untuk melewati suatu objek dan menggabungkan dengan objek default, sehingga urutan di mana argumen dilewatkan tidak masalah (lihat bagian kedua dari jawaban ini, di bawah).

Namun, jika Anda hanya menginginkan sesuatu yang cepat, andal, mudah digunakan, dan tidak besar, coba ini:


Perbaikan cepat bersih untuk sejumlah argumen default

  • Ini skala elegan: kode ekstra minimal untuk setiap default baru
  • Anda dapat menempelkannya di mana saja: cukup ubah jumlah argumen dan variabel yang diperlukan
  • Jika Anda ingin lulus undefined ke argumen dengan nilai default, dengan cara ini, variabel ditetapkan sebagai undefined. Sebagian besar opsi lain di halaman ini akan diganti undefined dengan nilai default.

Berikut ini contoh untuk menyediakan default untuk tiga argumen opsional (dengan dua argumen yang diperlukan)

function myFunc( requiredA, requiredB,  optionalA, optionalB, optionalC ) {

  switch (arguments.length - 2) { // 2 is the number of required arguments
    case 0:  optionalA = 'Some default';
    case 1:  optionalB = 'Another default';
    case 2:  optionalC = 'Some other default';
    // no breaks between cases: each case implies the next cases are also needed
  }

}

Demo sederhana. Ini mirip dengan Jawaban roenving, tetapi mudah diperluas untuk sejumlah argumen default, lebih mudah untuk diperbarui, dan menggunakan arguments tidak Function.arguments.


Melewati dan menggabungkan objek agar lebih fleksibel

Kode di atas, seperti banyak cara melakukan argumen default, tidak dapat meneruskan argumen dari urutan, misalnya, lewat optionalCtapi pergi optionalB untuk kembali ke defaultnya.

Pilihan yang bagus untuk itu adalah melewatkan objek dan menggabungkan dengan objek default. Ini juga bagus untuk pemeliharaan (cukup berhati-hati untuk menjaga agar kode Anda terbaca, sehingga para kolaborator masa depan tidak akan dibiarkan menebak tentang kemungkinan konten dari objek yang Anda keluarkan).

Contoh menggunakan jQuery. Jika Anda tidak menggunakan jQuery, Anda bisa menggunakan Underscore _.defaults(object, defaults) atau telusuri opsi ini:

function myFunc( args ) {
  var defaults = {
    optionalA: 'Some default',
    optionalB: 'Another default',
    optionalC: 'Some other default'
  };
  args = $.extend({}, defaults, args);
}

Ini contoh sederhana dalam aksi.


32
2018-02-20 15:36



Anda dapat menggunakan beberapa skema berbeda untuk itu. Saya selalu menguji argumennya.panjang:

function myFunc(requiredArg, optionalArg){
  optionalArg = myFunc.arguments.length<2 ? 'defaultValue' : optionalArg;

  ...

- melakukannya, itu tidak mungkin gagal, tapi saya tidak tahu apakah jalan Anda memiliki kesempatan untuk gagal, sekarang saya tidak bisa memikirkan skenario, di mana itu benar-benar akan gagal ...

Dan kemudian Paulus memberikan satu skenario gagal! -)


17
2017-09-29 14:33



Mirip dengan jawaban Oli, saya menggunakan argumen Object dan Object yang mendefinisikan nilai default. Dengan sedikit gula ...

/**
 * Updates an object's properties with other objects' properties. All
 * additional non-falsy arguments will have their properties copied to the
 * destination object, in the order given.
 */
function extend(dest) {
  for (var i = 1, l = arguments.length; i < l; i++) {
    var src = arguments[i]
    if (!src) {
      continue
    }
    for (var property in src) {
      if (src.hasOwnProperty(property)) {
        dest[property] = src[property]
      }
    }
  }
  return dest
}

/**
 * Inherit another function's prototype without invoking the function.
 */
function inherits(child, parent) {
  var F = function() {}
  F.prototype = parent.prototype
  child.prototype = new F()
  child.prototype.constructor = child
  return child
}

... ini bisa dibuat sedikit lebih baik.

function Field(kwargs) {
  kwargs = extend({
    required: true, widget: null, label: null, initial: null,
    helpText: null, errorMessages: null
  }, kwargs)
  this.required = kwargs.required
  this.label = kwargs.label
  this.initial = kwargs.initial
  // ...and so on...
}

function CharField(kwargs) {
  kwargs = extend({
    maxLength: null, minLength: null
  }, kwargs)
  this.maxLength = kwargs.maxLength
  this.minLength = kwargs.minLength
  Field.call(this, kwargs)
}
inherits(CharField, Field)

Apa yang baik tentang metode ini?

  • Anda dapat menghilangkan argumen sebanyak yang Anda suka - jika Anda hanya ingin mengganti nilai satu argumen, Anda dapat memberikan argumen itu, daripada harus secara eksplisit lulus undefined kapan, katakanlah ada 5 argumen dan Anda hanya ingin menyesuaikan yang terakhir, seperti yang harus Anda lakukan dengan beberapa metode lain yang disarankan.
  • Ketika bekerja dengan Fungsi konstruktor untuk suatu objek yang mewarisi dari yang lain, mudah untuk menerima argumen apa pun yang diperlukan oleh konstruktor dari Objek yang Anda warisi, karena Anda tidak harus menyebutkan argumen tersebut dalam tanda tangan konstruktor Anda, atau bahkan memberikan default Anda sendiri (biarkan konstruktor Object induk melakukan itu untuk Anda, seperti yang terlihat di atas kapan CharField panggilan Fieldkonstruktor).
  • Obyek anak dalam hierarki warisan dapat menyesuaikan argumen untuk konstruktor induknya sesuai yang mereka inginkan, menegakkan nilai default mereka sendiri atau memastikan bahwa nilai tertentu akan selalu digunakan.

13
2017-09-29 23:16



Jika Anda menggunakan default secara luas, ini tampaknya lebih mudah dibaca:

function usageExemple(a,b,c,d){
    //defaults
    a=defaultValue(a,1);
    b=defaultValue(b,2);
    c=defaultValue(c,4);
    d=defaultValue(d,8);

    var x = a+b+c+d;
    return x;
}

Cukup deklarasikan fungsi ini pada escope global.

function defaultValue(variable,defaultValue){
    return(typeof variable!=='undefined')?(variable):(defaultValue);
}

Pola penggunaan fruit = defaultValue(fruit,'Apple');

* PS Anda dapat mengganti nama defaultValue berfungsi untuk nama pendek, hanya tidak digunakan default itu kata yang dilindungi undang-undang di javascript.


8
2018-05-15 21:23



Pemeriksaan tipe longgar

Mudah ditulis, tapi 0, '', false, null dan undefined akan dikonversi ke nilai default, yang mungkin tidak diharapkan.

function myFunc(requiredArg, optionalArg) {
    optionalArg = optionalArg || 'defaultValue';
}

Memeriksa tipe yang ketat

Lebih panjang, tetapi mencakup sebagian besar kasus. Hanya kasus di mana salah menetapkan nilai default adalah ketika kita lulus undefined sebagai parameter.

function myFunc(requiredArg, optionalArg) {
    optionalArg = typeof optionalArg !== 'undefined' ? optionalArg : 'defaultValue';
}

Memeriksa variabel argumen

Menangkap semua kasus tetapi yang paling kikuk untuk ditulis.

function myFunc(requiredArg, optionalArg1, optionalArg2) {
    optionalArg1 = arguments.length > 1 ? optionalArg1 : 'defaultValue';
    optionalArg2 = arguments.length > 2 ? optionalArg2 : 'defaultValue';
}

ES6

Sayangnya ini memiliki dukungan browser yang sangat buruk saat ini

function myFunc(requiredArg, optionalArg = 'defaultValue') {

}

8
2018-05-15 13:46