Пустые массивы имеют значение true, но они также равны false.
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??");
Я предполагаю, что это связано с неявным преобразованием, используемым оператором равенства.
Кто-нибудь может объяснить, что происходит за кулисами?
javascript
Patonza
источник
источник
arr == true
это не соответствует действительности ;-)===
. Тогда, если вы хотите проверить пустоту массива, используйтеarr === []
arr === []
, так как это ВСЕГДА будет возвращать false, поскольку правая сторона создает новый массив, а переменная слева не может ссылаться на то, что вы только что создали. Проверка пустоты должна быть сделана, глядя вверхarr.length === 0
.Ответы:
Здесь вы тестируете разные вещи.
if (arr)
Вызванный объект (Array является экземпляром Object в JS) проверит наличие объекта и вернет true / false.При вызове
if (arr == false)
вы сравниваете значения этого объекта иfalse
значения примитива . Внутреннеarr.toString()
вызывается, что возвращает пустую строку""
.Это вызвано тем, что вызывается
toString
при возврате ArrayArray.join()
, а пустая строка является одним из ложных значений в JavaScript.источник
Boolean([])
возвращаетсяtrue
?Что касается линии:
Может быть, это поможет:
Я считаю, что происходит то, что булево значение
false
приводится0
для сравнения с объектом (левая часть). Объект приводится к строке (пустой строке). Затем пустая строка также приводится к числу, а именно к нулю. И вот окончательное сравнение0
==0
, чтоtrue
.Изменить: см. Этот раздел спецификации для деталей о том, как именно это работает.
Вот что происходит, начиная с правила № 1:
Следующее правило, которое применяется, это # 19:
Результатом
ToNumber(false)
является0
, таким образом , мы теперь имеем:Опять же, правило № 1 говорит нам перейти к шагу № 14, но следующий действительный шаг - № 21:
Результатом
ToPrimitive([])
является пустая строка, поэтому мы теперь имеем:Опять же, правило № 1 говорит нам перейти к шагу № 14, но следующий действительный шаг - № 17:
Результатом
ToNumber("")
является то0
, что оставляет нас с:Теперь оба значения имеют одинаковый тип, поэтому шаги продолжаются с # 1 до # 7, что говорит:
Итак, мы вернемся
true
.Вкратце:
источник
[] == 0
же верно. Я понимаю, как это происходит, основываясь на вашем объяснении спецификации, но это кажется странным поведением языка с логической точки зрения.Чтобы дополнить ответ Уэйна и попытаться объяснить, почему
ToPrimitive([])
возвращается""
, стоит рассмотреть два возможных типа ответов на вопрос «почему». Первый тип ответа: «потому что в спецификации сказано, что именно так будет вести себя JavaScript». В спецификации ES5, раздел 9.1 , который описывает результат ToPrimitive в качестве значения по умолчанию для объекта:Раздел 8.12.8 описывает
[[DefaultValue]]
метод. Этот метод принимает «подсказку» в качестве аргумента, и подсказка может быть либо String, либо Number. Чтобы упростить этот вопрос, отказавшись от некоторых деталей, если подсказкой является строка, то[[DefaultValue]]
возвращается значение,toString()
если оно существует, и возвращается примитивное значение, а в противном случае возвращается значениеvalueOf()
. Если подсказка является Number, приоритетыtoString()
иvalueOf()
меняются местами, так чтоvalueOf()
сначала вызывается и возвращается его значение, если это примитив. Таким образом,[[DefaultValue]]
возвращает ли результат результатtoString()
илиvalueOf()
зависит от указанного PreferredType для объекта и возвращают ли эти функции примитивные значения.Метод
valueOf()
Object по умолчанию просто возвращает сам объект, а это означает, что если класс не переопределяет метод по умолчанию, онvalueOf()
просто возвращает сам объект. Это дело дляArray
.[].valueOf()
возвращает сам объект[]
. ПосколькуArray
объект не является примитивом,[[DefaultValue]]
подсказка не имеет значения: возвращаемое значение для массива будет значениемtoString()
.Процитируем JavaScript Дэвида Фланагана : «Полное руководство» , которое, кстати, является превосходной книгой, которая должна стать первым местом для всех, чтобы получить ответы на следующие вопросы:
Второй тип ответа на вопрос «почему», отличный от «потому что спецификация говорит», дает некоторое объяснение того, почему поведение имеет смысл с точки зрения дизайна. По этому вопросу я могу только строить догадки. Во-первых, как преобразовать массив в число? Единственная разумная возможность, о которой я могу подумать, это преобразовать пустой массив в 0, а любой непустой массив в 1. Но, как показал ответ Уэйна, пустой массив будет преобразован в 0 для многих типов сравнений в любом случае. Помимо этого, трудно придумать разумное примитивное возвращаемое значение для Array.valueOf (). Таким образом, можно утверждать, что имеет больше смысла иметь
Array.valueOf()
значение по умолчанию и возвращать сам массив, что приводитtoString()
к результату, используемому ToPrimitive. Просто имеет смысл преобразовать массив в строку, а не в число.Более того, как подсказывает цитата Фланагана, это дизайнерское решение действительно допускает определенные типы полезного поведения. Например:
Такое поведение позволяет сравнивать одноэлементный массив с числами и получать ожидаемый результат.
источник
источник
В if (arr) он всегда оценивается (ToBoolean) как true, если arr является объектом, потому что все объекты в JavaScript верны . (ноль не объект!)
[] == false
оценивается в итеративном подходе. Сначала, если одна сторона==
является примитивной, а другая - объектом, сначала она преобразует объект в примитив, а затем преобразует обе стороны в число, если не обе стороныstring
(сравнение строк используется, если обе стороны являются строками). Таким образом, сравнение повторяется как,[] == false
->'' == false
->0 == 0
->true
.источник
Пример:
Это происходит потому что
[]
пустойArray
объект →ToPrimitive([])
→ "" →ToNumber("")
→0
ToNumber(false)
→ 0источник
Массив с элементами (независимо от 0, false или другого пустого массива) всегда разрешается с
true
использованием абстрактного сравнения равенства==
.Но, используя Сравнение строгого равенства
===
, вы пытаетесь оценить содержимое переменной, а также ее тип данных, поэтому:источник
Вы можете очистить массив JavaScript, ссылаясь на него в новом массиве, используя
list = []
или удаляя элементы текущего массива, на который ссылаютсяlist.length = 0
.Источник: JavaScript Пустой массив
источник
Ничто из вышеперечисленного не помогло мне при попытке использовать плагин отображения knockout.js, возможно, так как «пустой массив» на самом деле не пустой.
Я закончил тем, что использовал:
data-bind="if: arr().length"
который добился цели.Это относится только к нокауту, а не к вопросу ОП, но, возможно, это поможет кому-то еще, находящемуся здесь в аналогичной ситуации.
источник