Apakah JS Boolean yang memiliki properti khusus merupakan praktik yang buruk?

41

Di JS Anda dapat mengembalikan Boolean yang memiliki properti khusus. Misalnya. ketika Modernizr menguji dukungan video, ia mengembalikan trueatau falsetetapi Boolean yang dikembalikan (Bool adalah objek kelas satu di JS) memiliki properti yang menentukan format apa yang didukung. Pada awalnya itu sedikit mengejutkan saya tetapi kemudian saya mulai menyukai ide itu dan mulai bertanya-tanya mengapa itu tampaknya digunakan dengan hemat?

Sepertinya cara yang elegan untuk berurusan dengan semua skenario di mana Anda pada dasarnya ingin tahu apakah sesuatu itu benar atau salah tetapi Anda mungkin tertarik pada beberapa info tambahan yang dapat Anda tetapkan tanpa mendefinisikan objek pengembalian kustom atau menggunakan fungsi panggilan balik yang disiapkan untuk menerima lebih banyak parameter. Dengan cara ini Anda mempertahankan fungsi tanda tangan yang sangat universal tanpa mengurangi kapasitas untuk mengembalikan data yang lebih kompleks.

Ada 3 argumen yang menentangnya yang bisa saya bayangkan:

  1. Agak jarang / tidak terduga ketika mungkin lebih baik untuk setiap antarmuka menjadi jelas dan tidak rumit.
  2. Ini mungkin argumen orang bodoh, tetapi dengan itu menjadi sedikit kasus tepi saya bisa membayangkan diam-diam menjadi bumerang di beberapa pengoptimal JS, uglifier, VM atau setelah perubahan spesifikasi bahasa pembersihan kecil dll.
  3. Ada yang lebih baik - ringkas, jelas dan umum - cara melakukan hal yang persis sama.

Jadi pertanyaan saya adalah adakah alasan kuat untuk menghindari menggunakan Boolean dengan properti tambahan? Apakah itu tipuan atau hadiah?


Plot tikungan peringatan.

Di atas adalah pertanyaan asli dengan penuh kemuliaan. Seperti yang ditunjukkan oleh Matthew Crumley dan senevoldsen, itu didasarkan pada premis yang salah (salah?). Dalam tradisi JS yang bagus apa yang dilakukan Modernizr adalah trik bahasa dan yang kotor. Itu bermuara pada JS yang memiliki bool primitif yang jika disetel ke false akan tetap salah bahkan setelah MENCOBA untuk menambahkan alat peraga (yang gagal diam-diam) dan objek Boolean yang dapat memiliki alat peraga khusus tetapi menjadi objek selalu benar. Modernizr mengembalikan boolean false atau objek Boolean yang sebenarnya.

Pertanyaan awal saya mengasumsikan triknya bekerja secara berbeda dan sebagian besar jawaban populer berhubungan dengan aspek standar pengkodean (yang benar-benar valid). Namun saya menemukan jawaban yang membantah seluruh trik ini sangat membantu (dan juga argumen terakhir yang menentang penggunaan metode ini) jadi saya menerima salah satunya. Terima kasih untuk semua peserta!

konrad
sumber
35
Memperluas tipe boolean adalah wtf klasik .
hlovdal
7
Perhatikan bahwa di JS, mereka bisa saja kembali nulljika tidak didukung dan berbagai format jika demikian. Daftar dianggap benar di JS, dan nullpalsu.
jpmc26
3
Sebelum Anda menjawab pertanyaan ini: di javascript ada perbedaan besar antara "boolean" dan "Boolean". Mereka bukan hal yang sama dan jawaban apa pun yang tidak menggunakan huruf besar Boolean tidak valid.
Pieter B
2
Bagi Anda yang terpana melihat sesuatu seperti ini di alam bebas, di perpustakaan sepopuler Modernizr, berikut adalah kode yang relevan dari GitHub mereka: github.com/Modernizr/Modernizr/blob/…
Chris Nielsen

Jawaban:

38

Selain prinsip-prinsip desain umum, seperti tanggung jawab tunggal, dan paling tidak mengejutkan, ada alasan khusus JavaScript bahwa itu bukan ide yang baik: ada perbedaan besar antara a booleandan Booleandalam JavaScript yang mencegahnya bekerja dalam kasus umum.

booleanadalah tipe primitif, bukan objek, dan tidak dapat memiliki properti khusus. Ekspresi suka true.toString()bekerja karena di belakang layar, itu berubah menjadi (new Boolean(true)).toString().

