Boş dizilerin aynı anda doğru ve yanlış olduğu görülüyor


201

Boş diziler doğrudur ancak aynı zamanda yanlış değerine eşittir.

var arr = [];
console.log('Array:', arr);
if (arr) console.log("It's true!");
if (arr == false) console.log("It's false!");
if (arr && arr == false) console.log("...what??");

Bu eşitlik operatörü tarafından işletilen örtük dönüşüm nedeniyle sanırım.

Perde arkasında neler olup bittiğini açıklayan var mı?


1
İşte konuya biraz ışık tutması gereken benzer bir konu: stackoverflow.com/questions/4226101/…
Rion Williams

2
Not, bu arr == truedoğru değil ;-)
Michael Krelin - hacker

5
Vay canına ... sadece bütün bunların bittiğini düşündüğün zaman.
harpo

3
Javascript türü zorlama WTF'den kaçınmak için katı eşitlik opeartorunu kullanın ===. Eğer bir dizinin boşluğunu test etmek istiyorsanız, kullanınarr === []
DjebbZ

17
Bir dizinin boşluğunu test etmek istiyorsanız KULLANMAYIN arr === [], çünkü sağ taraf yeni bir dizi başlatırken ve soldaki değişken az önce oluşturduğunuz bir şeye işaret edemez. Test boşluğu yukarıya bakılarak yapılmalıdır arr.length === 0.
Kyle Baker

Yanıtlar:


274

Burada farklı şeyleri test ediyorsunuz.

