Есть ли у JavaScript неопределенное поведение?

Есть ли у JavaScript неопределенное поведение (похожее на C) или оно полностью определено спецификацией и детерминировано?

Обратите внимание, что я отбрасываю ошибки реализации и расхождения в спецификациях. Я также отбрасываю такие вещи, как Math.random() и Date.now().

Существует ли фрагмент кода JavaScript, поведение которого не полностью определяется спецификациями JavaScript и поэтому имеет «неопределенное поведение»?


person Randomblue    schedule 13.02.2013    source источник
comment
Да, читайте quirksmode.   -  person gdoron is supporting Monica    schedule 14.02.2013
comment
Есть много вещей, которые в IE ведут себя X, а в других ведут себя, например, Y, некоторые из-за того, что IE ужасен, а некоторые из-за того, что спецификация недостаточно ясна.   -  person gdoron is supporting Monica    schedule 14.02.2013
comment
Я отбрасываю ошибки реализации и расхождения в спецификациях   -  person Randomblue    schedule 14.02.2013
comment
@gdoron - это больше DOM, чем язык. Я уверен, что могут быть языковые различия, но они незначительны.   -  person iandotkelly    schedule 14.02.2013


Ответы (5)


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

15.1 Глобальный объект

Значения внутренних свойств [[Prototype]] и [[Class]] глобального объекта зависят от реализации.

15.1.2.2 parseInt (строка, основание)

[Если значащих цифр слишком много] mathInt может быть зависимой от реализации аппроксимацией математического целочисленного значения, представленного Z в системе счисления-R.

15.3.4.2 Function.prototype.toString

Возвращается зависимое от реализации представление функции.

Почти все алгоритмы анализа/строки даты зависят от реализации, включая toLocaleString, toString, parse и конструктор Date.

15.4.4.11 Array.prototype.sort (comparefn) — вероятно, лучший пример:

Если comparefn не является неопределенным и не является последовательной функцией сравнения для элементов этого массива, поведение sort определяется реализацией.

[…] Если proto не равно null и существует целое число j такое, что выполняются все приведенные ниже условия, то поведение sort определяется реализацией:

  • obj разреженный (15.4)
  • 0 ≤ j ‹ длина

Поведение sort также определяется реализацией, если obj является разреженным и выполняется любое из следующих условий:

  • Внутреннее свойство [[Extensible]] объекта obj равно false.
  • Любое свойство индекса массива obj, имя которого является неотрицательным целым числом, меньшим, чем len, является свойством данных, атрибут [[Configurable]] которого имеет значение false.

Поведение sort также определяется реализацией, если любое свойство индекса массива obj, имя которого является неотрицательным целым числом, меньшим, чем len, является свойством доступа или является свойством данных, атрибут [[Writable]] которого имеет значение false.

И наиболее заметно:

Выполните зависящую от реализации последовательность вызовов […]

15.5.4.9 String.prototype.localeCompare (это)

Две строки сравниваются определяемым реализацией образом.

15.5.4.11 String.prototype.replace [В символах замены, если число больше, чем количество групп], результат определяется реализацией.

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

person Bergi    schedule 13.02.2013
comment
Конечно, зависимость от реализации в JavaScript совсем не похожа на неопределенное поведение в C. - person supercat; 16.02.2016
comment
@supercat: Конечно, это не похоже на это или это, но реализация не запрещает сбой функции (исключение во время выполнения), всю страницу, весь браузер или всю систему. - person Bergi; 16.02.2016
comment
В первом предложении вопроса спрашивается, имеет ли он Undefined Behavior, аналогичный C. Хотя ничто в стандарте не запрещает браузерам позволять удаленному коду вызывать сбой локальной машины, также нет ничего, что могло бы предположить, что производители браузеров имеют право предполагать, что этот код никогда не будет получать входные данные, которые заставят его делать определенные вещи. - person supercat; 16.02.2016
comment
@supercat: я сосредоточился на полностью ли он определен спецификацией и детерминирован?. Считаете ли вы, что мне следует добавить к ответу уведомление о том, что это поведение, определяемое реализацией, не похоже на неопределенное поведение в C? - person Bergi; 16.02.2016
comment
Я думаю, что это различие стоит сделать. Лично я считаю прискорбным, что авторы стандарта C не указали, что, хотя реализации разрешено делать все, что ей заблагорассудится в различных случаях, в случаях, когда платформа может дешево предложить гарантии того, что произойдет, реализации должны постарайтесь сделать такие гарантии доступными для программиста. - person supercat; 16.02.2016

