Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Копирование и удаление переменных(обьектов). (https://javascript.ru/forum/misc/5731-kopirovanie-i-udalenie-peremennykh-obektov.html)

Yazla 01.11.2009 15:56

Копирование и удаление переменных(обьектов).
 
Здравствуйте, меня интересуют особенности внутренней работы интерпретатора и браузера.
Например:
В каком порядке удаляются объекты?
Когда переменная копируется по значение а когда по ссылке?
...

Может кто то подскажет книжки или статьи с данной инфой.


Заранее благодарен.

Zeroglif 01.11.2009 16:35

Yazla,

В js переменные со значениями любого типа передаются/копируюся "по-значению", никаких ссылок и проч. в стандарте нет, есть только значения. ECMAScript весь построен на by-value. Нужно только помнить, что в отношении объектов мы работаем со свойствами по ссылке. Но работа со свойствами объекта и работа с переменными - две большие разницы. ;-)

Объекты удаляет сборщик мусора (garbage collector), порядок и алгоритм в руках той или иной реализации языка, например, подробнее о JScript . Для программиста важно контролировать, чтобы объект, который он об-null-ил не зацепился за что-либо, что он не увидел. Иначе сборщик его не затрёт.

Dmitry A. Soshnikov 01.11.2009 18:20

Zeroglif, тут, на самом деле, людей сбивает с толку (тех, кто слышал о Reference Type из ES) само слово "Reference", которое ассоциируется со "ссылкой".

В технической же реализации (и описании в стандарте), то поведение, которое осуществляется для объектов, в общей теории - это передача by-sharing. Там как раз чётко описано отличие от передачи by-reference.

Zeroglif 01.11.2009 21:47

Ну, давай ещё добавим нечто, чтоб не разгрести было вообще. By-value - самое простое, объяснимое и вполне в рамках.

Kolyaj 01.11.2009 21:55

Цитата:

Сообщение от Zeroglif
By-value - самое простое, объяснимое и вполне в рамках.

Оно было бы объяснимое, если бы...
function foo(bar) {
    bar.a = 2;
}
var baz = {a: 1};
foo(baz);
alert(baz.a); // ...если бы вот тут было 1

Zeroglif 01.11.2009 22:07

Kolyaj,

Что есть value переменной, если тип объектный? Стандарт этого не раскрывает, но раскрыли давно разработчики языков, там адрес/указатель/нечто... и это не отменяет того факта, что это нечто копируется, стандарт даже не подразумевает ничего другого.

Brendan Eich:

- value is a *reference* to the object, not the object itself;
- the only thing that's copied is a *reference* (a safe pointer, if you will) that uniquely addresses the object;
- v2 = v just copies the reference in v into v2, making both variables denote the same object;

Выше по ссылке есть ещё несколько цитат от разрабов языков.

Kolyaj 01.11.2009 22:14

Цитата:

Сообщение от Zeroglif
Что есть value переменной, если тип объектный?

Ссылка, которая передается по значению, а объект, следовательно, передается по ссылке.

Zeroglif 01.11.2009 22:29

Kolyaj,

Ты прав совершенно в первой части - это ссылка, которая передаётся по значению. Именно эта ссылка и есть значение переменной в отношении объектного типа. Круг замкнулся, переменные by-value всегда. ;-)

Работа же с объектом (конкретно с его свойствами) происходит по ссылке из любой точки... но это не работа с переменными, это свойства.

Dmitry A. Soshnikov 01.11.2009 22:42

Цитата:

Сообщение от Zeroglif
Ну, давай ещё добавим нечто, чтоб не разгрести было вообще.

Не, наоборот, разгребли полностью. Если наиболее точно, то именно так. Поскольку есть чёткое разграничение между by-value, by-reference и by-sharing.

А остальное - это уже локальная терминология: ES называет by-value, Java называет by-value, Ruby называет by-reference - но во всех них в данном случае используется by-sharing.

