Tetapkan variabel dalam pernyataan kondisi apakah, praktik yang baik atau tidak? [Tutup]

113

Saya pindah satu tahun yang lalu dari bahasa OO klasik seperti Java ke JavaScript. Kode berikut jelas tidak direkomendasikan (atau bahkan tidak benar) di Java:

if(dayNumber = getClickedDayNumber(dayInfo))
{
    alert("day number found : " + dayNumber);
}
function getClickedDayNumber(dayInfo)
{
    dayNumber = dayInfo.indexOf("fc-day");
    if(dayNumber != -1) //substring found
    {
        //normally any calendar month consists of "40" days, so this will definitely pick up its day number.
        return parseInt(dayInfo.substring(dayNumber+6, dayNumber+8));
    }
    else return false;
}

Pada dasarnya saya baru tahu bahwa saya dapat menetapkan variabel ke nilai dalam pernyataan kondisi if, dan segera memeriksa nilai yang ditetapkan seolah-olah itu adalah boolean.

Untuk taruhan yang lebih aman, saya biasanya memisahkannya menjadi dua baris kode, tetapkan terlebih dahulu lalu periksa variabelnya, tetapi sekarang saya menemukan ini, saya hanya ingin tahu apakah ini praktik yang baik atau tidak di mata pengembang JavaScript berpengalaman?

Michael Mao
sumber
"The following code is definitely not recommended (or event not correct) in Java..."Apakah itu benar dalam JavaScript? Karena, sejauh yang saya lihat, Anda mengembalikan integer ( return parseInt(...)) jika dayNumber != -1benar, tetapi boolean jika salah.
Daniel Kvist

Jawaban:

117

Saya tidak akan merekomendasikannya. Masalahnya adalah, ini terlihat seperti kesalahan umum saat Anda mencoba membandingkan nilai, tetapi menggunakan nilai tunggal, =bukan ==atau ===. Misalnya, saat Anda melihat ini:

if (value = someFunction()) {
    ...
}

Anda tidak tahu apakah itu yang ingin mereka lakukan, atau apakah mereka bermaksud menulis ini:

if (value == someFunction()) {
    ...
}

Jika Anda benar-benar ingin melakukan tugas tersebut, saya akan merekomendasikan untuk melakukan perbandingan eksplisit juga:

if ((value = someFunction()) === <whatever truthy value you are expecting>) {
    ...
}
Matthew Crumley
sumber
1
@Matthew Crumley: ini menjawab pertanyaan saya dengan jelas. Saya tidak memeriksa dengan menetapkan tetapi memeriksa apa pun yang nilainya mengevaluasi setelah tugas. Apakah pemahaman ini benar?
Michael Mao
1
@ Michael: ya, itu benar. Menambahkan perbandingan pada dasarnya hanya membuat niat Anda lebih jelas.
Matthew Crumley
4
Namun, contoh terakhir tidak berfungsi jika Anda menguji kegagalan / keberhasilan fungsi yang mengembalikan boolean. Dengan kata lain, while if (resultArr = myNeedle.exec(myHaystack)) {...}works if ((resultArr = myNeedle.exec(myHaystack)) === true) {...}bukan karena penugasan ke resultArr selalu benar meski hasil fungsinya bukan. Jika ada yang menggunakan ini .. konstruksi, ingatlah untuk mendeklarasikan variabel hasil terlebih dahulu; 'var' tidak sah dalam pernyataan kondisi if.
Ville
3
Anda dapat menggunakan if (!!(value = someFunction())), tetapi seperti yang Anda katakan, masalahnya adalah Anda tidak dapat menggunakan varinside ifsehingga Anda akhirnya menciptakan global, atau tidak mencapai apa-apa karena Anda tetap harus mendeklarasikannya valuedi baris terpisah. Malu, saya sangat menyukai konstruksi ini di C ++.
riv
1
@riv, Anda benar; dalam hal fungsi mengembalikan boolean - seperti yang saya katakan di komentar saya di atas - maka kondisional berfungsi seperti yang diharapkan. Tetapi jika fungsi mengembalikan boolean (seperti dalam contoh saya) maka keseluruhan konstruksi adalah jenis non-sensical; jelas garis pemikiran saya adalah - dilihat dari contoh - bahwa fungsi tersebut akan mengembalikan array. Pengujian cepat menunjukkan bahwa kondisi mengevaluasi truehanya ketika fungsi kembali true, tetapi dalam semua kasus lain (termasuk ketika array, string, angka, atau nol dikembalikan) yang dievaluasi false.
Ville
28

Saya tidak melihat bukti bahwa ini bukan praktik yang baik. Ya, ini mungkin terlihat seperti kesalahan tetapi itu mudah diatasi dengan komentar yang bijaksana. Ambil contoh:

