Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Почему некоторые операторы возвращают значения, а не ссылки? (https://javascript.ru/forum/misc/30101-pochemu-nekotorye-operatory-vozvrashhayut-znacheniya-ne-ssylki.html)

dump 24.07.2012 12:16

Почему некоторые операторы возвращают значения, а не ссылки?
 
Вот код:

Код:

v=1;
var foo = {bar: function () {alert(this.v);}, v:2};

foo.bar(); // 2
(foo.bar)(); // 2

(foo.bar = foo.bar)(); // 1
(false || foo.bar)(); // 2
(foo.bar, foo.bar)(); // 1

Почему он в последовательно выводит 22121, хотя должен бы 22222? Вот здесь - http://dmitrysoshnikov.com/ecmascrip...#tip-reference сказано, что это из-за того, что если вызывается значение не ссылочного типа, то this равно null, а следовательно global. Но я не могу понять, почему оператор присваивания возвращает значение не типа reference? И почему та же запятая, возвращает значение, а не ссылку? Ведь функция - это ссылочный тип, как и любой другой объект, а значит (foo.bar = foo.bar)(); должно вызвать по ссылке и установить this в значение foo...

vasa_c 24.07.2012 12:42

нет никакого типа reference. он только теоретически в ECMA.
foo.bar = foo.bar возвращает функцию. а функция в JS не привязана ни к какому объекту.

dump 24.07.2012 14:18

Цитата:

а функция в JS не привязана ни к какому объекту.
Но в последних трёх примерах она привязана к объекту foo. Но значение this там не такое однозначное...

devote 24.07.2012 15:44

Цитата:

Сообщение от dump
Но в последних трёх примерах она привязана к объекту foo.

и где же вы там привязку нашли?
(foo.bar = foo.bar)();
это всеравно что вызвать так:
var a = foo.bar; // привязка объекта к безымянной переменной
a(); // вызов безымянной переменной

и это:
(foo.bar, foo.bar)();
тоже что и:
foo.bar; // просто бесмысленая конструкция, ничего совсем не делает
var a = foo.bar; // далее привязка объекта к безымянной переменной
a(); // вызов безымянной переменной

oneguy 24.07.2012 16:16

Цитата:

Сообщение от dump
Почему он в последовательно выводит 22121, хотя должен бы 22222?

Вообще-то он выводит 22111. Я уже писал пост по этому поводу. http://javascript.ru/forum/misc/2986...tml#post189309
Reference - это тип спецификации, отличный от языкового типа объект. Только операторы . и [], а также () в редких случаях возвращают значение Reference, все остальные операторы, в том числе ||, = и запятая всегда возвращают языковое значение.

dump 24.07.2012 17:22

Т.е. получается, что оператор (foo.bar, foo.bar) образно говоря проходит по ссылке foo.bar, извлекает объект(функцию) bar и представляет её в качестве значения в отдельной области памяти? Тогда почему в таком случае следующий код:
Код:

o={x:2,y:3};
b=(false , o);
b.x=7;
alert(o.x);

выведет 7? Он же по идее должен вывести 2, потому что оператор запятая возвратит значение, что приведёт к копированию всего объекта(а не его ссылки), следовательно b в станет не ссылкой, а значением. Но этого не происходит, запятая возвращает ссылку, а не сам объект, это видно если поменять свойство x. Тогда почему же (foo.bar, foo.bar) возвращает само значение?

Цитата:

Вообще-то он выводит 22111.
У меня он выводит 22121. Почему так? Какой программой для запуска пользуетесь?

devote 24.07.2012 18:06

Цитата:

Сообщение от dump
огда почему же (foo.bar, foo.bar) возвращает само значение?

а кто сказал что оно значение возвращает? оно так же возвращает ссылку на метод(функцию), просто контекст у функции теряется.

oneguy 24.07.2012 23:01

Здесь возникает путаница в понятиях. Есть 6 языковых типов, среди которых объект, а есть тип спецификации Reference. Значения типа Reference часто называют ссылками, и значения типа Object часто называют ссылками на объект. Хотя на самом деле Object и Reference - это два совершенно разных типа. Значение переменной и свойства объекта всегда принадлежит языковому типу и не может принадлежать типу Reference.
Значения Reference состоят из 2-х компонент: базы и имени (ещё и флага Strict, но в большинстве случаев его можно не рассматривать). Значение Object являются некоторым внутренним значением (адрес, идентификатор), с помощью которого можно однозначно определить структуру данных, состоящую из свойств, в памяти. Часто называют объектами сами такие структуры данных.
o={x:2,y:3};
b=(false , o); // в данном случае b имеет тип Object, значение переменной никогда не может иметь тип Reference
b.x=7;
alert(o.x);

v=1;
var foo = {bar: function () {alert(this.v);}, v:2};

foo.bar(); // 2
(foo.bar)(); // 2

(foo.bar = foo.bar)(); // 1
(false || foo.bar)(); // 2 (у меня 1)
(foo.bar, foo.bar)(); // 1

В данном случае выражение foo.bar возвращает значение Reference с базой, равной значению переменной foo, и именем "bar". Оператор запятая, если правый операнд возвращает значение Reference, его разыменовывает, и возвращает разыменованное значение. В данном случае это значение типа Reference разыменовывается в функцию с кодом { alert(this.v) }, точнее ссылку на эту функцию и выражение (foo.bar, foo.bar) её (ссылку на функцию, значение типа Object) и возвращает.
Цитата:

Сообщение от dump
У меня он выводит 22121. Почему так? Какой программой для запуска пользуетесь?

Запускал на тестовой странице, проверял в IE, Firefox, Chrome. А вы какой программой пользуетесь?

devote 25.07.2012 05:44

Цитата:

Сообщение от oneguy
(false || foo.bar)(); // 2 (у меня 1)

опера выводит двойку

oneguy 25.07.2012 16:17

Цитата:

Сообщение от devote
опера выводит двойку

Ну и дура :lol:
По спецификации там должно быть 1.
По-видимому, Опера при выполении операторов || и && не делает разыменование значения правого операнда перед возращением, хотя это неправильное поведение с точки зрения спецификации.


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