Пустые массивы кажутся равными true и false одновременно
пустые массивы истинны, но они также равны 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??");Я думаю, это связано с неявным преобразованием, управляемым оператором равенства.
может кто-нибудь объяснить, что происходит за кулисами?
7 ответов:
вы тестируете разные вещи здесь.
if (arr)вызывается объект (массив является экземпляром объекта в JS) будет проверять, если объект присутствует, и возвращает true/false.когда вы называете
if (arr == false)сравнить значения этого объекта и примитивныеfalseзначение. Внутренне,arr.toString()вызывается, который возвращает пустую строку"".это так
toStringвызывается массив возвращаетArray.join(), и пустая строка является одной из ложных значения в JavaScript.
о строку:
if (arr == false) console.log("It's false!");может это поможет:
console.log(0 == false) // true console.log([] == 0) // true console.log([] == "") // trueя считаю, что происходит то, что булево
falseприводится к0для сравнения с объектом (левая сторона). Объект приводится к строке (пустой строке). Затем пустая строка также преобразуется в число, а именно в ноль. И поэтому последнее сравнение0==0, которая составляетtrue.Edit: посмотреть этот раздел спецификации подробнее о том, как именно это работает.
вот что происходит, начиная с правила №1:
1. Если тип (x) отличается от типа(y), перейдите к шагу 14.
следующее правило, которое применяется #19:
19. Если тип (y) является логическим, возвращает результат сравнения x == Нумерации(г).
результат
ToNumber(false)и0, так что теперь мы есть:[] == 0опять же, правило №1 говорит нам перейти к шагу №14, но следующий шаг, который действительно применяется, - это #21:
21. Если Type(x) - Объект, А Type(y) - строка или число, верните значение результат сравнения ToPrimitive (x)== y.
результат
ToPrimitive([])это пустая строка, так что теперь у нас есть:"" == 0опять же, правило №1 говорит нам перейти к шагу №14, но следующий шаг, который действительно применяется #17:
17. Если тип (x) является строкой, а тип(y) - числом, верните результат сравнение ToNumber (x)== y.
результат
ToNumber("")и0, что оставляет нас с:0 == 0теперь оба значения имеют один и тот же тип, поэтому шаги продолжаются от #1 до #7, в котором говорится:
7. Если x-это то же числовое значение, что и y, верните true.
Итак, мы возвращаемся
true.вкратце:
ToNumber(ToPrimitive([])) == ToNumber(false)
в if (arr) он всегда оценивается (ToBoolean) в true, если arr является объектом, потому что все объекты в JavaScript являются правдивыми. (null-это не объект!)
[] == falseоценивается в итерационном подходе. Во-первых, если одна сторона==примитивен, а другой-объект, он сначала преобразует объект в примитив, а затем преобразует обе стороны в число, если обе стороны неstring(сравнения строк используется, если обе стороны являются строками). Так что сравнение повторяется как,[] == false->'' == false->0 == 0->true.
дополнить Вейн ответ и попытаться объяснить, почему
ToPrimitive([])возвращает"", стоит рассмотреть два возможных типа ответов на вопрос "почему". Первый тип ответа: "потому что спецификация говорит, что именно так будет вести себя JavaScript.- В спецификации ES5, 9.1, который описывает результат ToPrimitive как значение по умолчанию для объекта:значение по умолчанию объекта извлекается путем вызова [[DefaultValue]] внутренний метод объекта, передающий необязательную подсказку PreferredType.
8.12.8 описание
[[DefaultValue]]метод. Этот метод принимает "подсказку" в качестве аргумента, и подсказка может быть либо строкой, либо числом. Чтобы упростить дело, обойдясь без некоторых деталей, если подсказка является строкой, то[[DefaultValue]]возвращает значениеtoString()если он существует и возвращает примитивное значение, а в противном случае возвращает значениеvalueOf(). Если подсказка есть Число, приоритетыtoString()иvalueOf()перевернуты так, чтоvalueOf()вызывается первым и его значение возвращается, если это примитив. Таким образом, будь[[DefaultValue]]возвращает результатtoString()илиvalueOf()зависит от указанного PreferredType для объекта и возвращают ли эти функции примитивные значения.по умолчанию
valueOf()метод объекта просто возвращает сам объект, что означает, что если класс не переопределяет метод по умолчанию,valueOf()просто возвращает объект себя. Это относится кArray.[].valueOf()возвращает объект[]сам по себе. С тех пор какArrayобъект не является примитивом, то[[DefaultValue]]намек не имеет значения: возвращаемое значение для массива будет значениеtoString().цитата Дэвид Флэнаган JavaScript: Окончательное Руководство, которая, кстати, является превосходной книгой, которая должна быть первым местом каждого, чтобы получить ответы на эти типы вопросов:
в подробности этого преобразования объекта в число объясняют, почему пустой массив преобразуется в число 0 и почему массив с одним элементом также может преобразовываться в число. Массивы наследуют метод valueOf() по умолчанию, который возвращает объект, а не примитивное значение, поэтому преобразование массива в число зависит от метода toString (). Пустые массивы преобразуются в пустую строку. И пустая строка преобразуется в число 0. Массив с одним элементом преобразуется в ту же строку, что и один элемент делает. Если массив содержит одно число, то это число преобразуется в строку, а затем обратно в число.
второй тип ответа на вопрос" почему", кроме" потому что спецификация говорит", дает некоторое объяснение того, почему поведение имеет смысл с точки зрения дизайна. На этот счет я могу только гадать. Во-первых, как можно преобразовать массив в число? Единственная разумная возможность, о которой я могу думать, - это преобразовать пустой массив в 0 и любой непустой массив 1. Но, как показал ответ Уэйна, пустой массив будет преобразован в 0 для многих типов сравнений в любом случае. Помимо этого, трудно придумать разумное примитивное возвращаемое значение для массива.valueOf (). Так что можно утверждать, что это просто имеет больше смысла иметь
Array.valueOf()быть по умолчанию и вернуть сам массив, ведущийtoString()быть результатом, используемым ToPrimitive. Это просто имеет больше смысла, чтобы преобразовать массив в строку, а не число.более того, как намекает цитата Фланагана, это проектное решение позволяет определенные типы полезного поведения. Например:
var a = [17], b = 17, c=1; console.log(a==b); // <= true console.log(a==c); // <= falseтакое поведение позволяет сравнить одноэлементный массив с числами и получают ожидаемый результат.
пример:
const array = [] const boolValueOfArray = !!array // trueэто происходит потому, что
ToNumber(ToPrimitive([])) == ToNumber(false)
[]пустоArrayобъект →ToPrimitive([])→""→ToNumber("")→0ToNumber(false)→ 0- 0 = = 0 → true
Вы можете очистить массив JavaScript, сославшись на новый массив, используя
list = []или удаление элементов текущего массива ссылокlist.length = 0.источник: JavaScript Пустой Массив
ничто из вышеперечисленного не помогло мне, когда я пытался использовать нокаут.плагин отображения js, возможно, так как" пустой массив " на самом деле не пуст.
Я в конечном итоге с помощью:
data-bind="if: arr().length", который сделал свое дело.это специфично для нокаута, а не вопрос OP, но, возможно, это поможет кому-то еще просматривать здесь в аналогичной ситуации.
Comments