if (x = processorIntensiveFunction()) { // declaration inside if intended
    alert(x);
}

Mengapa fungsi itu diizinkan untuk berjalan untuk kedua kalinya dengan:

alert(processorIntensiveFunction());

Karena versi pertama TERLIHAT buruk? Saya tidak setuju dengan logika itu.

Adrian Bartholomew
sumber
32
Bukan untuk menggali komentar lama, tapi saya tidak setuju dengan argumen Anda. Kode yang dapat dibaca harus menjelaskan dirinya sendiri tanpa perlu komentar - menambahkan komentar ke kode yang membingungkan bukanlah solusi. Adapun bagian kedua, yang mengatakan alternatifnya adalah memanggil fungsi itu lagi, saya rasa tidak ada yang berniat melakukan itu. Sebaliknya Anda akan melakukanx = processorItensiveFunction(); if(x) { alert(x); }
maksim
9
@maksim: Saya suka kode yang dapat dibaca, tapi itu tidak berarti kode harus dibodohi atau terlalu bertele-tele. Menyebarkan sesuatu melalui banyak baris dan mengubah nilai antar variabel sebenarnya dapat menyebabkan kode yang lebih buruk. Kode yang disisipkan dapat memiliki efek samping yang tidak terduga dalam bahasa yang diketik dengan lemah / fleksibel seperti JS. Penugasan dalam pernyataan bersyarat valid di javascript, karena Anda hanya bertanya "jika penugasan valid, lakukan sesuatu yang mungkin menyertakan hasil penugasan". Tapi memang, assigning before the conditional juga valid, tidak terlalu bertele-tele, dan lebih umum digunakan.
okdewit
1
@maksim mengapa menurut Anda if ( ! x = anyFunction() )tidak dapat dibaca? Tidak perlu ada komentar apa pun.
JDrake
Jika Anda memperbaiki OPC, bekerja dengan pengembang lain dari berbagai tingkat keahlian (dengan kata lain, Anda adalah seorang profesional) Anda akan benci bahwa ini bahkan mungkin.
davidjmcclelland
2
@maksim - juga solusi Anda akan sangat tidak nyaman dalam suatu if-elsesituasi. Pertimbangkan- Prioritas if (condition) {...} else if (x = processorIntensiveFunction()) {alert(x)} Anda x = processorIntensiveFunction();akan menjadi usaha yang sia-sia jika awalnya conditionbenar.
Adrian Bartholomew
16

Saya melakukannya berkali-kali. Untuk melewati peringatan JavaScript, saya menambahkan dua tanda kurung:

if ((result = get_something())) { }

Anda harus menghindarinya, jika Anda benar-benar ingin menggunakannya, tulis komentar di atasnya dengan mengatakan apa yang Anda lakukan.

Ming-Tang
sumber
1
@SHiNKiROU: bagaimana saya bisa melihat peringatan javascript? Apakah ada kompiler Javascript? atau penerjemah akan mengeluarkan semacam peringatan? Saya menggunakan konsol Firefox seperti pada javascript debugging sepanjang waktu tetapi tidak pernah melihat keluaran yang serupa. Maaf tentang pengalaman saya yang terbatas.
Michael Mao
5
@Michael: JSLint ( jslint.com ) adalah program / pustaka populer yang memeriksa program JavaScript untuk kemungkinan kesalahan atau kode buruk.
Matthew Crumley
Gunakan Mozilla Firefox dengan Firebug dan / atau ekstensi Pengembang Web untuk memeriksa peringatan.
Ming-Tang
Saya baru saja mencobanya dengan di if ((a = [1, 2]).length > 0) { console.log(a); }mana abelum diinisialisasi di mana pun dan itu memang berhasil (bagus! Membuat penggunaan regex jauh lebih mudah). Apakah ini benar bahwa saya tidak membutuhkannya di var|const|letsini? Apakah Anda kebetulan tahu di mana saya bisa membaca lebih banyak tentang trik ini ?
t3chb0t
4

Anda juga dapat melakukan ini di Java. Dan tidak, ini bukan praktik yang baik. :)

