2012-02-21 3 views
43

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

Сравнение

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

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

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

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

+5

конечно функция больше, чем массив, он может производить heckuvalotta массивы ;-) –

+5

Вы не читали достаточно спецификации пока. Оператор '>' также может сравнивать строки. – Pointy

+1

@ Отлично, действительно. 'f' больше, чем '1' (есть ли скрытый смысл?). –

ответ

54

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

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

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

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

Поскольку точная форма строки для функции могут варьироваться в зависимости от браузера к браузеру (и заметьте Esailija's investigations   — выглядит как IE9 держит внешний (), Chrome не делает), не удивительно, что результат может отличаться.

+0

Я думаю, что массивы превращаются в строки через '.join()' ... – Pointy

+1

Может также быть 'function() {...' и '1,2,3' (я думаю, это то, что Chrome сделает из них). –

+0

@Pointy: Да, и 'toString' на функциях возвращает источник (обычно, не гарантируется). Я думал о Object.prototype.toString.call (func) '- doh! –

60

В IE ИНГ (function (x) {return x*x;}) дает

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

В то время как в хроме это дает:

"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 

Так вот, как мы получаем от функции и массива по сравнению с простым сравнением чисел :)

+0

Интересный анализ очевидной несовместимости, допускаемый спецификацией. – Abel

+0

Не в моем IE9: http://i.imgur.com/1zhLa.png. Я вижу только parens в режиме IE8/IE7. Ваш браузер находится в режиме совместимости? – gilly3

+0

@ gilly3 true У меня был режим IE7, OP должен был иметь ту же ошибку, что и true для сравнения (так же, как и современные браузеры) – Esailija

2

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

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

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

function (x) { 
    return x * x; 
} 

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

5

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

11.8.2 Большой-чем (>)

Производственный ВыраженияОтношения: ВыражениеОтношения> ВыражениеСдвига вычисляется следующим образом:

  1. Пусть LRef быть результатом оценки ВыраженияОтношения ,
  2. Позвольте lval быть GetValue (lref).
  3. Пусть rref будет результатом оценки ShiftExpression.
  4. Пусть rval будет GetValue (rref).
  5. Пусть r является результатом выполнения абстрактное реляционное сравнение rval < lval with LeftFirst равно false. (см. 11.8.5).

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

11.8.5 абстрактного Relational алгоритм сравнение

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

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

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

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

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

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

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

15.2.4.4 Object.prototype.valueOf()

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^