Bagaimana cara mempersingkat blok saklar kasus yang mengubah angka menjadi nama bulan?

110

Adakah cara untuk menulis ini dengan lebih sedikit baris, tetapi masih mudah dibaca?

var month = '';

switch(mm) {
    case '1':
        month = 'January';
        break;
    case '2':
        month = 'February';
        break;
    case '3':
        month = 'March';
        break;
    case '4':
        month = 'April';
        break;
    case '5':
        month = 'May';
        break;
    case '6':
        month = 'June';
        break;
    case '7':
        month = 'July';
        break;
    case '8':
        month = 'August';
        break;
    case '9':
        month = 'September';
        break;
    case '10':
        month = 'October';
        break;
    case '11':
        month = 'November';
        break;
    case '12':
        month = 'December';
        break;
}
Leon Gaban
sumber
7
Jawaban IMHO vidriduch adalah yang paling tepat. Ini mungkin bukan satu-satunya bagian dari kode Anda yang memerlukan manipulasi Tanggal (meskipun yang Anda tunjukkan sangat mudah untuk dikodekan). Anda harus secara serius mempertimbangkan untuk menggunakan pustaka Tanggal yang sudah ada dan teruji.
coredump
2
Saya tidak tahu javascript, tapi bukankah ia memiliki hashmap, seperti kamus Python atau std :: map C ++?
Masked Man
28
Bukankah ini seharusnya untuk codereview.stackexchange.com ?
Loko
2
Begitu banyak jawaban yang mengubah perilaku kode dengan tidak memperhitungkan default '' yang menghasilkan keluaran tidak terdefinisi, yang berbeda dengan aslinya.
Pieter B
2
Ini bukan pertanyaan duplikat> :( ini menanyakan pertanyaan yang sama sekali berbeda, namun jawabannya mungkin sama.
Leon Gaban

Jawaban:

199

Tentukan array, lalu dapatkan dengan indeks.

var months = ['January', 'February', ...];

var month = months[mm - 1] || '';
xdazz
sumber
23
alih-alih mm - 1Anda juga dapat mengatur undefinedsebagai nilai pertama (indeks 0) sehingga indeks array akan cocok dengan nomor bulan
Touffy
9
var month = month[(mm -1) % 12]
mpez0
77
@ mpez0 Saya rasa saya lebih suka mengetahui bahwa seseorang berhasil menampilkan bulan nomor 15, daripada menyembunyikan data yang mungkin buruk
Izkata
21
@Touffy saya pikir saya akan bertahan mm-1, jadi itu months.length==12.
Teepeemm
48
@Touffy Saya berpendapat itu bukan masalah selera, tetapi masalah menghindari kode pintar . Bayangkan diri Anda membaca yang lain [undefined, 'January', 'February', ...]- saya yakin reaksi pertama Anda adalah WTF ?! , yang biasanya bukan pertanda baik ...
miraculixx
81

bagaimana jika tidak menggunakan array sama sekali :)

var objDate = new Date("10/11/2009"),
    locale = "en-us",
    month = objDate.toLocaleString(locale, { month: "long" });

console.log(month);

// or if you want the shorter date: (also possible to use "narrow" for "O"
console.log(objDate.toLocaleString(locale, { month: "short" }));

sesuai jawaban ini Dapatkan nama bulan dari Tanggal dari David Storey

vidriduch
sumber
2
Mengingat pernyataan masalah yang dimaksud, jawaban Anda tidak benar-benar menyelesaikan masalah itu tetapi beberapa solusi berbeda yang mungkin benar dalam konteks yang berbeda. Jawaban yang dipilih tetap yang terbaik dan paling efisien.
TechMaze
6
Hanya new Date("2009-11-10")format yang dijamin akan diurai (lihat spesifikasi ini: ecma-international.org/publications/standards/Ecma-262.htm ). Format tanggal lain (termasuk salah satu dalam jawaban Anda) dapat diurai jika browser memilihnya, dan karenanya tidak portabel.
jb.
58