if (arr) nesneye çağrılan (Dizi JS'deki Object örneğidir) nesnenin var olup olmadığını kontrol eder ve true / false döndürür.

Aradığınızda if (arr == false)karşılaştırmak değerleri bu nesnenin ve ilkel bir falsedeğer. Dahili olarak arr.toString()boş bir dize döndüren çağrılır "".

Bunun nedeni toStringArray öğesinde çağrılması Array.join()ve boş dizenin JavaScript'teki yanlış değerlerden biri olmasıdır.


2
Neden Boolean([])geri döndüğünü açıklayabilir misin true?
Devy

11
bu kural olarak, JS'de nesneler Boole'ye zorlanıyorsa, her zaman TRUE'ya zorlanırlar. "Boolean bağlamı" tablosuna bakın: javascript.info/tutorial/object-conversion
Niki

2
@ JavaScript'teki tüm nesneler doğrudur, bu nedenle herhangi bir nesneyi Boole'ye dönüştürmek doğrudur. Bkz 2ality.com/2013/08/objects-truthy.html
Thomson

62

Hat ile ilgili olarak:

if (arr == false) console.log("It's false!");

Belki bunlar yardımcı olacaktır:

console.log(0 == false) // true
console.log([] == 0) // true
console.log([] == "") // true

falseGerçek olduğuna inandığım şey , booleanın 0bir nesneyle (sol taraf) karşılaştırma yapmak için zorlanmasıdır . Nesne bir dizeye (boş dize) zorlanır. Daha sonra, boş dize bir sayıya, yani sıfıra zorlanır. Ve son karşılaştırma 0== 0, yani true.

Düzenleme: Tam olarak nasıl çalıştığı hakkında ayrıntılar için teknik özelliklerin bu bölümüne bakın .

Kural # 1'den başlayarak olanlar:

1. Tür (x) Tür (y) 'den farklıysa, 14. adıma gidin.

Geçerli olan bir sonraki kural # 19:

19. Type (y) Boolean ise, x == ToNumber (y) karşılaştırmasının sonucunu döndürün.

Sonucu ToNumber(false)olduğunu 0şimdi var bu yüzden,:

[] == 0

Yine, # 1 kuralı bize # 14 adıma atlamamızı söyler, ancak gerçekte geçerli olan bir sonraki adım # 21'dir:

21. Tür (x) Nesne ve Tür (y) Dize veya Sayı ise, karşılaştırmanın sonucunu ToPrimitive (x) == y olarak döndürün.

Sonucu ToPrimitive([])şimdi var bu yüzden, boş dizedir:

"" == 0

Yine, # 1 kuralı bize # 14 adıma atlamamızı söyler, ancak gerçekte geçerli olan bir sonraki adım # 17'dir:

17. Tür (x) Dize ve Tür (y) Sayı ise, karşılaştırmanın sonucunu döndürün ToNumber (x) == y.

Sonucu ToNumber("")DİR 0bize bırakır,:

0 == 0

Şimdi, her iki değer de aynı türe sahip, bu nedenle adımlar # 1'den # 7'ye kadar devam ediyor;

7. x, y ile aynı sayı değeriyse, true değerini döndürün.

Böylece geri dönüyoruz true.

Kısaca:

ToNumber(ToPrimitive([])) == ToNumber(false)

2
Harika referans! Karışıklığı önlemek için, # 1 kuralı "14. adıma git" demesine rağmen "geçerli olan bir sonraki kural # 19" nedeninin belirtilmesi yararlı olabilir. değerleri karşılaştırılıyor.
Sean the Bean

2
Güzel açıklama. Boş dizilerin doğru olduğu düşünülüyor, 0 yanlıştır ve yine [] == 0de doğrudur. Bunun spesifikasyon açıklamanıza göre nasıl olduğunu anlıyorum, ama mantıklı bir bakış açısından tuhaf dil davranışı gibi görünüyor.
bigh_29

7

Wayne'in cevabını desteklemek ve neden ToPrimitive([])geri döndüğünü açıklamaya çalışmak için ""'neden' sorusuna iki olası cevap türünü düşünmeye değer. İlk cevap türü: "çünkü şartname JavaScript'in bu şekilde davranacağını söylüyor." ES5 spesifikasyonunda, ToPrimitive sonucunu bir Nesne için varsayılan değer olarak tanımlayan bölüm 9.1 :

Bir nesnenin varsayılan değeri, isteğe bağlı ipucu PreferredType iletilerek nesnenin [[DefaultValue]] dahili yöntemi çağrılarak alınır.

Bölüm 8.12.8 tarif [[DefaultValue]]yöntem. Bu yöntem bağımsız değişken olarak bir "ipucu" alır ve ipucu Dize veya Sayı olabilir. İpucu dize ise, o zaman, bazı ayrıntıları vazgeçilerek madde kolaylaştırmak için [[DefaultValue]]değerini verir toString()varsa ve bir temel değerini verir ve aksi takdirde değerini verir valueOf(). Eğer ipucu Sayı ise, öncelikleri toString()ve valueOf()tersi olur, böylece valueOf()ilk denir ve ilkel ise değeri döndürülür. Böylece, [[DefaultValue]]sonucu döndürürse toString()veyavalueOf() nesne için belirtilen PreferredType bağlıdır ve olsun ya da olmasın, bu fonksiyonlar ilkel değerler verir.

Varsayılan valueOf()Object yöntemi yalnızca nesnenin kendisini döndürür; başka bir deyişle, bir sınıf varsayılan yöntemi geçersiz kılmadığı sürece valueOf()Object'in kendisini döndürür. Bu böyledir Array. [].valueOf()nesnenin []kendisini döndürür . Bir Arraynesne ilkel olmadığından, [[DefaultValue]]ipucu önemsizdir: bir dizinin dönüş değeri,toString() .

David Flanagan'ın JavaScript: Alıntı Rehberi , bu arada, bu tür sorulara cevap almak için herkesin ilk yeri olması gereken mükemmel bir kitap:

Bu nesne-sayı dönüşümünün ayrıntıları, boş bir dizinin neden 0 rakamına dönüştürdüğünü ve tek bir öğeye sahip bir dizinin neden bir sayıya dönüşebileceğini açıklar. Diziler, ilkel bir değer yerine bir nesne döndüren varsayılan valueOf () yöntemini devralır, böylece dizi-sayı dönüşümü toString () yöntemine dayanır. Boş diziler boş dizeye dönüştürülür. Ve boş dize, 0 rakamına dönüştürür. Tek bir öğeye sahip bir dizi, bir öğeyle aynı dizeye dönüştürülür. Bir dizi tek bir sayı içeriyorsa, bu sayı bir dizeye ve sonra tekrar bir sayıya dönüştürülür.

"Spesifikasyon söylediği için" dışında "neden" sorusunun ikinci cevabı, davranışın neden tasarım perspektifinden anlamlı olduğuna dair bazı açıklamalar verir. Bu konuda sadece spekülasyon yapabilirim. İlk olarak, bir dizi bir sayıya nasıl dönüştürülür? Düşünebildiğim tek mantıklı olasılık, boş bir diziyi 0'a ve boş olmayan herhangi bir diziyi 1'e dönüştürmek olacaktır. Ancak Wayne'in cevabı ortaya çıktığı gibi, boş bir dizi zaten birçok karşılaştırma türü için 0'a dönüştürülecektir. Bunun ötesinde, Array.valueOf () için mantıklı bir ilkel dönüş değeri düşünmek zor. Öyleyse Array.valueOf(), varsayılan olmanın ve Dizinin kendisini geri döndürmenin daha mantıklı olduğu iddia edilebilir.toString() olmanın ve Dizinin ToPrimitive tarafından kullanılan sonuç olur. Bir Array'ı sayıdan ziyade dizeye dönüştürmek daha mantıklıdır.

Ayrıca, Flanagan alıntısının da işaret ettiği gibi, bu tasarım kararı belirli türden faydalı davranışları mümkün kılmaktadır. Örneğin:

var a = [17], b = 17, c=1;
console.log(a==b);      // <= true
console.log(a==c);      // <= false

Bu davranış, tek öğeli bir diziyi sayılarla karşılaştırmanıza ve beklenen sonucu almanıza olanak tanır.


3
console.log('-- types: undefined, boolean, number, string, object --');
console.log(typeof undefined);  // undefined
console.log(typeof null);       // object
console.log(typeof NaN);        // number
console.log(typeof false);      // boolean
console.log(typeof 0);          // number
console.log(typeof "");         // string
console.log(typeof []);         // object
console.log(typeof {});         // object

console.log('-- Different values: NotExist, Falsy, NaN, [], {} --');
console.log('-- 1. NotExist values: undefined, null have same value --');
console.log(undefined == null); // true

console.log('-- 2. Falsy values: false, 0, "" have same value --');
console.log(false == 0);        // true
console.log(false == "");       // true
console.log(0 == "");           // true

console.log('-- 3. !NotExist, !Falsy, and !NaN return true --');
console.log(!undefined);        // true
console.log(!null);             // true

console.log(!false);            // true
console.log(!"");               // true
console.log(!0);                // true

console.log(!NaN);              // true

console.log('-- 4. [] is not falsy, but [] == false because [].toString() returns "" --');
console.log(false == []);       // true
console.log([].toString());     // ""

console.log(![]);               // false

console.log('-- 5. {} is not falsy, and {} != false, because {}.toString() returns "[object Object]" --');
console.log(false == {});       // false
console.log({}.toString());     // [object Object]

console.log(!{});               // false

console.log('-- Comparing --');
console.log('-- 1. string will be converted to number or NaN when comparing with a number, and "" will be converted to 0 --');
console.log(12 < "2");          // false
console.log("12" < "2");        // true
console.log("" < 2);            // true

console.log('-- 2. NaN can not be compared with any value, even if NaN itself, always return false --');
console.log(NaN == NaN);        // false

console.log(NaN == null);       // false
console.log(NaN == undefined);  // false
console.log(0 <= NaN);          // false
console.log(0 >= NaN);          // false
console.log(undefined <= NaN);  // false
console.log(undefined >= NaN);  // false
console.log(null <= NaN);       // false
console.log(null >= NaN);       // false

console.log(2 <= "2a");         // false, since "2a" is converted to NaN
console.log(2 >= "2a");         // false, since "2a" is converted to NaN

console.log('-- 3. undefined can only == null and == undefined, and can not do any other comparing even if <= undefined --');
console.log(undefined == null);         // true
console.log(undefined == undefined);    // true

console.log(undefined == "");           // false
console.log(undefined == false);        // false
console.log(undefined <= undefined);    // false
console.log(undefined <= null);         // false
console.log(undefined >= null);         // false
console.log(0 <= undefined);            // false
console.log(0 >= undefined);            // false

console.log('-- 4. null will be converted to "" when <, >, <=, >= comparing --');
console.log(12 <= null);        // false
console.log(12 >= null);        // true
console.log("12" <= null);      // false
console.log("12" >= null);      // true

console.log(0 == null);         // false
console.log("" == null);        // false

console.log('-- 5. object, including {}, [], will be call toString() when comparing --');
console.log(12 < {});           // false, since {}.toString() is "[object Object]", and then converted to NaN
console.log(12 > {});           // false, since {}.toString() is "[object Object]", and then converted to NaN
console.log("[a" < {});         // true, since {}.toString() is "[object Object]"
console.log("[a" > {});         // false, since {}.toString() is "[object Object]"
console.log(12 < []);           // false, since {}.toString() is "", and then converted to 0
console.log(12 > []);           // true, since {}.toString() is "", and then converted to 0
console.log("[a" < []);         // false, since {}.toString() is ""
console.log("[a" > []);         // true, since {}.toString() is ""

console.log('-- 6. According to 4 and 5, we can get below weird result: --');
console.log(null < []);         // false
console.log(null > []);         // false
console.log(null == []);        // false
console.log(null <= []);        // true
console.log(null >= []);        // true

2

İf (arr) öğesinde, arr bir nesne ise her zaman true olarak değerlendirilir (ToBoolean) çünkü JavaScript'teki tüm nesneler doğrudur . (null bir nesne değildir!)

[] == falseyinelemeli yaklaşımla değerlendirilir. İlk başta, eğer bir tarafı== ilkel ve diğeri nesne ise, ilk başta nesneyi ilkeye dönüştürür, daha sonra her iki taraf değilse her iki tarafı da Sayıya dönüştürür (her iki tarafın stringdize olması durumunda dize karşılaştırması kullanılır). Böylece karşılaştırma, [] == false-> '' == false-> 0 == 0-> gibi yinelenir true.


2

Misal:

const array = []
const boolValueOfArray = !!array // true

Olur çünkü

ToNumber(ToPrimitive([])) == ToNumber(false)  
  1. []boş bir Arraynesne → ToPrimitive([])→ "" → ToNumber("")0
  2. ToNumber(false) → 0
  3. 0 == 0 → doğru

1

Öğeleri olan bir dizi (0, false veya başka bir boş dizi olursa olsun), her zaman trueÖzet Eşitliği Karşılaştırması'nı kullanmaya karar verir ==.

1. [] == false; // true, because an empty array has nothing to be truthy about
2. [2] == false; // false because it has at least 1 item
3. [false] == false; // also false because false is still an item
4. [[]] == false; // false, empty array is still an item

Ancak Sıkı Eşitlik Karşılaştırması kullanarak ===, değişkenin içeriğini ve veri türünü değerlendirmeye çalışıyorsunuz, bu yüzden:

1. [] === false; // false, because an array (regardless of empty or not) is not strictly comparable to boolean `false`
2. [] === true; // false, same as above, cannot strictly compare [] to boolean `true`
3. [[]] === false; // true, because see #1

-1

Şu list = []anda başvurulan dizinin öğelerini kullanarak veya silerek bir JavaScript Dizisini yeni bir diziye başvurarak boşaltabilirsinizlist.length = 0 .

Kaynak: JavaScript Empty Array


-2

Yukarıdakilerin hiçbiri, knockout.js eşleme eklentisini kullanmaya çalışırken, belki de "boş bir dizi" gerçekten boş olmadığından bana yardımcı olmadı.

Ben kullanarak sona erdi: data-bind="if: arr().length"hile yaptı.

Bu, OP'nin sorusuna değil, nakavt'a özgüdür, ancak belki de benzer bir durumda buraya göz atan başka birine yardımcı olacaktır.


Bu cevap ilgili değil
fauverizm

sadece teğetsel olarak, reddedildiği gibi :)
domoarigato
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.