Здесь фишка завязана ещё на связывание имён и объектов в памяти. Именно из-за того, что присваивание переменной объекта, отвязывает переменную от старого места в памяти, и не получается чистый by-reference.

Если бы был by-reference, было бы так:

function test(a) {
  a = {x: 20};
}
var b = {x: 10};
test(b);
alert(b.x); // 20


Если бы был by-value, было бы так:

function test(a) {
  a.x = 20;
}
var b = {x: 10};
test(b);
alert(b.x); // 10


А вот by-sharing, как раз имеет чёткую разницу от них двоих:

function test(a) {
  a.x = 20;
}
var b = {x: 10};
test(b);
alert(b.x); // 20

function test2(a) {
   // присваивание связывает "а" с новым объектом
  // старый остаётся нетронутым
  a = {x: 30};
}
test2(b);
alert(b.x); // 20


Но именно это связывание переменной с объектом ничем не отличается, если сделать то же самое вне функции и её параметров:

var a = {x: 10};
var b = a;
// a и b указывают на одно место в памяти
alert(b.x); // 10
b = {x: 20}; // связывание с новым объектом, но не апдейт "а"
alert(a.x); // 10


Если в рамках ES, то, конечно, можно и by-value говорить, главное знать, что выше этого стоит определение общей теории. С другой стороны, ECMA-262-3 точно это не описывает. Есть куча ссылок (в том числе, которые приводил ты), где, действительно, говорят by-value, но это, опять же, локальная терминология для by-sharing.

Может смущать, что работает оператор ===, который возвращает true для локального формального параметра и внешнего объекта (а он возвращает true в данном случае, если операнды указывают на один и тот же объект):

function test(a) {
  alert(a === b); // true
}
var b = {x: 10};
test(b);


Т.е. здесь тоже с толку может сбивать людей - кажется, что "a" - точно не локальный объект, а как будто бы переданный by-reference.

Но, во всяком случае, при разрешении "a" и "b", базовые объекты у них разные - для "а" - объект активации, для "b" - глобальный:

aRef = {baseObject: AO(test), propertyName: "a"};
bRef = {baseObject: Global, propertyName: "b"};


Каким-то образом затем [[Get]] получает value aRef и bRef и определяет, что они указывают на один объект.

Kolyaj 01.11.2009 22:47

Цитата:

Сообщение от Dmitry A. Soshnikov
Если бы был by-reference, было бы так:

Т.е. ссылки отличаются от указателей только тем, что операция разыменования не нужна?

Zeroglif 01.11.2009 22:48

Цитата:

Сообщение от Dmitry A. Soshnikov
ES называет by-value, Java называет by-value

вот... оно самое ;-)

Dmitry A. Soshnikov 01.11.2009 22:57

Цитата:

Сообщение от Kolyaj
Т.е. ссылки отличаются от указателей только тем, что операция разыменования не нужна?

Пример был псевдо-кодом, не касаемо конкретной реализации и терминологии из C/С++ с её указателями и ссылками.

Цитата:

Сообщение от Zeroglif
вот... оно самое ;-)

Ага, только ES я имею в виду не ECMA-262-3, а разъяснения программеров. В любом случае, я буду в дальнейшем объяснять так: "название из общей теории - by-sharing (и ссылка), но в ES - принято название - by-value (и, возможно, ссылки на объяснения B.Eich-a)", т.к. это наиболее полно.

Zeroglif 01.11.2009 23:15

В javascript было принято говорить by-val в отношении примитивов, и by-ref в отношении объектов. Это даже в доках было. Eсли ты видел на vingrad-e на меня с моим by-value смотрели как на марсианина. Потом постепенно начали исправлять по аналогии с java в онлайн-доках mdc, уточняя ситуацию с помощью разъяснений dev-ов.

By-value мне кажется очевидней, наиболее точным по отношению к стандарту, где есть только значения, где есть внутренние методы [[Get]], GetValue, промежуточный внутренний тип Reference Type, конкретизация переменных, где значения всегда копируются. И потом этот проще для понимания по сравнению с двойным случаем и уж тем более по сравнению с не используемым в быту by-sharing... Можете включать голосовалку, я за by-value... ;-)

