Пустые массивы кажутся равными 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??");





Я думаю, это связано с неявным преобразованием, управляемым оператором равенства.



может кто-нибудь объяснить, что происходит за кулисами?

287   7  

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)  
  1. [] пусто Array объект → ToPrimitive([])→""→ ToNumber("")0
  2. ToNumber(false) → 0
  3. 0 = = 0 → true

Вы можете очистить массив JavaScript, сославшись на новый массив, используя list = [] или удаление элементов текущего массива ссылок list.length = 0.

источник: JavaScript Пустой Массив

ничто из вышеперечисленного не помогло мне, когда я пытался использовать нокаут.плагин отображения js, возможно, так как" пустой массив " на самом деле не пуст.

Я в конечном итоге с помощью: data-bind="if: arr().length", который сделал свое дело.

это специфично для нокаута, а не вопрос OP, но, возможно, это поможет кому-то еще просматривать здесь в аналогичной ситуации.

Comments

    Ничего не найдено.