Boolean(dengan huruf B) adalah objek, tetapi memiliki sedikit kegunaan yang baik, dan digunakan sebagai booleanjelas bukan salah satunya. Alasan untuk itu adalah, bahwa setiap Boolean"benar", terlepas dari nilainya , karena semua objek dikonversi ke truedalam konteks boolean. Misalnya, coba ini:

var answer = new Boolean(false);
if (answer) {
  console.log("That was unexpected.");
}

Jadi, secara umum, tidak ada cara untuk menambahkan properti ke boolean dalam JavaScript yang masih memungkinkannya berperilaku secara logis. Modernizr bisa lolos begitu saja karena hanya menambah properti ke nilai "true", jenis pekerjaan seperti yang Anda harapkan (yaitu mereka bekerja dalam pernyataan if). Jika video tidak didukung sama sekali, Modernizr.videoakan menjadi aktual boolean(dengan nilai false), dan tidak dapat menambahkan properti ke dalamnya.

Matthew Crumley
sumber
18
Saya menemukan pendekatan Modernizr agak aneh, mengingat bahwa hanya memiliki objek dengan properti sudah dievaluasi truedalam kondisi. Mengapa menggunakan secara eksplisit Boolean?
Arturo Torres Sánchez
Terima kasih banyak untuk argumen teknis yang bagus. Sepertinya tes cepat saya cacat: jsbin.com/hurebi/3/edit?js,console . Bahkan setelah menambahkan alat peraga khusus untuk falseitu benar-benar 'palsu' dan palsu ( ===dan ==berfungsi sebagai) TAPI memang Anda sebenarnya tidak dapat menambahkan alat peraga ke bool primitif. Perbedaan antara Bool dan bool ternyata membuat saya bingung.
konrad
@ ArturoTorresSánchez karena cara mereka melakukannya nilai-nilai pengembalian secara nominal dari jenis yang sama.
Jared Smith
1
@ ArturoTorresSánchez itu sebabnya saya menambahkan kualifikasi "nominal": P
Jared Smith
1
@konrad Sebagai referensi, secara default JavaScript akan berpura-pura membiarkan Anda menambahkan properti ke primitif dengan tidak mengeluh ketika Anda mencoba melakukannya. Menggunakan mode ketat akan memperbaikinya, dan melempar TypeErrorjika Anda mencoba menambahkan properti (lihat jsbin.com/yovasafibo/edit?js,console ).
Matthew Crumley
59

Selamat, Anda telah menemukan benda. Alasan untuk tidak melakukan ini disebut prinsip ketakjuban . Terkejut dengan desain bukanlah hal yang baik.

Tidak ada yang salah dengan menggabungkan informasi ini tetapi mengapa Anda ingin menyembunyikannya di Bool? Masukkan ke dalam sesuatu yang Anda harapkan memiliki semua informasi ini. Termasuk bool.

candied_orange
sumber
1
LOL ya saya sebutkan objek sebagai alternatif yang jelas dalam pertanyaan saya. Prinsip paling tidak heran adalah poin yang baik meskipun dengan JS objek mengetik yang lemah kurang mengejutkan tetapi masih membingungkan dan Anda perlu memeriksa dokumen pula. Adapun penggunaan Modernizr adalah contoh yang baik: Anda memiliki serangkaian besar tes dengan hasil benar / salah yang seragam dan hanya sekarang dan kemudian Anda perlu memberikan info lebih lanjut - bahkan mungkin kebutuhan untuk itu datang kemudian jadi ketika itu Anda bisa membuat perubahan pada seluruh perpustakaan yang membuat sebagian besar pembungkus berlebihan di sekitar boolean atau Anda meningkatkan boole. IMO tidak begitu bodoh.
konrad
1
Sedikit lebih banyak tentang penggunaan. Jika Anda tetap mengembalikan nilai boolean, Anda dapat meneruskan semua fungsi ke daftar operasi seperti (), semua (), filter () dengan mudah. Ini menghindari kurangnya pengetikan yang kuat atau antarmuka formal di JS dengan biaya sedikit tidak konvensional - yang tampaknya sejauh ini menjadi argumen utama yang menentangnya.
konrad
1
"Tidak konvensional" sepertinya bukan argumen yang kuat bagi saya.
Robert Harvey
Saya mengedit pertanyaan. Inilah prinsip yang paling mengejutkan. :-)
konrad
16