Dmitry A. Soshnikov 01.11.2009 23:38

Цитата:

Сообщение от Zeroglif
Можете включать голосовалку, я за by-value... ;-)

Не-а, я не участвую ;-) Единственное, на что могу согласиться, это поменять местами приоритеты - сначала говорить, что в ES используют терминологию by-value, но вообще, не касаемо реализаций и языков, это называется by-sharing (даже если! даже, если - by-sharing и не часто используется в быту; меня всегда больше теория интересует).

Цитата:

Сообщение от Zeroglif
by-ref в отношении объектов. Это даже в доках было. Eсли ты видел на vingrad-e на меня с моим by-value смотрели как на марсианина

Ну by-reference не верно, в любом случае, так что, на vingrad-e ты был прав.

Цитата:

Сообщение от Zeroglif
конкретизация переменных

Это, в смысле, ты имеешь в виду [[Get]]? Или, наоборот, только разрешение имени?

С другой стороны, технически, тогда обычное присвоение тоже создаёт копию ссылки и ничем не отличает от передачи в качестве параметра функции:

var a = {x: 10};
var b = a;

aRef = {baseObject: Global, propertyName: "a"}; // address: 0xFF
bRef = {baseObject: Global, propertyName: "b"}; // address: 0xFF (скопировался)

var a = {x: 20};
aRef = {baseObject: Global, propertyName: "a"}; // address: 0xFА (новый)
bRef = {baseObject: Global, propertyName: "b"}; // address: 0xFF (старый)


Вот в этом отношении говорить о значении (скопированном value адреса, ссылки) - да, конечно, правильно. И, повторю, тогда вообще нет разницы от присваивания и передачи в функции в качестве формального параметра (или есть, как думаешь?).

Но, теоретическая evaluation strategy - остаётся by-sharing, как специально выделенная и обособленная от by-value и by-reference и именно по этому критерию.

Zeroglif 01.11.2009 23:53

Ты просто на объекте замкнулся, представь, что объект не меняет свойств, почему сразу свойства дёргать внутри функции. Речь ведь о переменной и изменении её значения, а не о свойствах объекта. Если значением переменной не является объект, а только URL до объекта, то почему изменение свойств объекта (отражаемое везде) является аргументом в пользу by-sharing, и тем более by-ref. Меняем ведь не значение переменной. Это ж очевидно.

Dmitry A. Soshnikov 02.11.2009 00:33

Zeroglif, на самом деле, мы говорим об одном и том же. Даже в статье об evaluation strategy из Википедии в подразделе by-value говорится о нашем случае:

Цитата:

Сообщение от Wikipedia ::Evaluation strategy :: Call by value
The term "call-by-value" is sometimes problematic, as the value implied is not the value of the variable as understood by the ordinary meaning of value, but an implementation-specific reference to the value. The term "call-by-value where the value is a reference" is common (but should not be understood as being call-by-reference). Thus the behaviour of call-by-value Java or Visual Basic and call-by-value C or Pascal are significantly different: in C or Pascal, calling a function with a large structure as an argument will cause the entire structure to be copied, potentially causing serious performance degradation, and mutations to the structure are invisible to the caller. However, in Java or Visual Basic only the reference to the structure is copied, which is fast, and mutations to the structure are visible to the caller. (See also call-by-sharing....)

И далее, в подразделе by-sharing, так же есть рекурсивная ссылка на подраздел by-value:

Цитата:

Сообщение от Wikipedia ::Evaluation strategy :: Call by sharing
The semantics of call-by-sharing differ from call-by-reference in that assignments to function arguments within the function aren't visible to the caller (unlike by-reference semantics). However since the function has access to the same object as the caller (no copy is made ), mutations to those objects within the function are visible to the caller, which differs from call-by-value semantics.

Although this term has widespread usage in the Python community, identical semantics in other languages such as Java and Visual Basic are often described as call-by-value, where the value is implied to be a reference to the object.