(Dan gunakan ===dalam Javascript untuk kesetaraan yang diketik. Baca buku Crockford's The Good Parts di JS.)

Ben Zotto
sumber
@quixoto: Bisakah saya melakukan trik ini di Java? Saya ingin tahu ... Saya tidak memiliki jdk dengan atm tangan jadi saya tidak bisa mendapatkan kode sampel di Jawa. Dari ingatan saya yang buruk, Java hanya akan memberi Anda Runtime error jika nilai yang dikembalikan mengevaluasi sesuatu yang bukan boolean seperti jika pernyataan bersyarat, bukan?
Michael Mao
1
Ah, ya, di Java, jenisnya diperiksa menjadi jenis boolean. Tapi Anda bisa melakukannyaif (foo = getSomeBoolValue()) { }
Ben Zotto
ya itu benar. variabel boolean untuk menguji apakah sesuatu berhasil dan variabel lain untuk menyimpan nilai yang dikembalikan. Begitulah cara Java melakukan tugasnya, saya terlalu terbiasa dengan itu jadi saya merasa aneh melihat Javascript dapat melakukan dua hal dalam satu baris saja :)
Michael Mao
@BenZotto itu bukan praktik yang baik, mengapa? "Untuk menghindari penyalahgunaan variabel yang tidak disengaja, biasanya merupakan ide yang baik untuk memperkenalkan variabel ke dalam cakupan sekecil mungkin. Secara khusus, biasanya yang terbaik adalah menunda definisi variabel sampai seseorang dapat memberikan nilai awal ... Salah satu aplikasi paling elegan dari kedua prinsip ini adalah mendeklarasikan variabel dalam kondisi bersyarat. " - Stroustrup, "Bahasa Pemrograman C ++."
JDrake
1
Hai, saya datang ke sini sebagai pengguna javascript node.js. Mengapa tidak ada praktik yang baik dalam satu kasus yang saya alami: if (myvar = 'just a test') Membuat variabel GLOBAL node.js myvar ( nodejs.org/docs/latest-v12.x/api/globals.html #globals_global ). Jadi jika Anda seperti saya dan menggunakan variabel itu dalam penanganan permintaan server (kembali ke sana setelah beberapa detik ketika permintaan lain mungkin turun dan sebagainya), Anda dapat terkejut dengan hasil apa yang Anda dapatkan. Jadi rekomendasinya adalah: Perhatikan bahwa pola ini membuat variabel global di node.js.
pein-consulting.de
4

Ada satu kasus saat Anda melakukannya, dengan while-loops.
Saat membaca file, biasanya Anda melakukan seperti ini:

void readFile(String pathToFile) {
    // Create a FileInputStream object
    FileInputStream fileIn = null;
    try {
        // Create the FileInputStream
        fileIn = new FileInputStream(pathToFile);
        // Create a variable to store the current line's text in
        String currentLine;
        // While the file has lines left, read the next line,
        // store it in the variable and do whatever is in the loop
        while((currentLine = in.readLine()) != null) {
            // Print out the current line in the console
            // (you can do whatever you want with the line. this is just an example)
            System.out.println(currentLine);
        }
    } catch(IOException e) {
        // Handle exception
    } finally {
        try {
            // Close the FileInputStream
            fileIn.close();
        } catch(IOException e) {
            // Handle exception
        }
    }
}

Lihat while-loop pada baris 9. Di sana, baris baru dibaca dan disimpan dalam variabel, dan kemudian isi loop dijalankan. Saya tahu ini bukan if-statement, tapi saya rasa beberapa saat loop dapat dimasukkan dalam pertanyaan Anda juga.

Alasan untuk ini adalah bahwa ketika menggunakan FileInputStream, setiap kali Anda memanggil FileInputStream.readLine(), itu membaca baris berikutnya dalam file, jadi jika Anda akan memanggilnya dari perulangan dengan hanya fileIn.readLine() != nulltanpa menetapkan variabel, daripada memanggil (currentLine = fileIn.readLine()) != null, dan kemudian memanggilnya dari di dalam loop juga, Anda hanya akan mendapatkan setiap baris kedua.

Semoga Anda mengerti, dan semoga berhasil!

Daniel Kvist
sumber
3

Anda juga dapat melakukan tugas dalam pernyataan if di Java. Contoh yang bagus adalah membaca sesuatu dan menuliskannya:

http://www.exampledepot.com/egs/java.io/CopyFile.html?l=new

Kode:

// Copies src file to dst file.
// If the dst file does not exist, it is created
void copy(File src, File dst) throws IOException 
{
    InputStream in = new FileInputStream(src);
    OutputStream out = new FileOutputStream(dst);

    // Transfer bytes from in to out
    byte[] buf = new byte[1024];
    int len;
    while ((len = in.read(buf)) > 0) {
        out.write(buf, 0, len);
    }
    in.close();
    out.close();
}
Nitrodist
sumber
@ Nitrodist: terima kasih untuk contoh ini. Saya benar-benar tidak ahli dalam Java atau javascript ... Senang mengetahui bahwa pendekatan ini juga dapat dilakukan di Java :)
Michael Mao
Saya tidak mengerti maksudnya. Anda dapat melakukannya di Java, PHP, dan banyak bahasa lainnya. Pertanyaannya adalah tentang Javascript.
pmrotule
Tidak, belum tentu, Anda perlu membaca ulang pertanyaannya dengan cermat.
Nitrodist
3