Argumen utama yang saya pegang terhadapnya adalah, prinsip tanggung jawab tunggal , seorang boolean seharusnya hanya mengatakan jika sesuatu itu trueatau false, bukan mengapa atau bagaimana atau hal lainnya. Adalah keyakinan dan praktik saya yang teguh bahwa benda-benda lain harus digunakan untuk mengomunikasikannya atau informasi lainnya.

J. Pichardo
sumber
maksud Anda boolean atau Boolean (dengan modal B) di javascript ada perbedaan.
Pieter B
Tetapi jika Anda memiliki objek yang mendefinisikan hal ini dan beberapa hal lain, bukankah itu bisa melanggar prinsip yang sama?
Casey
1
@Casey Tidak karena tujuan dari objek itu akan berbeda dari boolean asli. Dan itu hanya akan memiliki satu tanggung jawab, untuk mengomunikasikan keadaan dan alasan transaksi, sebagai contoh.
J. Pichardo
1
@Casey masalahnya bukan bahwa mengandung informasi ini dengan sendirinya merupakan pelanggaran terhadap SRP. Ini hanya menjadi masalah ketika dikombinasikan dengan tanggung jawab yang sudah dimiliki boolean - untuk mewakili benar atau salah. BooleanMeskipun demikian, kekurangan JavaScript .
Jacob Raihle
10

Karena seluruh alasan itu disebut nilai boolean adalah fakta itu benar atau salah, saya tidak suka ide itu, karena Anda cukup banyak merusak seluruh tujuannya dari wikipedia

Dalam ilmu komputer, tipe data Boolean adalah tipe data, yang memiliki dua nilai (biasanya dilambangkan benar dan salah), dimaksudkan untuk mewakili nilai kebenaran logika dan aljabar Boolean .

(huruf tebal saya)

Nama tampilan
sumber
1
benar, tetapi kebutuhan dapat menentukan sebaliknya
svarog
8
@svarog satu-satunya kebutuhan saya dapat melihat adalah desainer kode tidak terampil. Jika Anda perlu mengembalikan bool dan sesuatu yang lain, buat kelas, atau tuple, atau daftar, atau apa pun yang cocok dengan kode tertentu.
MatthewRock
jika Anda kembali ya
svarog
Saya pikir pertanyaannya adalah tentang objek Boolean bukan boolean primitif. Objek bukan nilai.
Pieter B
1
Jika bisa mengambil nilai selain benar atau salah, itu juga bukan boolean. Yang diberi nama itu konyol.
berguna
2

Hanya karena Anda tidak dapat berarti Anda harus melakukannya, di JS Anda dapat cukup banyak melampirkan properti ke objek apa pun (termasuk Boolean)

Bagaimana itu hal yang buruk?

Di satu sisi, Anda dapat melampirkan lebih banyak data yang tidak relevan ke Boolean (per contoh Anda), sesuatu yang tidak diharapkan oleh pengembang lain karena mengapa harus ada di sana ?! bools hanya untuk benar dan salah.

Titik baliknya adalah melampirkan beberapa properti berguna yang relevan yang dapat membantu Anda menangani nilai boolean ( Java melakukan itu ).

Misalnya, Anda dapat melampirkan fungsi yang mengubah nilai boolean menjadi string, dirtybendera yang berubah benar jika nilai diubah, pengamat dan callback peristiwa yang dapat diaktifkan ketika nilai diubah dll.

tetapi Boolean yang dikembalikan (Bool adalah objek kelas pertama di JS) memiliki properti yang menentukan format apa yang didukung

Kedengarannya seperti sesuatu yang tidak boleh disimpan dalam Boolean, melainkan menggunakan Set boolean, atau Set properti dengan boolean di dalamnya. Saya pikir pendekatan yang lebih baik adalah mengembalikan objek dengan semua format dan detail dukungan.

{
    isSomethingSupported: true,
    isSomethingElseSupported: false,
    ....
}
svarog
sumber
1
maksud Anda boolean atau Boolean (dengan modal B)?
Pieter B
1

Anda tidak dapat membuat boolean dengan properti khusus di JavaScript. Gagal berikut (setidaknya dalam FF):

    var x = false;
    x.foo = "bar";
    console.log(x.foo);