Кстати, там же, есть похожая на by-sharing (и by-value в случае ES, Java и т.д.) стратегия - by-copy-restore.

by-value - это правильно (особенно, если учесть, что данную терминологию использует создатель языка). Но обособление by-sharing для этого случая (что означает ровно то же самое - копирование не целиком массивного объекта (как это было бы в Cи в случае by-value), а копирование лёгкой ссылки), мне кажется оправданным - чтобы не путать именно с by-value, когда передался бы объект-бегемот и менялся бы там внутри функции независимо. Хотя, с другой стороны, by-value в Си - это всего лишь одна из реализаций. Но, эта реализация (и её понятие by-value) появилась раньше JS.

Zeroglif 02.11.2009 00:53

Хорошие цитаты. Особенно "but should not be understood as being call-by-reference". В общем, я сегодня почти поставил для себя в этом вопросе окончательную точку. Только вот разберусь с этим твоим call-by-sharing основательнее...

Dmitry A. Soshnikov 02.11.2009 11:35

А я, пожалуй, найду время и напишу заметку по этому поводу, чтобы, опять же, ссылаться на неё, а не на вырванные из контекста ответы, если возникнет похожий вопрос. Мотивацией будет этот тред. В общем, будет "by-value" (a.lso k.nown a.s "by-sharing").

Zeroglif 02.11.2009 13:40

Dmitry A. Soshnikov,

Пиши, пиши, вот цитаты B.E. со ссылками:

...the property's value is a *reference* to the object, not the object itself.
http://groups.google.com/group/mozil...ff6fa9deb204e1

JS is not C++. There is no deep or shallow copy on assignment. Object is a reference type, so v2 = v just copies the reference in v into v2, making both variables denote the same object.
http://groups.google.com/group/netsc...dd2121f1fb8424

There is no copy of any object data. The only thing that's copied is a *reference* (a safe pointer, if you will) that uniquely addresses the object.
http://groups.google.com/group/netsc...95f5eef93c1734

Just the reference - objects are reference types in JS, as in Java
http://groups.google.com/group/netsc...79c0c9f86a6336

Что-то по JScript на винграде есть... liskov-y я прочитал (manual языка), да, это был бы подходящий термин, если бы прижился, там они чётко описывают, что значением переменной является reference на объект. Но раз не прижился, то пиарить не буду, только в качестве экскурса... меня полностью удовлетворяет то, как компактно и точно звучит первая цитата в твоём предыдущем сообщении.

Dmitry A. Soshnikov 02.11.2009 14:06

Цитата:

Сообщение от Zeroglif
вот цитаты B.E. со ссылками

Ага, спасибо.

Yazla 02.11.2009 14:10

Всем большое спасибо за ответы и ссылки, всё очень понятно и доступно.

Yazla 02.11.2009 15:45

Ещё один вопрос созрел насчёт удаления объектов.
Пример кода:
var objectA = {a:1};
  var objectB = {b:1};
  objectA.property1 = objectB;

Вопрос в следующем:
Как правильно обнулить объекты в данном случае и нужно ли их обнулять(может уборщик мусора сам справиться)?
Как я понял правильнее было бы вначале objectA.property1 = null потом обнулить объекты но я не совсем уверен нужно ли это.

Заранее благодарен.

blackrabbit99 25.11.2011 14:03

Цитата:

Сообщение от Yazla (Сообщение 34219)
Ещё один вопрос созрел насчёт удаления объектов.
Пример кода:
var objectA = {a:1};
  var objectB = {b:1};
  objectA.property1 = objectB;

Вопрос в следующем:
Как правильно обнулить объекты в данном случае и нужно ли их обнулять(может уборщик мусора сам справиться)?
Как я понял правильнее было бы вначале objectA.property1 = null потом обнулить объекты но я не совсем уверен нужно ли это.

Заранее благодарен.

По идеи надо сделать следующее
for(x in objectA){
delete x;
}
objectA = null;


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