Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Почему оператор ++ генерирует искючение, а не NaN в случае со строкой? (https://javascript.ru/forum/misc/29869-pochemu-operator-generiruet-iskyuchenie-ne-nan-v-sluchae-so-strokojj.html)

dump 14.07.2012 16:44

Почему оператор ++ генерирует искючение, а не NaN в случае со строкой?
 
Почему код:

alert('d'++);

генерирует ошибку, а не выводит значение NaN?

9xakep 14.07.2012 16:47

dump,
потому что не совмещение типов вроде.
Другие знаки приводят операнды к одному типу:
alert('a' + 1)
alert('a' * 1)
alert('a' - 1)
alert('a' / 1)

oneguy 14.07.2012 18:25

Цитата:

Сообщение от 9xakep
dump,
потому что не совмещение типов вроде.
Другие знаки приводят операнды к одному типу:

Ответ неверный. Операнд оператора ++ должен быть такой, который может стоять в левой части присваивания, то есть либо переменной, либо свойством объекта. У вас там строка, поэтому генерируется SyntaxError.
Этот код работает:
var a='d';
alert(a++); //NaN

bes 15.07.2012 17:57

Цитата:

Сообщение от oneguy
Ответ неверный. Операнд оператора ++ должен быть такой, который может стоять в левой части присваивания, то есть либо переменной, либо свойством объекта. У вас там строка, поэтому генерируется SyntaxError.

Можно пояснить, как получить такой вывод из спецификации


http://es5.javascript.ru/x11.html#x11.3.1
Цитата:

11.3.1 Постфиксный оператор инкремента # Ⓣ Ⓡ Ⓖ
Для вычисления PostfixExpression : LeftHandSideExpression [no LineTerminator here] ++ выполняются следующие шаги:

Пусть lhs будет результатом вычисления LeftHandSideExpression Левостороннее выражение.
Сгенерировать исключение SyntaxError, если все следующие условия являются истинными:
Type(lhs) равно Reference равно true
IsStrictReference(lhs) равно true
Type(GetBase(lhs)) равно Environment Record
GetReferencedName(lhs) равно либо "eval", либо "arguments"
Пусть oldValue Старое значение будет ToNumber(GetValue(lhs)).
Пусть newValue Новое значение будет результатом прибавления значения 1 к значению oldValue, с применением таких же правил, что и для оператора + (см. пункт. 11.6.3).
Вызвать PutValue(lhs, newValue).
Вернуть oldValue.

oneguy 15.07.2012 21:40

Цитата:

Сообщение от bes
Можно пояснить, как получить такой вывод из спецификации

При вычислении LeftHandSideExpression [no LineTerminator here] ++ одним из шагом вычисляется PutValue(lhs, newValue). Операция PutValue кидает ReferenceError, если тип первого операнда не Reference.
Дальше читаем: http://es5.javascript.ru/x16.html#x16
Цитата:

Реализация должна рассматривать все случаи следующих ошибок как раннюю ошибку:

...

Попытки вызвать PutValue для значения, по которому можно заранее определить, что оно не является Reference (например, при выполнении инструкции присваивания 3=4).

В данном случае в выражении 'd'++ PutValue должен вызываться для значения выражения 'd', а строковый литерал никогда не возвращает Reference, поэтому интерпретатор при этом сообщает о ранней ошибке.

bes 15.07.2012 22:11

Спасибо за пояснение, то есть ошибка возникает не из этих пунктов
Цитата:

Сгенерировать исключение SyntaxError, если все следующие условия являются истинными:
Type(lhs) равно Reference равно true
IsStrictReference(lhs) равно true
Type(GetBase(lhs)) равно Environment Record
GetReferencedName(lhs) равно либо "eval", либо "arguments"
а как результат предпоследнего шага
Цитата:

Вызвать PutValue(lhs, newValue).

Цитата:

Сообщение от oneguy
а строковый литерал никогда не возвращает Reference

Почитав про reference http://es5.javascript.ru/x8.html#x8.7 не пойму, что и когда является reference (это нечто предопределённое или нет)
(исходя из приведённых пояснений, если бы строковый литерал был ссылкой, тогда ошибка возникла бы ещё на пункте
Цитата:

Type(lhs) равно Reference равно true
)

oneguy 15.07.2012 23:06

Цитата:

Сообщение от bes
Почитав про reference http://es5.javascript.ru/x8.html#x8.7 не пойму, что и когда является reference (это нечто предопределённое или нет)

Reference - это тип данных, который используется для вычисления выражений. Например, как объяснить вычисление выражения delete object.method ? Что нужно взять от object.method и передать оператору delete?
Цитата:

(исходя из приведённых пояснений, если бы строковый литерал был ссылкой, тогда ошибка возникла бы ещё на пункте
Цитата:
Type(lhs) равно Reference равно true
)
Не совсем понял. Объясните, пожалуйста, поконкретнее, что значит "если бы строковый литерал был ссылкой".

bes 15.07.2012 23:28

Цитата:

Сообщение от oneguy
Не совсем понял. Объясните, пожалуйста, поконкретнее, что значит "если бы строковый литерал был ссылкой".

Цитата:

Сгенерировать исключение SyntaxError, если все следующие условия являются истинными:
Type(lhs) равно Reference равно true
если тип операнда слева - ссылочный, генерировать исключение (так как литерал не ссылочного типа, поэтому не генерировать)

Цитата:

Сообщение от oneguy
Reference - это тип данных, который используется для вычисления выражений. Например, как объяснить вычисление выражения delete object.method ? Что нужно взять от object.method и передать оператору delete?

передаётся ссылка на метод, как я понимаю
хотелось бы понять, как по спецификации определить, что ссылочного типа, что нет (где-то это должно быть в спецификации обозначено, а в http://es5.javascript.ru/x8.html#x8.7 не совсем понятно об этом написано)

oneguy 16.07.2012 02:09

Цитата:

Сообщение от bes (Сообщение 189142)
если тип операнда слева - ссылочный, генерировать исключение

Не так. В спецификации написано, что генерировать исключение, если выполняются все 4 условия одновременно:

Type(lhs) равно Reference равно true
IsStrictReference(lhs) равно true
Type(GetBase(lhs)) равно Environment Record
GetReferencedName(lhs) равно либо "eval", либо "arguments"

Цитата:

хотелось бы понять, как по спецификации определить, что ссылочного типа, что нет (где-то это должно быть в спецификации обозначено, а в http://es5.javascript.ru/x8.html#x8.7 не совсем понятно об этом написано)
Не понял вопрос. Объясните поподробнее, пожалуйста, что определить, как и при каких условиях.

bes 16.07.2012 09:57

Цитата:

Сообщение от oneguy
Не так. В спецификации написано, что генерировать исключение, если выполняются все 4 условия одновременно:

Да, здесь я блажанул

Цитата:

Сообщение от oneguy
Не понял вопрос. Объясните поподробнее, пожалуйста, что определить, как и при каких условиях.

Вопрос в том как определять, какие типы можно отнести к типу Reference, а какие нет.


Алгоритм выполняется последовательно, поэтому пытаемся разобрать фразу Type(lhs) равно Reference равно true:

Type(lhs)
Цитата:

В тексте данной спецификации выражение "Type(x)" используется в качестве сокращения для фразы "тип, к которому относится x", где "тип" означает языковой тип и тип спецификации, описываемые в данной главе.
то есть определяется тип левостороннего выражения
далее этот тип сравнивается с типом Reference

собственно о Reference http://es5.javascript.ru/x8.html#x8.7
Цитата:

8.7 Тип спецификации Reference # Ⓣ
Тип Reference Cсылка используется, чтобы объяснить поведение операторов delete и typeof и операторов присваивания. Например, можно сказать, что "левосторонний операнд присваивания создаёт ссылку". Поведение операторов присваивания можно также объяснить и анализом синтаксической формы левостороннего оператора. Но здесь есть одна сложность: вызовы функции могут возвращать ссылки. Правда, эта возможность применима только к объектам среды: возврат ссылки не предусмотрен ни для функций ECMAScript, определяемых данной спецификацией, ни для функций, определяемых пользователем. (Еще один довод против синтаксического анализа заключается в том, что это было бы долго и неудобно, и затрагивало бы многие части спецификации.)

Reference является предвычисленной resolved привязкой имени. Ссылка состоит из трех компонентов: значения базы base value, имени по ссылке referenced name, и флага строгой ссылки strict reference с булевым значением. Значение базы – это undefined, Object, Boolean, String, Number, или запись окружения (10.2.1). Если значение базы – undefined, это означает, что значение по ссылке не удалось вычислить. Имя по ссылке – это строка.

Для доступа к компонентам ссылок в данной спецификации используются следующие абстрактные операции:

GetBase(V) Получить базу(V). Возвращает компонент со значением базы ссылки V.
GetReferencedName(V) Получить имя по ссылке(V). Возвращает компонент имени по ссылке для ссылки V.
IsStrictReference(V) Является строгой ссылкой(V). Возвращает компонент строгой ссылки для ссылки V.
HasPrimitiveBase(V) Имеет примитивную базу(V). Возвращает true, если значение базы – Boolean, String или Number.
IsPropertyReference(V) Является ссылкой на свойство(V). Возвращает true, если либо значение базы является объектом, либо HasPrimitiveBase(V) – true; в противном случае возвращает false.
IsUnresolvableReference(V) Является неразрешимой ссылкой(V). Возвращает true, если значение базы – undefined, в противном случае возвращает false.

/////Далее описывается алгоритм работы getValue и putValue.
На какой основе понять, что полученный тип Type(lhs) равен или не равен типу Reference, собственно из того, что здесь приведено у меня пока не получается сделать такой вывод.

bes 16.07.2012 10:06

Ещё про типы http://es5.javascript.ru/x8.html#x8

Цитата:

8 Типы # Ⓣ
Алгоритмы, рассматриваемые в данной спецификации, манипулируют значениями, у каждого из которых есть тип, к которому он относится. В данной главе описаны все возможные типы значений. Они делятся на две категории: языковые типы language types и типы спецификации specification types.

Языковые типы соответствуют значениям, которыми непосредственно манипулирует создатель кода на языке ECMAScript. К типам спецификации относятся: Undefined, Null, Boolean, String, Number и Object.

Типы спецификации соответствуют мета-значениям, используемым в алгоритмах для описания семантики конструкций языка ECMAScript и языковых типов ECMAScript. К ним относятся типы Reference, List, Completion, Property Descriptor, Property Identifier, Lexical Environment и Environment Record. Значения типов спецификации представляют собой артефакты спецификации, которые вовсе не обязательно соответствуют каким-либо конкретным сущностям в реализации ECMAScript. Они могут использоваться для описания промежуточных результатов вычисления выражения ECMAScript, при этом такие значения не могут храниться как свойства объектов или значения переменных языка ECMAScript.

В тексте данной спецификации выражение "Type(x)" используется в качестве сокращения для фразы "тип, к которому относится x", где "тип" означает языковой тип и тип спецификации, описываемые в данной главе.
Как это и приведённое выше правильно увязать между собой

bes 16.07.2012 17:31

Знатоки спецификации, ответьте, пожалуйста, на этот (может быть нубский) вопрос.

oneguy 16.07.2012 18:37

Все типы делятся на языковые типы и типы спецификации. Тип Reference является одним из типов спецификации. Любое выражение возвращает значение либо одного из языковых типов, либо ссылку.
Интерпретатор всегда знает, какого типа используемое значение.
Операторы . и [] всегда возвращают ссылку, оператор вызова функции может возвращать значение как языкового типа, так и Reference (для встроенных и юзерских объектов всегда языкового типа), все остальные операторы - только значение языкового типа. Идентификатор всегда возвращает ссылку, все остальные примитивные выражение - всегда значение языкового типа.
Правда, в ECMAScript 5.1 есть серьёзная ошибка, связанная с возможностью функций среды возвращать ссылку. Дело в том, что любую функцию можно использовать в качестве геттера или сеттера свойства объекта. Получается, что getValue можут возвращать ссылку, и putValue может принимать ссылку, что приводит к многочисленным недоразумениям.
Интерпретатор может зараннее определить, возвращает ли выражение ссылку или языковое значение, кроме одного случая: выражение является вызовом функции, завёрнутым в произвольное количество скобок (возможно, 0).
Примеры:
alert(1);
'd'++; //SyntaxError: invalid increment operand - бросает зараннее, не выполняя alert

alert(1);
String.fromCharCode(100)++; //ReferenceError: invalid assignment left-hand side - бросает во время выполения, после алерта.

Во втором случае интерпретатор не может зараннее определить, возвратит ли вызов функции языковое значение или ссылку.

Ред. Первый пример работает так, как написано только в Фаерфоксе, и это правильное поведение с точки зрения спецификации. Остальные браузеры сначала выполняют alert, а потом бросают ReferenceError.

devote 16.07.2012 18:58

Цитата:

Сообщение от oneguy
бросает зараннее, не выполняя alert

в опере выполняет алерт, а потом бросает исключение.

B~Vladi 16.07.2012 19:03

Цитата:

Сообщение от devote
в опере выполняет алерт, а потом бросает исключение.

:lol: Это пздц.

devote 16.07.2012 19:09

Цитата:

Сообщение от B~Vladi
Это пздц.

от чего же?

oneguy 16.07.2012 19:23

Цитата:

Сообщение от devote
в опере выполняет алерт, а потом бросает исключение.

Спасибо за замечание. Действительно, так ведёт себя не только Опера, но и Хром, Сафари, ИЕ! Похоже, только Фаерфокс выполняет пункты спецификации:
Цитата:

Сообщение от oneguy
http://es5.javascript.ru/x16.html#x16
Цитата:
Реализация должна рассматривать все случаи следующих ошибок как раннюю ошибку:

...

Попытки вызвать PutValue для значения, по которому можно заранее определить, что оно не является Reference (например, при выполнении инструкции присваивания 3=4).

Интересно, что Опера в первом примере бросает ReferenceError: Cannot assign to 'alert', хотя, казалось бы, при чем тут 'alert'? :lol:

devote 16.07.2012 19:32

Цитата:

Сообщение от oneguy
только Фаерфокс выполняет пункты спецификации:

Ну об этом мало кто задумывается, для разрабов браузеров важнее скорость работы нежели тратить ЦП на предварительную проверку кода

bes 16.07.2012 20:04

oneguy, спасибо за информацию.

Итог по Reference, как я понимаю, такой:
Типом Reference обладают только значения, полученные при помощи . (точки), [] (квадратных скобок) и идентификатора (в относительно редких случаях значение типа Reference может вернуть функция).

Для использования то, что нужно, осталось только узнать: вы из спецификации эту информацию получили?

oneguy 16.07.2012 20:14

Цитата:

Сообщение от bes
Для использования то, что нужно, осталось только узнать: вы из спецификации эту информацию получили?

Да.

bes 16.07.2012 20:20

Цитата:

Сообщение от oneguy
Да.

Ок, когда-нибудь наткнусь на неё :)

PS: плюсик пока поставить не могу (надо всё-таки менять систему +/-)

B~Vladi 16.07.2012 22:12

Цитата:

Сообщение от bes
плюсик пока поставить не могу

Я за тебя поставил.

oneguy 16.07.2012 22:19

Цитата:

Сообщение от B~Vladi (Сообщение 189363)
Я за тебя поставил.

Спасибо :)

bes 16.07.2012 22:44

Цитата:

Сообщение от B~Vladi
Я за тебя поставил.

Всё забываю засечь, через сколько отзывов даёт снова ставить (где-то 5-7, неадекватно по-моему)


Часовой пояс GMT +3, время: 02:30.