Anda dapat menggunakan, atau mewarisi dari Boolean, tetapi seperti yang dikatakan Matthew Crumley itu memberikan hasil yang berbeda. Booleanadalah tipe Object . Ketika JS membutuhkan nilai boolean dari ekspresi yang dikonversikan menggunakan fungsi spesifikasi ToBoolean, yang mengamanatkan bahwa untuk Objecthasilnya selalu true. Dengan demikian nilai new Boolean(false)dievaluasi menjadi true! Anda dapat memverifikasi ini dalam contoh ini: https://jsfiddle.net/md7abx5z/3/ .

Satu-satunya alasan ia bekerja untuk Modernizr adalah insidental. Mereka hanya membuat Booleanobjek ketika kondisinya benar. Ketika mereka menilai salah mereka hanya kembali biasa false. Jadi itu berhasil karena mereka hanya mengembalikan Boolean objek ketika hasilnya benar, dan tidak pernah ketika itu salah.

senevoldsen
sumber
1

Saya mengerti konteksnya telah berubah, tetapi saya ingin menjawab pertanyaan asli yang saya baca menggunakan JS sebagai contoh, tetapi tidak terbatas pada JS saja.

Menambahkan properti ke boolean, tidak akan menjadi masalah JIKA properti itu ada hubungannya dengan true / false, bukan dengan variabel yang menyimpan nilai. Sebagai contoh, menambahkan metode toYesNoString akan baik-baik saja, menambahkan numberOfChildren ke nilai hasChildren tidak, dan tidak akan pertanyaan. Tidak banyak yang bisa Anda tambahkan ke boolean, selain berbagai repesentasi string, satu-satunya properti yang dapat saya pikirkan yang masuk akal adalah originalExpression. Namun menambahkannya tidak selalu merupakan ide buruk dalam teori.

jmoreno
sumber
0

Jika saya melihat kode ini bukan tentang memberikan properti kustom Boolean tetapi tentang metode yang memiliki metode pengembalian dengan tanda tangan yang berbeda.

Jika itu salah maka Anda mendapatkan primitif salah dan jika itu benar itu mengembalikan objek yang menurut definisi ditafsirkan sebagai benar dalam javascript.

Jadi, menurut saya pertanyaan Anda tidak boleh apakah itu ide yang baik untuk memberikan properti kustom Boolean tetapi apakah itu ide yang baik untuk memiliki metode dengan tanda tangan kembali ganda.

Pieter B
sumber
0

Dalam contoh yang diberikan, tidak bisakah Anda mengembalikan array dari semua format video yang didukung?

  • Array kosong berarti "tidak ada format video yang didukung", yang artinya "tidak ada video yang didukung".
  • Kalau tidak, jika ada format video yang didukung, maka jelas video secara umum didukung.

Paling tidak saya akan mengatakan bahwa menggunakan array agak kurang mengejutkan daripada memiliki "custom booleans".

Dalam Javascript, array kosong bahkan dianggap falsy , sedangkan array non-kosong truthy , sehingga dengan sedikit keberuntungan Anda hanya bisa beralih ke array dan semuanya akan bekerja seperti sebelumnya mengedit Tidak, konyol saya untuk berpikir aku bisa ingat truthiness yang objek dalam JavaScript: P

daniero
sumber
Array kosong tidak bernilai false dalam pernyataan if. if ([]) console.log ('not false'); mencetak 'not false' di Chrome misalnya. typeof [] === 'objek' jadi tidak ada array kosong yang tidak palsu. Lihat developer.mozilla.org/en-US/docs/Glossary/Truthy untuk referensi.
joshp
@ joshp oops, kau benar, salahku. Diperbaiki
daniero
Meskipun, saya tidak yakin bahwa jenis hal membuktikan apa pun; ""memiliki tipe "string"tetapi sebenarnya palsu
daniero
1
Di sisi lain, [].lengthapakah falsey jika panjang 0, tidak lebih banyak mengetik, dan menurut saya merupakan indikasi niat yang lebih baik daripada hanya if([])jika itu berhasil.
IllusiveBrian
@daniero Poin tentang typeof [] === 'objek' adalah bahwa setiap Objek adalah benar, bahkan Boolean baru (salah). Beberapa tipe primitif (mis. String "" dan angka 0) adalah falsy, tetapi mereka bukan Object sejauh menyangkut typeof. Itu hanya cara lain untuk diingat. Ini bukan tentang membuktikan apa pun. Buktinya ada dalam spesifikasi atau tes, mana yang Anda inginkan.
joshp