Подтвердить что ты не робот

Функция больше, чем массив?

Один мой друг обнаружил какое-то интересное поведение в каком-то коде Javascript, который я решил продолжить.

Сравнение

(function (x) {return x*x;}) > [1,2,3]

возвращает true в большинстве основных браузеров (Firefox, Chrome, Opera и Safari) и false в IE9. Для меня нет логического результата этого сравнения, кроме undefined, поскольку нет способа сказать, что функция больше, чем массив.

Считая это в стандарте ECMA- script, он говорит, что фактические аргументы >, когда он используется для объектов, являются результатом вызова внутренней операции ToNumber для аргументов. Некоторые эксперименты и дальнейшее чтение говорят мне, что это не то же самое, что применять преобразование типа, например (Number) arg. Читая спецификацию, мне трудно понять, что происходит здесь.

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

4b9b3361

Ответ 1

Операнды > не обязательно преобразуются в числа. абстрактный алгоритм реляционного сравнения вызывает ToPrimitive с подсказкой Number, но ToPrimitive может все еще возвращать строку (и в случае как функций, так и массивов).

Итак, вы в итоге сравниваете две строки. Результат вызова toString в объектах функций не определяется спецификацией, хотя большинство основных движков возвращают исходный код функции (или в какой-то форме, и форматирование меняется). Результатом вызова toString на массивах является то же самое, что join.

Таким образом, вероятность того, что вы в конечном итоге выполните это:

"function (x) {return x*x;}" > "1,2,3"

Так как точная форма строки для функции может варьироваться от браузера к браузеру (и отметить исследования Esailija — похоже, что IE9 сохраняет внешний (), Chrome не работает), не удивительно, что результат может отличаться.

Ответ 2

В IE < 9, .toString ing (function (x) {return x*x;}) дается

"(function (x) {return x*x;})" 

Пока в chrome это дает:

"function (x) {return x*x;}"

Если вы сравните:

"function (x) {return x*x;}" > "1,2,3" // true
"(function (x) {return x*x;})"  > "1,2,3"  // false

Это фактически то же самое, что и сравнение:

"f" > "1"
"(" > "1"

То же самое, что и сравнение:

102 > 49
40 > 49

Итак, как мы получаем из сравнения функций и массивов с простым сопоставлением чисел:)

Ответ 3

Позвольте погрузиться в спецификацию ECMA. Я включил номера разделов, чтобы вы могли ссылаться.

11.8.2 Оператор больше, чем оператор ( > )

Производство RelationalExpression: RelationalExpression > Выражение Shift оценивается следующим образом:

  • Пусть lref является результатом вычисления RelationalExpression.
  • Пусть lval - GetValue (lref).
  • Пусть rref является результатом оценки выражения Shift.
  • Пусть rval - GetValue (rref).
  • Пусть r является результатом выполнения абстрактного реляционного сравнения rval < lval с LeftFirst равным false. (видеть 11.8.5).

Важной частью этого является абстрактное реляционное сравнение. Определяется:

11.8.5 Алгоритм абстрактного реляционного сравнения

Функция toPrimitive сначала будет вызываться в объектах. Хотя это смещено, чтобы вернуть Numbers, если это возможно, строки также могут быть получены. Как только это произойдет, будет рассмотрено следующее:

а. Если py является префиксом px, верните false. (Строковое значение p является префиксом значения String q, если q может быть результат конкатенации p и некоторой другой строки r. Обратите внимание, что любой Строка является префиксом сама по себе, так как r может быть пустой строкой.)

б. Если px является префиксом py, верните true.

с. Пусть k - наименьшее неотрицательное целое число такое, что символ в позиции k внутри px отличается от символа в положении k внутри py. (Должно быть такое k, поскольку ни String не является префиксом другого.)

д. Пусть m - целое число, которое является значением единицы кода для символа в позиции k в пределах px. е. Пусть n - целое число, которое является значением единицы кода для символа в позиции k внутри py. е. Если m < n, верните true. В противном случае верните false.

Это означает, что будет проверен первый символ в строке, отличной от другой. Как было указано Esailija, функция IE toString() возвращает немного другую строку в другую, чем другие браузеры, что приводит к другому сравнению.

Это различие между браузерами кажется действительным, как указано здесь:

15.2.4.4 Object.prototype.valueOf()

Когда вызывается метод valueOf, выполняются следующие шаги:

  • Пусть O - результат вызова ToObject, передающего это значение в качестве аргумента.
  • Если O является результатом вызова конструктора Object с объектом-хостом (15.2.2.1), тогда a. Вернуть либо O, либо другое значение, например объект-хост изначально передан конструктору. Конкретные результат, который возвращается, определяется реализацией.
  • Возврат O.

Ответ 4

Оба IE и другие браузеры будут использовать одинаковое сравнение строк для обоих объектов. Причиной разницы является то, что IE преобразует функцию в строку с буквами:

(function (x) {return x*x;})

Другие браузеры (тестирование в Firefox) выведут свою собственную скомпилированную интерпретацию функции:

function (x) {
    return x * x;
}

Поскольку первый символ представления функции IE (, который выше, чем 1, он вернет false. Поскольку f ниже, чем 1, другие браузеры вернут true.