Vacuousness
Tüm dünyadaki herhangi bir değerin boş olup olmadığını hesaplayan bir işlev tanımlamaya veya kullanmaya çalışmanızı önermiyorum. Gerçekten "boş" olmak ne anlama geliyor? Eğer varsa let human = { name: 'bob', stomach: 'empty' }
, isEmpty(human)
geri dönmeli true
mi? Eğer varsa let reg = new RegExp('');
, isEmpty(reg)
geri dönmeli true
mi? Ne oldu isEmpty([ null, null, null, null ])
- bu liste sadece boşluk içeriyor, bu yüzden listenin kendisi boş mu? Ben burada javascript "boşluk" (kasıtlı olarak karanlık bir kelime, önceden var olan ilişkilendirmeleri önlemek için) bazı notlar koymak istiyorum - ve ben javascript değerleri "boşluk" asla genel olarak ele gerektiğini tartışmak istiyorum.
Truthiness / Falsiness
Değerlerin "boşluğunu" nasıl belirleyeceğimize karar vermek için, javascript'in dahili, içsel, değerlerin "doğru" veya "sahte" olup olmadığını anlamamız gerekir. Doğal olarak, null
ve undefined
her ikisi de "falsy" dir. Daha az doğal olarak, sayı 0
(ve başka hiçbir sayı hariç NaN
) de "sahte" dir. Doğal olarak en az: ''
sahtelik, ama []
ve {}
(ve new Set()
, ve new Map()
) doğrudur - hepsi eşit derecede boş görünüyor!
Null ve Tanımsız
İle ilgili bazı tartışmalar da vardır null
vs undefined
biz gerçekten bizim programlarında vacuousness ifade etmek amacıyla ikisine de ihtiyacım var? - Şahsen ben bu sırayla kodumda u, n, d, e, f, i, n, e, d harflerinin görünmesini önlerim. Her zaman null
"boşluk" anlamına gelir. Yine de, javascript'in doğasında nasıl null
ve nasıl undefined
farklı olduğu fikrini karşılamak zorundayız :
- Var olmayan bir mülke erişmeye çalışmak,
undefined
- Bir işlevi çağırırken bir parametrenin atlanması o parametrenin alınmasına neden olur
undefined
:
let f = a => a;
console.log(f('hi'));
console.log(f());
- Varsayılan değerlere sahip parametreler varsayılanı yalnızca verildiğinde alır
undefined
, değil null
:
let f = (v='hello') => v;
console.log(f(null));
console.log(f(undefined));
Jenerik Olmayan Boşluk
Boşluğun asla genel bir şekilde ele alınmaması gerektiğine inanıyorum. Bunun yerine her zaman boş olup olmadığını belirlemeden önce verilerimiz hakkında daha fazla bilgi almak için titizliğe sahip olmalıyız - Bunu esas olarak hangi tür verilerle uğraştığımı kontrol ederek yaparım:
let isType = (value, Cls) => {
try {
return Object.getPrototypeOf(value).constructor === Cls;
} catch(err) {
return false;
}
};
Bu işlevin polimorfizmi yok saydığına dikkat edin - bunun bir alt sınıfının örneği değil, value
doğrudan bir örneği olmasını bekler . İki ana nedenden dolayı kaçınırım :Cls
Cls
instanceof
([] instanceof Object) === true
("Dizi Nesnedir")
('' instanceof String) === false
("Bir Dize Bir Dize Değildir")
Bu işlev Object.getPrototypeOf
gibi bir durumu önlemek için kullanıldığını unutmayın let v = { constructor: String };
( isType
işlev) hala isType(v, String)
(false) ve isType(v, Object)
(true) için doğru döner .
Genel olarak, bu isType
işlevi aşağıdaki ipuçlarıyla birlikte kullanmanızı öneririz :
- Bilinmeyen türdeki kod işleme değerlerinin miktarını en aza indirin. Örneğin, için
let v = JSON.parse(someRawValue);
, bizim v
değişken artık bilinmeyen türde. Mümkün olduğunca erken, olasılıklarımızı sınırlamalıyız. Bunu yapmanın en iyi yolu, belirli bir tür gerektirmek olabilir: örneğin if (!isType(v, Array)) throw new Error('Expected Array');
- bu, genel doğasını kaldırmak ve v
her zaman bir sağlamak için gerçekten hızlı ve etkileyici bir yoldur Array
. Ancak bazen, v
birden fazla türde olmasına izin vermemiz gerekir . Bu durumlarda, v
mümkün olduğunca erken, artık genel olmayan kod blokları oluşturmalıyız :
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');
}
- Doğrulama için her zaman "beyaz listeleri" kullanın. Bir değerin örneğin Dize, Sayı veya Dizi olmasını istiyorsanız, bu 3 "beyaz" olasılığı kontrol edin ve 3'ten hiçbiri tatmin olmazsa bir Hata atın. "Siyah" olasılıkları kontrol etmenin çok yararlı olmadığını görebilmeliyiz: Diyelim ki yazıyoruz
if (v === null) throw new Error('Null value rejected');
- bu, null
değerlerin bunu gerçekleştirmemesini sağlamak için harikadır , ancak bir değer bunu başarırsa , hala çok az şey biliyoruz bunun hakkında herhangi bir şey. v
Bu boş denetimi geçen bir değer hala ÇOK genel - bir şey amanull
! Kara listeler jenerikliği neredeyse hiç yok etmez.
Bir değer olmadığı sürece null
, asla "boş bir değer" olarak düşünmeyin. Bunun yerine "boş olan bir X" düşünün. Esasen, asla böyle bir şey yapmayı düşünmeyin if (isEmpty(val)) { /* ... */ }
- bu isEmpty
fonksiyon nasıl uygulanırsa uygulansın (bilmek istemiyorum ...), anlamlı değil! Ve bu çok genel! Boşluk yalnızca türünün bilgisi ile hesaplanmalıdır val
. Boşluk kontrolleri şöyle görünmelidir:
- "Karakter içermeyen bir dize":
if (isType(val, String) && val.length === 0) ...
- "0 sahne olan bir nesne":
if (isType(val, Object) && Object.entries(val).length === 0) ...
- "Sıfıra eşit veya sıfırdan küçük bir sayı":
if (isType(val, Number) && val <= 0) ...
"Öğe içermeyen bir Dizi": if (isType(val, Array) && val.length === 0) ...
Bunun tek istisnası, null
belirli işlevleri belirtmek için kullanıldığındadır. Bu durumda "Boş bir değer" demek anlamlı:if (val === null) ...