Я нашел несколько примеров, цитирующих спецификации языка ECMAScript (выделено мной ):

8.5 Тип номера

В некоторых реализациях внешний код может обнаруживать разницу между различными значениями Not-a-Number, но такое поведение зависит от реализации; для кода ECMAScript все значения NaN неотличимы друг от друга.

15.7.4.5 Number.prototype.toFixed (fractionDigits)

Если метод toFixed вызывается с более чем одним аргументом, то поведение не определено (см. пункт 15).

15.7.4.6 Number.prototype.toExponential (fractionDigits)

Если метод toExponential вызывается с более чем одним аргументом, то поведение не определено (см. пункт 15).

15.7.4.7 Number.prototype.toPrecision (точность)

Если метод toPrecision вызывается с более чем одним аргументом, то поведение не определено (см. пункт 15).

15.9.4.3 Дата.UTC (год, месяц [, дата [ , часы [, минуты [, секунды [, мс] ] ] ] ] )

Когда функция UTC вызывается с менее чем двумя аргументами, поведение зависит от реализации.

person Tomasz Nurkiewicz    schedule 13.02.2013
comment
Я думаю, что первый пример недействителен, так как для кода ECMAScript все значения NaN неотличимы друг от друга. Я уверен, что почти на каждом языке внешний код может обнаруживать различия в реализации, не охваченные спецификацией языка. - person Bergi; 14.02.2013

я нашел

Array.sort(compareFunction);

в случае, когда compareFunction ведет себя неправильно (т. е. возвращает согласованные результаты для одних и тех же входных данных).

Из спецификации:

Если comparefn не является неопределенным и не является последовательной функцией сравнения элементов этого массива (см. ниже), поведение sort определяется реализацией.

person hvgotcodes    schedule 13.02.2013

Любая программа, вызывающая Undefined Behavior в стиле C в ответ на любой ввод, будет непригодна для использования с ненадежным вводом. Хотя существует много ситуаций, когда спецификация ECMAScript не определяет точное поведение, но она не дает реализациям той же свободы отрицать законы времени и причинно-следственных связей, которые компиляторы C имеют с Undefined Behavior.

person supercat    schedule 16.02.2016

Во-первых, стандарт ECMA-262, определяющий язык, неофициально известный как JavaScript, использует термины «зависящий от реализации» и «определяемый реализацией» без определения того, что эти термины означают. По сути, все эти поведения не определены; никаких требований о том, что должно произойти, не дается. Реализация, которая дает сбой или ведет себя непредсказуемо, соответствует требованиям; безусловно, так, если он документирует это поведение: этот сбой или неустойчивое поведение определяется реализацией. Напротив, стандарт ISO C формально определяет такие термины, как «неопределенное поведение», «поведение, определяемое реализацией» и «неопределенное поведение». Эти слова на самом деле что-то означают, где бы они ни встречались.

Во-вторых, стандарт ECMA-262 ничего не говорит об ограничениях реализации. Это не значит, что их нет. Например, может ли программа Javascript в данной конкретной реализации иметь какую-либо глубину рекурсии? Любое количество аргументов функции? Любая глубина лексического охвата? Может ли он выделить любое количество объектов? Конечно нет, верно? Слово «ограничение» даже нигде не встречается в ECMA-262 2018, кроме как в имени аргумента функции. В документе, например, не говорится, что соответствующая реализация ECMAScript должна разрешать функции с 64 параметрами. Следовательно, приходит к выводу, что реализации должны поддерживать функции с любым количеством переданных им параметров. Если мы создадим функцию с десятью миллионами параметров, а реализация выйдет из строя, она не соответствует требованиям; нигде ECMA-262 не утверждает, что такой сбой разрешен. Если компилятор C дает сбой из-за десяти миллионов параметров в функции, мы можем прямо указать на это как на проблему в программе: он превышает минимальный предел реализации, задокументированный в стандарте, и, таким образом, не соответствует строгому соответствию (формальный термин). Это случай неопределенного поведения: речь идет о непереносимой программе, для которой стандарт не предъявляет никаких требований (не требует реализации для обработки такого количества аргументов функции).

person Kaz    schedule 31.05.2019
comment
Я не думаю, что Стандарт определяет какую-либо ситуацию, когда соответствующая реализация должна была бы что-либо делать без сбоя, не так ли? Я не думаю, что неспособность Стандарта запретить сбой реализации, когда код выполняет какое-либо действие, предназначена для того, чтобы подразумевать какую-либо специальную лицензию на сбой в таких случаях. - person supercat; 31.05.2019