Coba ini:

var months = {'1': 'January', '2': 'February'}; //etc
var month = months[mm];

Perhatikan bahwa mmbisa berupa integer atau string dan itu akan tetap berfungsi.

Jika Anda ingin kunci yang tidak ada menghasilkan string kosong ''(bukan undefined), tambahkan baris ini:

month = (month == undefined) ? '' : month;

JSFiddle .

Tapi Aku Bukan Kelas Pembungkus
sumber
4
Pada kumpulan data yang lebih besar daripada "bulan-bulan dalam setahun" ini mungkin akan lebih efisien.
DGM
3
Ini secara efektif merupakan enum (yaitu membuatnya tidak dapat diubah), mendefinisikannya sebagai var months = Object.freeze({'1': 'January', '2': 'February'}); //etcLihat Enum di JavaScript?
Alexander
1
@Alexander Jika Anda menukar kunci dan nilai, maka ya itu mirip dengan enum.
Tapi Aku Bukan Kelas Wrapper
26

Anda dapat membuat array dan mencari nama bulan:

var months = ['January','February','March','April','May','June','July','August','September','October','November','December']


var month = months[mm-1] || '';

Lihat jawaban oleh @CupawnTae untuk alasan di balik kode || ''

Alex
sumber
bukan awal dengan 0 indeks Anda bisa tetap undefineddi 0 sebagai var months = [ undefined, 'January','February','March', .....cara ini Anda akan menggunakanmonth = months[mm];
Grijesh Chauhan
@GrijeshChauhan: harap hindari kode 'pintar'. Reaksi pertama orang berikutnya adalah wtf. Ini hanya '-1', bulan. Panjangnya akan menjadi 13, wtf ^ 2. programmer.stackexchange.com/questions/91854/…
RvdK
19

Hati-hati!

Hal yang harus segera memicu lonceng alarm adalah baris pertama: var month = '';- mengapa variabel ini diinisialisasi ke string kosong, bukan nullatau undefined? Ini mungkin hanya kebiasaan atau salin / tempel kode, tetapi kecuali Anda tahu pasti, tidak aman untuk mengabaikannya saat Anda memfaktorkan ulang kode.

Jika Anda menggunakan array nama bulan dan mengubah kode var month = months[mm-1];Anda, Anda mengubah perilaku, karena sekarang untuk angka di luar rentang, atau nilai non-numerik, monthakan undefined. Anda mungkin tahu bahwa ini tidak masalah, tetapi ada banyak situasi di mana hal ini akan berdampak buruk.

Misalnya, Anda switchada dalam suatu fungsi monthToName(mm), dan seseorang memanggil fungsi Anda seperti ini:

var monthName = monthToName(mm);

if (monthName === '') {
  alert("Please enter a valid month.");
} else {
  submitMonth(monthName);
}

Sekarang jika Anda mengubah menggunakan array dan mengembalikan monthName[mm-1], kode panggilan tidak akan berfungsi lagi sebagaimana mestinya, dan akan mengirimkan undefinednilai ketika seharusnya menampilkan peringatan. Saya tidak mengatakan ini adalah kode yang bagus , tetapi kecuali Anda tahu persis bagaimana kode itu digunakan, Anda tidak dapat membuat asumsi.

Atau mungkin inisialisasi asli ada di sana karena beberapa kode lebih jauh mengasumsikan bahwa monthakan selalu berupa string, dan melakukan sesuatu seperti month.length- ini akan menghasilkan pengecualian yang dilemparkan selama beberapa bulan yang tidak valid dan berpotensi mematikan skrip pemanggil sepenuhnya.

Jika Anda benar- benar mengetahui konteks keseluruhan - mis. Itu semua adalah kode Anda sendiri, dan tidak ada orang lain yang akan menggunakannya, dan Anda percaya pada diri sendiri tidak lupa Anda membuat perubahan di masa mendatang - mungkin aman untuk mengubah perilaku seperti ini, tapi soooo banyak bug berasal dari asumsi semacam ini bahwa dalam kehidupan nyata Anda jauh lebih baik memprogram secara defensif dan / atau mendokumentasikan perilaku secara menyeluruh.

Jawaban Wasmoo benar (EDIT: sejumlah jawaban lain, termasuk yang diterima, kini telah diperbaiki juga) - Anda dapat menggunakanmonths[mm-1] || '' atau jika Anda lebih suka membuatnya lebih jelas sekilas tentang apa yang terjadi, seperti:

var months = ['January', 'February', ...];

var month;

if (mm >= 1 && m <= 12) {
  month = months[mm - 1];
} else {
  month = ''; // empty string when not a valid month
}
CupawnTae
sumber
1
Belum ada orang lain yang menyebutkan perubahan perilaku, jadi ini harus dipertimbangkan saat memfaktorkan ulang kode.
Mauro
Jawaban ini tepat. Sebagian besar jawaban lain mengubah perilaku kode dengan cara yang halus. Ini mungkin tidak masalah atau mungkin menjadi sangat sulit untuk menemukan bug.
Pieter B
Ah jadi itu selalu yang terbaik untuk memulai undefined? Apakah itu menghemat kinerja jika jenisnya dikonversi?
Leon Gaban
2
@LeonGaban ini bukan tentang kinerja: pertanyaan asli menginisialisasi variabel ke string kosong dan membiarkannya jika tidak ada bulan yang valid dipilih, sedangkan banyak jawaban lain di sini mengabaikan fakta itu dan mengubah perilaku dengan kembali undefinedketika input tidak t 1..12. Kecuali dalam keadaan yang sangat luar biasa, perilaku yang benar selalu mengalahkan kinerja.
CupawnTae
17

Untuk kelengkapan, saya ingin melengkapi jawaban saat ini. Pada dasarnya, Anda dapat menghilangkan breakkata kunci dan langsung mengembalikan nilai yang sesuai. Taktik ini berguna jika nilai tidak dapat disimpan dalam tabel pencarian yang dihitung sebelumnya.

function foo(mm) {
    switch(mm) {
        case '1':  return 'January';
        case '2':  return 'February';
        case '3':  return 'March';
        case '4':  return 'April';
        // [...]
        case '12': return 'December';
    }
    return '';
}

Sekali lagi, menggunakan tabel pencarian atau fungsi tanggal lebih ringkas dan lebih baik secara subyektif .

Gerard
sumber
16

Anda bisa melakukannya menggunakan array:

var months = ['January', 'February', 'March', 'April', 
              'May', 'June', 'July', 'August', 
              'September', 'October', 'November', 'December'];

var month = months[mm - 1] || '';
Stuart Wagner
sumber
12

Berikut opsi lain yang hanya menggunakan 1 variabel dan masih menerapkan nilai default ''saat mmberada di luar rentang.

var month = ['January', 'February', 'March',
             'April', 'May', 'June', 'July',
             'August', 'September', 'October',
             'November', 'December'
            ][mm-1] || '';
Wasmoo
sumber
Pemeriksaan jarak, dan melempar pengecualian juga bisa bekerja. Dan mengembalikan "Error", atau "Undefined" mungkin merupakan alternatif dari string kosong.
ChuckCottrill
9

Anda bisa menulisnya sebagai ekspresi alih-alih sakelar, menggunakan operator bersyarat:

var month =
  mm == 1 ? 'January' :
  mm == 2 ? 'February' :
  mm == 3 ? 'March' :
  mm == 4 ? 'April' :
  mm == 5 ? 'May' :
  mm == 6 ? 'June' :
  mm == 7 ? 'July' :
  mm == 8 ? 'August' :
  mm == 9 ? 'September' :
  mm == 10 ? 'October' :
  mm == 11 ? 'November' :
  mm == 12 ? 'December' :
  '';

Jika Anda belum pernah melihat operator bersyarat yang dirantai sebelumnya, ini mungkin tampak lebih sulit untuk dibaca pada awalnya. Menulisnya sebagai ekspresi membuat satu aspek lebih mudah dilihat daripada kode aslinya; jelas bahwa maksud kode adalah untuk memberikan nilai ke variabel month.

Guffa
sumber
1
Saya bermaksud menyarankan yang ini juga. Ini sebenarnya sangat mudah dibaca namun tetap ringkas, dan akan bekerja dengan baik untuk pemetaan jarang dan kunci non-numerik, yang tidak dapat dilakukan oleh solusi array. NB. Saya juga mendapat suara negatif yang tidak dapat dijelaskan secara acak pada jawaban saya - mungkin artis yang sama.
CupawnTae
6

Berdasarkan jawaban Cupawn Tae sebelumnya, saya akan mempersingkatnya menjadi:

var months = ['January', 'February', ...];
var month = (mm >= 1 && mm <= 12) ? months[mm - 1] : '';

Atau, ya, saya menghargai, kurang terbaca:

var month = months[mm - 1] || ''; // as mentioned further up
NeilElliott-NSDev
sumber
Anda dapat melewati (!!months[mm - 1])dan melakukannya months[mm - 1].
YingYang
Itu akan mengakibatkan tidak terdefinisi jika indeks larik berada di luar jangkauan!
NeilElliott-NSDev
months[mm - 1]akan mengembalikan undefinedindeks yang di luar jangkauan. Karena undefinedfalsy Anda akan berakhir dengan ''sebagai nilai month.
YingYang
Seperti yang dinyatakan dalam jawaban lain, Anda dapat lebih menyederhanakan baris ini:var month = months[mm - 1] || '';
YingYang
Meskipun saya telah memperhatikan lebih jauh (tidak ada saat saya memposting), var month = months [mm - 1] || ''; Mana yang lebih rapi.
NeilElliott-NSDev
4
var getMonth=function(month){
   //Return string to number.
    var strMonth = ['January', 'February', 'March',
             'April', 'May', 'June', 'July',
             'August', 'September', 'October',
             'November', 'December'
            ];
    //return number to string.
    var intMonth={'January':1, 'February':2, 'March':3,
             'April':4, 'May':5, 'June':6, 'July':7,
             'August':8, 'September':9, 'October':10,
             'November':11, 'December':12
            };
    //Check type and return 
    return (typeof month === "number")?strMonth[month-1]:intMonth[month]
}
Laxmikant Dange
sumber
4

Seperti @vidriduch, saya ingin menggarisbawahi pentingnya i20y ("kemampuan internasional") kode dalam konteks saat ini dan menyarankan solusi ringkas dan kuat berikut bersama dengan uji kesatuan.

function num2month(month, locale) {
    if (month != Math.floor(month) || month < 1 || month > 12)
        return undefined;
    var objDate = new Date(Math.floor(month) + "/1/1970");
    return objDate.toLocaleString(locale, {month: "long"});
}

/* Test/demo */
for (mm = 1; mm <= 12; mm++)
    document.writeln(num2month(mm, "en") + " " +
                     num2month(mm, "ar-lb") + "<br/>");
document.writeln(num2month("x", "en") + "<br/>");
document.writeln(num2month(.1, "en") + "<br/>");
document.writeln(num2month(12.5, "en" + "<br/>"));

Saya mencoba untuk sedekat mungkin dengan pertanyaan asli, yaitu mengubah angka 1 menjadi 12 menjadi nama bulan, tidak hanya untuk satu kasus khusus, tetapi kembali undefinedjika ada argumen yang tidak valid, menggunakan beberapa kritik yang ditambahkan sebelumnya ke dan isi dari yang lain jawaban. (Perubahan dari undefinedmenjadi ''sepele, jika diperlukan pencocokan tepat .)

Beladau
sumber
0

Saya akan mencari solusi wasmoo , tetapi sesuaikan seperti ini:

var month = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
][mm-1] || '';

Ini adalah kode yang persis sama, sungguh, tetapi berlekuk berbeda, yang membuatnya lebih mudah dibaca.

John Slegers
sumber