Jika Anda merujuk ke buku Martin Fowlers Refactoring memperbaiki desain kode yang ada ! Lalu ada beberapa kasus di mana itu akan menjadi praktik yang baik misalnya. persyaratan kompleks yang panjang untuk menggunakan panggilan fungsi atau metode untuk menegaskan kasus Anda:

"Motivasi

Salah satu area kompleksitas yang paling umum dalam sebuah program terletak pada logika kondisional yang kompleks. Saat Anda menulis kode untuk menguji kondisi dan melakukan berbagai hal tergantung pada berbagai kondisi, Anda akan segera berakhir dengan metode yang cukup panjang. Panjang suatu metode dengan sendirinya merupakan faktor yang membuatnya lebih sulit untuk dibaca, tetapi kondisi menambah kesulitan. Masalahnya biasanya terletak pada fakta bahwa kode, baik dalam pemeriksaan kondisi dan tindakan, memberi tahu Anda apa yang terjadi tetapi dapat dengan mudah mengaburkan mengapa itu terjadi.

Seperti halnya blok kode besar lainnya, Anda dapat memperjelas maksud Anda dengan mendekomposisi dan mengganti potongan kode dengan pemanggilan metode yang dinamai sesuai maksud blok kode tersebut. > Dengan kondisi Anda dapat menerima manfaat lebih lanjut dengan melakukan ini untuk bagian bersyarat dan setiap alternatif. Dengan cara ini Anda menyorot kondisi dan membuatnya dengan jelas> bercabang. Anda juga menyoroti alasan percabangan tersebut. "

Dan ya jawabannya juga berlaku untuk implementasi Java. Itu tidak menetapkan fungsi kondisional ke variabel meskipun dalam contoh.

allan
sumber
1

Ini bukan praktik yang baik. Anda akan segera bingung tentang itu. Ini terlihat serupa dengan kesalahan umum: operator misuse "=" dan "==".

Anda harus memecahnya menjadi 2 baris kode. Ini tidak hanya membantu membuat kode lebih jelas, tetapi juga mudah untuk difaktor ulang di masa mendatang. Bayangkan Anda mengubah kondisi IF? Anda mungkin tidak sengaja menghapus garis dan variabel Anda tidak lagi mendapatkan nilai yang ditetapkan padanya.

thethanghn
sumber
@thethanghn: itulah yang saya takutkan. ketika saya bertambah tua dan malas, saya hanya tidak ingin mengetik lebih banyak ke dalam kode jika lebih sedikit penekanan tombol saja sudah cukup :)
Michael Mao
1
Tidak, saya tidak bingung dan saya melakukannya sepanjang waktu. Ada manfaatnya.
JDrake
Itu sangat tergantung, bukan? Jika Anda berasal dari latar belakang 'C' (dan bahasa lain berdasarkan C), maka konstruksinya sangat familiar, dan alternatifnya sangat aneh. IMO, itu adalah sesuatu yang dipelajari sekali dan kemudian Anda tahu. Itu bukanlah sesuatu yang akan membuat Anda tersandung lebih dari sekali.
Max Waterman
0

Saya akan menganggap ini lebih dari gaya C sekolah tua; ini bukan praktik yang baik dalam JavaScript jadi Anda harus menghindarinya.

Justin Ethier
sumber
8
Saya juga tidak menganggapnya sebagai praktik yang baik di C.
Matthew Crumley
1
Saya menganggapnya sebagai praktik yang baik dalam banyak bahasa.
JDrake
Hanya mengatakan 'bukan praktik yang baik' saja tidak cukup, imo. Ini benar-benar hanya tentang pendidikan - itu dipelajari sekali, dan hanya itu.
Max Waterman
0

Anda bisa melakukan sesuatu seperti ini:

if (value = /* sic */ some_function()){
  use_value(value)
}
Joseph Le Brech
sumber
0

Saya datang ke sini dari golang, di mana melihat sesuatu seperti itu biasa

if (err := doSomething(); err != nil) {
    return nil, err
}

Di mana errhanya dicakup ke ifblok itu. Karena itu, inilah yang saya lakukan di es6, yang tampaknya cukup jelek, tetapi tidak membuat aturan eslint saya yang agak ketat berubah, dan mencapai hal yang sama.

{
  const err = doSomething()
  if (err != null) {
    return (null, err)
  }
}

Tanda kurung kurawal menentukan, eh, "lingkup leksikal" baru? Artinya saya bisa menggunakan const, dan errtidak tersedia untuk blok luar.

Adam Barnes
sumber