Kekosongan
Saya tidak menyarankan mencoba mendefinisikan atau menggunakan fungsi yang menghitung apakah nilai di seluruh dunia kosong. Apa artinya menjadi "kosong"? Jika sudah let human = { name: 'bob', stomach: 'empty' }
, haruskah isEmpty(human)
kembali true
? Jika sudah let reg = new RegExp('');
, haruskah isEmpty(reg)
kembali true
? Bagaimana dengan isEmpty([ null, null, null, null ])
- daftar ini hanya berisi kekosongan, jadi apakah daftar itu sendiri kosong? Saya ingin mengajukan beberapa catatan tentang "kekosongan" (kata yang sengaja dikaburkan, untuk menghindari asosiasi yang sudah ada sebelumnya) dalam javascript - dan saya ingin berdebat bahwa "kekosongan" dalam nilai-nilai javascript tidak boleh ditangani secara umum.
Kebenaran / Kepalsuan
Untuk memutuskan bagaimana menentukan "kekosongan" dari nilai-nilai, kita perlu mengakomodasi inbuilt javascript, rasa yang melekat pada apakah nilai-nilai itu "benar" atau "salah". Secara alami, null
dan undefined
keduanya "palsu". Kurang alami, jumlahnya 0
(dan tidak ada nomor lain kecuali NaN
) juga "palsu". Paling tidak secara alami: ''
adalah palsu, tetapi []
dan {}
(dan new Set()
, dan new Map()
) adalah kebenaran - meskipun mereka semua tampak sama-sama hampa!
Null vs Tidak terdefinisi
Ada juga beberapa diskusi tentang null
vs undefined
- apakah kita benar - benar membutuhkan keduanya untuk mengekspresikan kekosongan dalam program kita? Saya pribadi menghindari agar huruf-huruf u, n, d, e, f, i, n, e, d muncul dalam kode saya dalam urutan itu. Saya selalu menggunakan null
untuk menandakan "kekosongan". Namun, sekali lagi, kita perlu mengakomodasi pengertian inheren javascript tentang bagaimana null
dan undefined
berbeda:
- Mencoba mengakses memberi properti tidak ada
undefined
- Menghilangkan parameter saat memanggil fungsi menghasilkan parameter yang menerima
undefined
:
let f = a => a;
console.log(f('hi'));
console.log(f());
- Parameter dengan nilai default hanya menerima default saat diberikan
undefined
, bukan null
:
let f = (v='hello') => v;
console.log(f(null));
console.log(f(undefined));
Kekosongan non-generik
Saya percaya bahwa kekosongan seharusnya tidak pernah ditangani dengan cara yang umum. Sebagai gantinya, kita harus selalu memiliki kekakuan untuk mendapatkan lebih banyak informasi tentang data kita sebelum menentukan apakah data itu kosong - saya terutama melakukan ini dengan memeriksa jenis data apa yang saya hadapi:
let isType = (value, Cls) => {
try {
return Object.getPrototypeOf(value).constructor === Cls;
} catch(err) {
return false;
}
};
Perhatikan bahwa fungsi ini mengabaikan polimorfisme - ia diharapkan value
menjadi turunan langsung dari Cls
, dan bukan turunan dari subkelas dari Cls
. Saya menghindari instanceof
karena dua alasan utama:
([] instanceof Object) === true
("Array adalah Obyek")
('' instanceof String) === false
("String bukan String")
Perhatikan bahwa Object.getPrototypeOf
digunakan untuk menghindari kasus seperti let v = { constructor: String };
The isType
fungsi masih kembali dengan benar untuk isType(v, String)
(palsu), danisType(v, Object)
(benar).
Secara keseluruhan, saya sarankan menggunakan isType
fungsi ini bersama dengan tips ini:
- Minimalkan jumlah nilai pemrosesan kode dari tipe yang tidak dikenal. Misalnya, untuk
let v = JSON.parse(someRawValue);
, v
variabel kami sekarang dari tipe tidak dikenal. Sedini mungkin, kita harus membatasi kemungkinan kita. Cara terbaik untuk melakukan ini bisa dengan memerlukan jenis tertentu: misalnya if (!isType(v, Array)) throw new Error('Expected Array');
- ini adalah cara yang sangat cepat dan ekspresif untuk menghilangkan sifat generik v
, dan memastikan itu selalu menjadi Array
. Namun, kadang-kadang, kita perlu mengizinkan v
beberapa tipe. Dalam kasus tersebut, kita harus membuat blok kode v
yang tidak lagi generik, sedini mungkin:
if (isType(v, String)) {
/* v isn't generic in this block - It's a String! */
} else if (isType(v, Number)) {
/* v isn't generic in this block - It's a Number! */
} else if (isType(v, Array)) {
/* v isn't generic in this block - it's an Array! */
} else {
throw new Error('Expected String, Number, or Array');
}
- Selalu gunakan "daftar putih" untuk validasi. Jika Anda membutuhkan nilai untuk menjadi, misalnya, String, Nomor, atau Array, periksa 3 kemungkinan "putih", dan melemparkan Kesalahan jika tidak ada dari 3 yang puas. Kita harus bisa melihat memeriksa bahwa untuk "hitam" kemungkinan tidak sangat berguna: Katakanlah kita menulis
if (v === null) throw new Error('Null value rejected');
- ini sangat bagus untuk memastikan bahwa null
nilai-nilai tidak membuatnya melalui, tetapi jika nilai tidak membuatnya melalui, kita masih tahu hampir tidak apapun tentang itu. Nilai v
yang lolos dari pemeriksaan nol ini masih SANGAT generik - sama sekali tidaknull
! Daftar hitam hampir tidak menghilangkan sifat generik.
Kecuali jika nilainya null
, jangan pernah menganggap "nilai yang kosong". Sebagai gantinya, pertimbangkan "sebuah X yang kosong". Pada dasarnya, jangan pernah mempertimbangkan untuk melakukan hal seperti if (isEmpty(val)) { /* ... */ }
- tidak peduli bagaimana isEmpty
fungsi itu diimplementasikan (saya tidak ingin tahu ...), itu tidak berarti! Dan itu terlalu generik! Kekosongan seharusnya hanya dihitung dengan val
tipe pengetahuan . Pengecekan kekosongan seharusnya terlihat seperti ini:
- "Sebuah string, tanpa karakter":
if (isType(val, String) && val.length === 0) ...
- "Sebuah Objek, dengan 0 properti":
if (isType(val, Object) && Object.entries(val).length === 0) ...
- "Angka, sama atau kurang dari nol":
if (isType(val, Number) && val <= 0) ...
"An Array, tanpa item": if (isType(val, Array) && val.length === 0) ...
Satu-satunya pengecualian adalah ketika null
digunakan untuk menandakan fungsi tertentu. Dalam hal ini, bermakna untuk mengatakan: "Nilai kosong":if (val === null) ...