Как работают указатели в Javascript? [Дубликат]

Иногда вы можете получить только количество месяцев между двумя датами, полностью игнорирующими дневную часть. Например, если у вас были две даты - 2013/06/21 и 2013/10/18 - и вы заботились только о частях 2013/06 и 2013/10, вот сценарии и возможные решения:

var date1=new Date(2013,5,21);//Remember, months are 0 based in JS
var date2=new Date(2013,9,18);
var year1=date1.getFullYear();
var year2=date2.getFullYear();
var month1=date1.getMonth();
var month2=date2.getMonth();
if(month1===0){ //Have to take into account
  month1++;
  month2++;
}
var numberOfMonths; 

1.Если вы хотите просто количество месяцев между двумя датами, исключая как month1, так и month2

numberOfMonths = (year2 - year1) * 12 + (month2 - month1) - 1;

2.Если вы хотите включить один из месяцев

numberOfMonths = (year2 - year1) * 12 + (month2 - month1);

3.Если вы хотите включить оба месяца

numberOfMonths = (year2 - year1) * 12 + (month2 - month1) + 1;
1174
задан Taryn 22 March 2017 в 17:23
поделиться

31 ответ

Это интересно в Javascript. Рассмотрим этот пример:

function changeStuff(a, b, c)
{
  a = a * 10;
  b.item = "changed";
  c = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};

changeStuff(num, obj1, obj2);

console.log(num);
console.log(obj1.item);    
console.log(obj2.item);

Это приводит к выходу:

10
changed
unchanged
  • Если он был чистым перейдите по значению, тогда изменение obj1.item не повлияет на obj1 вне функции.
  • Если бы это было чистое обращение по ссылке, все изменилось бы. num будет 100, а obj2.item будет читать "changed".

Вместо этого ситуация заключается в том, что переданный элемент передается по значению. Но элемент, который передается по значению, является самой ссылкой. Технически это называется вызовом по обмену .

В практическом плане это означает, что если вы измените сам параметр (как в num и obj2), что не повлияет на элемент, который был подан в параметр. Но если вы измените INTERNALS параметра, который будет распространяться обратно (как с obj1).

1362
ответ дан 10 revs, 10 users 60% 16 August 2018 в 00:53
поделиться
  • 1
    Это то же самое (или, по крайней мере, семантически) как C #. Объект имеет два типа: значение (примитивные типы) и ссылку. – Peter Lee 24 December 2011 в 02:15
  • 2
    Я думаю, что это также используется в Java: reference-by-value. – Jpnh 4 January 2012 в 15:41
  • 3
    реальная причина в том, что в changeStuff, num, obj1 и obj2 являются ссылками. Когда вы изменяете свойство item объекта, на которое ссылается obj1, вы меняете значение свойства элемента, которое изначально было установлено так «без изменений». Когда вы назначаете obj2 значение {item: & quot; changed & quot;}, вы меняете ссылку на новый объект (который сразу выходит из области действия при выходе из функции). Становится более очевидным, что происходит, если вы называете функцию params такими, как numf, obj1f и obj2f. Затем вы видите, что параметры скрывали внешние имена переменных. – jinglesthula 30 January 2012 в 21:26
  • 4
    @BartoNaz Не совсем. Вы хотите передать ссылку по ссылке вместо передачи ссылки по значению. Но JavaScript всегда передает ссылку по значению, точно так же, как передает все остальное по значению. (Для сравнения, C # имеет поведение с положением-по-значению, аналогичное JavaScript и Java, но позволяет вам указывать ссылку-ссылку на ссылку с ключевым словом ref.) Обычно вы просто должны вернуть функцию новому объекту , и выполняйте назначение в том месте, где вы вызываете функцию. Например, foo = GetNewFoo(); вместо GetNewFoo(foo); – Tim Goodman 5 August 2013 в 16:26
  • 5
    Хотя этот ответ наиболее популярен, он может быть немного запутанным, потому что он утверждает: «Если это был чистый проход по значению». JavaScript is чистый проход по значению. Но переданное значение является ссылкой. Это не ограничивается передачей параметров вообще. Вы можете просто скопировать переменную на var obj1 = { item: 'unchanged' }; var obj2 = obj1; obj2.item = 'changed'; и наблюдать тот же эффект, что и в вашем примере. Поэтому я лично ссылаюсь на ответ Тима Гудмана – chiccodoro 2 May 2014 в 10:19

Объект вне функции передается в функцию, указывая ссылку на внешний obejct. Когда вы используете эту ссылку для манипулирования своим объектом, объект наружу, таким образом, затрагивается. Однако, если внутри функции вы решили указать ссылку на что-то еще, вы вообще не повлияли на объект снаружи, потому что все, что вы делали, перенаправляло ссылку на что-то еще.

22
ответ дан alex 16 August 2018 в 00:53
поделиться
3
ответ дан C Perkins 16 August 2018 в 00:53
поделиться

Для юристов на языке программирования я просмотрел следующие разделы ECMAScript 5.1 (который легче читать, чем последнее издание), и дойдите до , задав его в списке рассылки ECMAScript ,

TL; DR : все передаются по значению, но свойства объектов - это ссылки, а определение объекта, как правило, отсутствует в стандарте.

Построение списков аргументов

Раздел 11.2.4 «Списки аргументов» говорит следующее о создании списка аргументов, состоящего всего из 1 аргумента:

Вывод ArgumentList: AssignmentExpression оценивается следующим образом:

  1. Пусть ref является результатом оценки AssignmentExpression.
  2. Пусть arg - GetValue (ref).
  3. Возвращает список, единственным элементом которого является arg.

В этом разделе также перечислены случаи, когда список аргументов имеет 0 или> 1 аргумент.

Таким образом, все передается по ссылке.

Доступ к свойствам объекта

Раздел 11.2.1 «Аксессоры свойств»

Вывод MemberExpression: MemberExpression [Expression] оценивается следующим образом:

  1. Пусть baseReference будет результатом оценки MemberExpression.
  2. Пусть baseValue будет GetValue (baseReference).
  3. Пусть свойствоNameReference является результатом вычисления выражения.
  4. Пусть свойствоNameValue будет GetValue (свойствоNameReference).
  5. Вызов CheckObjectCoercible (baseValue).
  6. Пусть свойствоNameString будет ToString (propertyNameValue).
  7. If синтаксическое производство, которое оценивается, содержится в коде строгого режима, пусть строгое истинно, иначе пусть строгое будет ложным.
  8. Возвращает значение типа Reference , базовое значение которого baseValue и ссылочным именем которого является свойствоNameString, а флаг строгого режима - строгий.

Таким образом, свойства объектов всегда доступны как рефери се.

On Reference

Описан в разделе 8.7 «Тип ссылочной спецификации», что ссылки не являются реальными типами на языке - они используются только для описания поведения delete, typeof и операторы присваивания.

Определение «Object»

В редакции 5.1 определено, что «Object - это совокупность свойств». Поэтому мы можем заключить, что значение объекта - это коллекция, но что касается того, что значение коллекции плохо определено в спецификации, и требует немного усилий для понимания.

2
ответ дан DannyNiu 16 August 2018 в 00:53
поделиться
  • 1
    Меня никогда не перестает удивлять, сколько людей путают различия между аргументами, передаваемыми по значению, аргументами, переданными по ссылке, операциями над целыми объектами и операциями над их свойствами. В 1979 году я не получил диплом по информатике, вместо этого вместо того, чтобы добавить 15 часов или около того CS-факультатов к своей программе MBA. Тем не менее, вскоре мне стало ясно, что мое понимание этих концепций по крайней мере так же хорошо, как и у любого из моих коллег, имеющих ученые степени в области информатики или математики. Изучите ассемблер, и это станет совершенно ясным. – David A. Gray 1 October 2017 в 06:11

Мой простой способ понять это ...

  • При вызове функции вы передаете содержимое (ссылку или значение) переменных аргумента, а не сами переменные.
    var var1 = 13;
    var var2 = { prop: 2 };
    
    //13 and var2's content (reference) are being passed here
    foo(var1, var2); 
    
  • Внутри функции переменные параметра inVar1 и inVar2 получают переданное содержимое.
    function foo(inVar1, inVar2){
        //changing contents of inVar1 and inVar2 won't affect variables outside
        inVar1 = 20;
        inVar2 = { prop: 7 };
    }
    
  • Поскольку inVar2 получил ссылку { prop: 2 }, вы можете изменить значение свойства объекта.
    function foo(inVar1, inVar2){
        inVar2.prop = 7; 
    }
    
2
ответ дан dpp 16 August 2018 в 00:53
поделиться

Рассмотрим следующее:

  1. Переменные - указатели для значений в памяти.
  2. Переназначение переменной просто указывает, что указатель на новое значение .
  3. Переназначение переменной никогда не повлияет на другие переменные, указывающие на тот же объект

Итак, забудьте о «pass by reference / value» не зацикливаться на «pass by reference / value», потому что:

  1. Термины используются только для описания поведения языка языка, не обязательно фактическая базовая реализация. В результате этой абстракции теряются критические детали, которые необходимы для достойного объяснения, что неизбежно приводит к текущей ситуации, когда один термин не описывает адекватное описание фактического поведения и дополнительной информации
  2. Эти понятия изначально не были определены с целью описания javascript в частности, и поэтому я не чувствую себя вынужденным использовать их, когда они только добавляют к путанице.

Чтобы ответить на ваш вопрос : указатели переданы.

// code
var obj = {
    name: 'Fred',
    num: 1
};

// illustration
               'Fred'
              /
             /
(obj) ---- {}
             \
              \
               1

// code
obj.name = 'George';


// illustration
                 'Fred'


(obj) ---- {} ----- 'George'
             \
              \
               1

// code
obj = {};

// illustration
                 'Fred'


(obj)      {} ----- 'George'
  |          \
  |           \
 { }            1

// code
var obj = {
    text: 'Hello world!'
};

/* function parameters get their own pointer to 
 * the arguments that are passed in, just like any other variable */
someFunc(obj);


// illustration
(caller scope)        (someFunc scope)
           \             /
            \           /
             \         /
              \       /
               \     /
                 { }
                  |
                  |
                  |
            'Hello world'

Некоторые окончательные комментарии:

  • Заманчиво думать, что примитивы применяются специальными правилами, а объекты - нет, но примитивы просто конец цепочки указателей.
  • В качестве окончательного примера рассмотрим, почему общая попытка очистить массив работает не так, как ожидалось.

var a = [1,2];
var b = a;

a = [];
console.log(b); // [1,2]
// doesn't work because `b` is still pointing at the original array
57
ответ дан geg 16 August 2018 в 00:53
поделиться
  • 1
    Последующие вопросы для дополнительного кредита;) Как работает сбор мусора? Если я циклирую переменную через миллион {'George', 1} значений, но только один из них за один раз, то как другие управляются? И что происходит, когда я присваиваю переменную значение другой переменной? Я тогда указываю на указатель или указывая на указатель правильного операнда? Имеет ли var myExistingVar = {"blah", 42}; var obj = myExistingVar; результат obj, указывающий на {"blah", 42}, или на myExistingVar? – Michael Hoffmann 4 March 2017 в 22:43
  • 2
    @MichaelHoffmann Они заслуживают собственных SO-вопросов и, вероятно, уже ответили лучше, чем я могу справиться. При этом 1) я запустил профиль памяти в инструментах браузера dev для функции цикла, такой как описанная вами, и увидел всплески в использовании памяти во время цикла. Казалось бы, это указывает на то, что на каждой итерации цикла действительно создаются новые идентичные объекты. Когда пики внезапно падают, сборщик мусора просто очистил группу этих неиспользуемых объектов. – geg 14 March 2017 в 05:14
  • 3
    @MichaelHoffmann 2) Что касается чего-то вроде var a = b, javascript не предоставляет механизм для использования указателей, и поэтому переменная никогда не может указывать на указатель (как вы можете на C), хотя базовый механизм javascript, несомненно, использует их. Поэтому ... var a = b будет указывать a "на указатель правильного операнда" – geg 14 March 2017 в 05:16
  • 4
    Я задал здесь вопрос № 1 (в частности, о Chrome, потому что реализация, вероятно, будет отличаться в каждом браузере) stackoverflow.com/q/42778439/539997 , и я все еще пытаюсь вспомнить, как сформулировать вопрос # 2. Любая помощь приветствуется. – Michael Hoffmann 14 March 2017 в 06:39
  • 5
    @CPerkins Справедливая точка. Я попытался уточнить. – geg 1 June 2017 в 22:06

Очень подробное объяснение о копировании, прохождении и сравнении по значению и по ссылке содержится в в этой главе книги «JavaScript: окончательное руководство».

До мы оставляем тему манипуляции объектами и массивами по ссылке, нам нужно прояснить точку номенклатуры. Фраза «пройти по ссылке» может иметь несколько значений. Для некоторых читателей фраза относится к методу вызова функции, которая позволяет функции назначать новые значения своим аргументам и изменять эти измененные значения вне функции. Это не значит, что термин используется в этой книге. Здесь мы имеем в виду просто, что ссылка на объект или массив - не сам объект - передается функции. Функция может использовать ссылку для изменения свойств объекта или элементов массива. Но если функция перезаписывает ссылку ссылкой на новый объект или массив, эта модификация не видна вне функции. Читатели, знакомые с другим значением этого термина, могут предпочесть сказать, что объекты и массивы передаются по значению, но переданное значение на самом деле является ссылкой, а не самим объектом.

One вещь, которую я до сих пор не могу понять. Проверьте код ниже. Любые мысли?

function A() {}
A.prototype.foo = function() {
    return 'initial value';
}


function B() {}
B.prototype.bar = A.prototype.foo;

console.log(A.prototype.foo()); //initial value
console.log(B.prototype.bar()); //initial value

A.prototype.foo = function() {
    return 'changed now';
}

console.log(A.prototype.foo()); //changed now
console.log(B.prototype.bar()); //Why still 'initial value'???
10
ответ дан igor 16 August 2018 в 00:53
поделиться
  • 1
    Я точно объяснил, что вы сделали и что это значит, но эти комментарии не позволяют мне отправлять более 600 символов или что-то еще, поэтому я разместил их как ответ ниже. Пожалуйста, проверьте это и прокомментируйте. thx ~ дневной свет – raddevus 17 May 2011 в 15:06
  • 2
    Итак, кажется, что B.prototype.bar = A.prototype.foo; назначается ссылкой, но последний A.prototype.foo = function () {...} изменяет значение свойства foo для A.prototype и нарушает ссылку. B.prototype.bar все еще содержит ссылку на ту же первую функцию. – igor 18 May 2011 в 12:03
  • 3
    Установка одной функции, равной другой, не является присвоением по ссылке. «foo» и «bar» - это просто функции, являющиеся членами объектов A и B – Greg 10 December 2016 в 02:01
  • 4
    Ниже приведена демонстрация реализации функции как отдельного элемента массива. Массив будет копировать по ссылке, но функция будет копировать по значению. jsfiddle.net/ug04ks33 – Greg 12 December 2016 в 17:32

Я нашел метод extend библиотеки Underscore.js очень полезен, когда я хочу передать объект в качестве параметра, который может быть либо изменен, либо полностью заменен .

function replaceOrModify(aObj) {
  if (modify) {

    aObj.setNewValue('foo');

  } else {

   var newObj = new MyObject();
   // _.extend(destination, *sources) 
   _.extend(newObj, aObj);
  }
}
0
ответ дан Jack 16 August 2018 в 00:53
поделиться

Передача аргументов функции в JavaScript аналогична передаче параметров по значению указателя в C:

/*
The following C program demonstrates how arguments
to JavaScript functions are passed in a way analogous
to pass-by-pointer-value in C. The original JavaScript
test case by @Shog9 follows with the translation of
the code into C. This should make things clear to
those transitioning from C to JavaScript.

function changeStuff(num, obj1, obj2)
{
    num = num * 10;
    obj1.item = "changed";
    obj2 = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};
changeStuff(num, obj1, obj2);
console.log(num);
console.log(obj1.item);    
console.log(obj2.item);

This produces the output:

10
changed
unchanged
*/

#include <stdio.h>
#include <stdlib.h>

struct obj {
    char *item;
};

void changeStuff(int *num, struct obj *obj1, struct obj *obj2)
{
    // make pointer point to a new memory location
    // holding the new integer value
    int *old_num = num;
    num = malloc(sizeof(int));
    *num = *old_num * 10;
    // make property of structure pointed to by pointer
    // point to the new value
    obj1->item = "changed";
    // make pointer point to a new memory location
    // holding the new structure value
    obj2 = malloc(sizeof(struct obj));
    obj2->item = "changed";
    free(num); // end of scope
    free(obj2); // end of scope
}

int num = 10;
struct obj obj1 = { "unchanged" };
struct obj obj2 = { "unchanged" };

int main()
{
    // pass pointers by value: the pointers
    // will be copied into the argument list
    // of the called function and the copied
    // pointers will point to the same values
    // as the original pointers
    changeStuff(&num, &obj1, &obj2);
    printf("%d\n", num);
    puts(obj1.item);
    puts(obj2.item);
    return 0;
}
3
ответ дан John Sonderson 16 August 2018 в 00:53
поделиться
  • 1
    Я не думаю, что это имеет место в JavaScript: `` `javascript var num = 5; – Danail Nachev 7 April 2015 в 00:05

Все аргументы функции в ECMAScript передаются по значению. Это означает, что значение вне функции копируется в аргумент внутри функции так же, как значение копируется из одной переменной в другую. Если значение является примитивным, то оно действует так же, как и примитивная переменная, и если значение является ссылкой, оно действует как копия ссылочной переменной. Это часто является путаницей для разработчиков, поскольку к переменным обращаются как по значению, так и по ссылке, но аргументы передаются только по значению. Когда аргумент передается по значению, значение копируется в локальную переменную (именованный аргумент и в ECMAScript - слот в объекте arguments). Когда аргумент передается по ссылке, местоположение значения в памяти сохраняется в локальной переменной, что означает, что изменения в локальной переменной отражаются вне функции. (Это невозможно в ECMAScript.)

2
ответ дан Kamal Raj 16 August 2018 в 00:53
поделиться

В некоторых случаях это может быть полезно изменить anArg:

function alterMyArg(func) {
    // process some data
    // ...
    func(data);
}

alertMyArg(function(d) {anArg = d;});
-2
ответ дан lefakir 16 August 2018 в 00:53
поделиться

Наиболее кратким объяснением, которое я нашел, было в руководстве по стилю AirBNB :

  • Примитивы: при доступе к примитивному типу вы работаете непосредственно со своим номером строки значений boolean null undefined

Например:

var foo = 1,
    bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9
  • Сложность: Когда вы получаете доступ к сложному типу, вы работаете над ссылкой на его функцию массива объектов объекта

Например:

var foo = [1, 2],
    bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

Т.е. эффективно примитивные типы передаются по значению, а сложные типы передаются по ссылке.

1
ответ дан lid 16 August 2018 в 00:53
поделиться
  • 1
    Нет, все всегда передается по значению. Это зависит от того, что вы проходите (значение или ссылка). См. это . – Scott Marcus 5 April 2018 в 17:26

Я бы сказал, что это pass-by-copy -

. Рассмотрение аргументов и объектов переменных - это объекты, созданные во время контекста выполнения, созданного в начале вызова функции, - и ваше фактическое значение / ссылка, переданная в функция просто хранится в этих аргументах + объекты переменных.

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

0
ответ дан lyslim 16 August 2018 в 00:53
поделиться
  • 1
    & Quot; передача по копии & Quot; === проход по значению – Scott Marcus 5 April 2018 в 17:29

Javascript всегда pass-by-value , все имеет тип значения. Объекты являются значениями, функции-члены объектов сами являются значениями (помните, что функции являются первоклассными объектами в Javascript). Кроме того, в отношении концепции, что все в Javascript является объектом , это неверно. Строками, символами, числами, булевыми значениями, нулями и неопределенными являются примитивы . Иногда они могут использовать некоторые функции-члены и свойства, унаследованные от их базовых прототипов, но это только для удобства, это не значит, что они сами объекты. Попробуйте следующее для справки

x = "test";
alert(x.foo);
x.foo = 12;
alert(x.foo);

В обоих предупреждениях вы найдете неопределенное значение.

14
ответ дан Maggyero 16 August 2018 в 00:53
поделиться
  • 1
    -1, он не всегда проходит по значению. Из MDC: «Если вы передаете объект (т. Е. Не примитивное значение, такое как Array или определяемый пользователем объект) в качестве параметра, ссылка на объект передается функции. – Nick 13 October 2010 в 22:43
  • 2
    @Nick: он всегда проходит по значению. Период. Ссылка на объект передается по значению в функцию. Это не проходит по ссылке. & quot; Передавать по ссылке & quot; можно было почти мыслить как прохождение самой переменной, а не ее значение; any изменяет функцию делает аргумент (включая замену его другим объектом целиком!), будет отражен в вызывающем. Этот последний бит невозможен в JS, потому что JS не проходит по ссылке - он передает ссылки по значению. Различие является тонким, но весьма важным для понимания его ограничений. – cHao 10 May 2012 в 15:21
  • 3
    Для будущих штабелеров ... Об этой ссылке: x = "teste"; x.foo = 12; и т. Д. Просто потому, что свойство не является постоянным, это не значит, что это не объект. Как говорит MDN: В JavaScript почти все является объектом. Все примитивные типы, кроме null и undefined, рассматриваются как объекты. Им могут быть назначены свойства (назначенные свойства некоторых типов не являются постоянными), и у них есть все характеристики объектов. link – slacktracer 16 August 2012 в 02:49
  • 4
    MDN - это отредактированная пользователем wiki, и она там неправильная. Нормативной ссылкой является ECMA-262. См. S. 8 «Тип ссылочной спецификации», в котором объясняется, как решаются ссылки, а также 8.12.5 «[[Put]]», который используется для объяснения выражения AssignmentExpression для Reference и для объектной конверсии 9.9 Для объекта. Для примитивных значений Майкл уже объяснил, что делает TOObject, как в спецификации. Но см. Также s. 4.3.2 примитивное значение. – Garrett 14 December 2013 в 20:16
  • 5
    @WonderLand: Нет, это не так. Люди, которые никогда не могли пройти по ссылке, никогда не могут понять различия между передачей по ссылке и передачей ссылки по значению. Но они там, и они имеют значение. Я не хочу дезинформировать людей, потому что это звучит просто. – cHao 5 May 2016 в 17:49

Здесь обсуждается использование термина «передать по ссылке» в JS здесь , но для ответа на ваш вопрос:

Объект автоматически передается ссылка, без необходимости конкретно указывать его

(Из статьи, упомянутой выше.)

2
ответ дан mmitchell 16 August 2018 в 00:53
поделиться
  • 1
    Связанная статья больше не включает в себя эти инструкции и позволяет избежать использования «pass by reference». в целом. – C Perkins 23 December 2016 в 20:15
  1. переменная примитивного типа, такая как строка, число всегда передается как пропуск по значению.
  2. Массив и объект передаются как проход по ссылке или передаются по значению на основе этих двух условий. если вы изменяете значение этого Объекта или массива с новым объектом или массивом, то оно передается по значению. object1 = {item: "car"}; array1=[1,2,3]; здесь вы назначаете новый объект или массив старым. Вы не меняете значение свойства старого объекта. Так что это пропуск по значению. если вы изменяете значение свойства объекта или массива, то оно передается по ссылке. object1.key1= "car"; array1[0]=9; здесь вы меняете значение свойства старого объекта. Вы не назначаете новый объект или массив старым. Также он передается по ссылке.

Код

    function passVar(object1, object2, number1) {

        object1.key1= "laptop";
        object2 = {
            key2: "computer"
        };
        number1 = number1 + 1;
    }

    var object1 = {
        key1: "car"
    };
    var object2 = {
        key2: "bike"
    };
    var number1 = 10;

    passVar(object1, object2, number1);
    console.log(object1.key1);
    console.log(object2.key2);
    console.log(number1);

Output: -
    laptop
    bike
    10
-2
ответ дан Mukund Kumar 16 August 2018 в 00:53
поделиться
  • 1
    Оператор присваивания не следует путать с вызовом функции. Когда вы назначаете новые данные существующей переменной, счетчик ссылок старых данных уменьшается, а новые данные связаны со старой переменной. В основном, переменная заканчивается тем, что указывает на новые данные. То же самое относится к переменным свойства. Поскольку эти присвоения не являются функциональными вызовами, они не имеют ничего общего с передачей по значению или передачей по ссылке. – John Sonderson 29 October 2014 в 12:45
  • 2
    Нет, все всегда передается по значению. Это зависит от того, что вы проходите (значение или ссылка). См. это . – Scott Marcus 5 April 2018 в 17:28

На языке низкого уровня, если вы хотите передать переменную по ссылке, вы должны использовать определенный синтаксис при создании функции:

int myAge = 14;
increaseAgeByRef(myAge);
function increaseAgeByRef(int &age) {
  *age = *age + 1;
}

&age является ссылкой на myAge, но если вам нужно значение, которое вы должны преобразовать ссылку, используйте *age.

Javascript - это язык высокого уровня, который делает это преобразование для вас. Таким образом, хотя объекты передаются по ссылке, язык преобразует ссылочный параметр в значение. Вам не нужно использовать & в определении функции, чтобы передать его по ссылке, а не *, в тело функции, чтобы преобразовать ссылку на значение, JS делает это для вас.

Поэтому, когда вы пытаетесь изменить объект внутри функции, заменив его значение (т.е. age = {value:5}), это изменение не сохраняется, но если вы измените его свойства (например, age.value = 5), , он делает.

Подробнее

2
ответ дан Narayon 16 August 2018 в 00:53
поделиться

Простые значения внутри функций не изменят эти значения вне функции (они передаются по значению), тогда как сложные (будут переданы по ссылке).

function willNotChange(x) {

x = 1;

}

var x = 1000;

willNotChange(x);

document.write('After function call, x = ' + x + '<br>'); //still 1000

function willChange(y) {

y.num = 2;

}

var y = {num: 2000}; 

willChange(y);
document.write('After function call y.num = ' + y.num + '<br>'); //now 2, not 2000
-3
ответ дан Olivera Kovacevic 16 August 2018 в 00:53
поделиться
  • 1
    это смешно, y изменится из-за функционального уровня, он будет поднят не потому, что он передается по ссылке. – Parijat Kalia 10 November 2015 в 20:02
  • 2
    Нет, все всегда передается по значению. Это зависит от того, что вы проходите (значение или ссылка). См. это . – Scott Marcus 5 April 2018 в 17:25

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

Вот пример, передающий число (примитивный тип)

function changePrimitive(val) {
    // At this point there are two '10's in memory.
    // Changing one won't affect the other
    val = val * 10;
}
var x = 10;
changePrimitive(x);
// x === 10

Повторение этого с объектом дает разные результаты:

function changeObject(obj) {
    // At this point there are two references (x and obj) in memory,
    // but these both point to the same object.
    // changing the object will change the underlying object that
    // x and obj both hold a reference to.
    obj.val = obj.val * 10;
}
var x = { val: 10 };
changeObject(x);
// x === { val: 100 }

One еще пример:

function changeObject(obj) {
    // Again there are two references (x and obj) in memory,
    // these both point to the same object.
    // now we create a completely new object and assign it.
    // obj's reference now points to the new object.
    // x's reference doesn't change.
    obj = { val: 100 };
}
var x = { val: 10 };
changeObject(x);
// x === { val: 10}
17
ответ дан Phil Mander 16 August 2018 в 00:53
поделиться

JavaScript передает примитивные типы по значениям и типам объектов по ссылке

Теперь люди любят бесконечно препираться о том, является ли «пройти по ссылке» правильным способом описать, что такое Java et al. действительно делаю. Дело в том, что:

  1. Передача объекта не копирует объект.
  2. Объект, переданный функции, может иметь свои члены, модифицированные функцией.
  3. Первичное значение, переданное функции, не может быть изменено функцией. Копия сделана.

В моей книге это называется передачей по ссылке.

- Брайан Би - Какие языки программирования проходят по ссылке?

0
ответ дан Quentin 16 August 2018 в 00:53
поделиться

Мои 2 цента ... Я так понимаю. (Не стесняйтесь исправить меня, если я ошибаюсь)

Пришло время выбросить все, что вы знаете о прохождении по значению / ссылке.

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

Хорошо, позвольте мне изо всех сил объяснить, что я имею в виду. Допустим, у вас есть несколько объектов.

var object1 = {};
var object2 = {};

То, что мы сделали, это «назначение» ... Мы назначили 2 отдельных пустых объекта для переменных «object1» и «object2».

Теперь скажем, что нам нравится object1 лучше ... Итак, мы «назначаем» новую переменную.

var favoriteObject = object1;

Далее, по какой-то причине мы решили, что нам нравится объект 2 лучше. Итак, мы просто немного переустановили.

favoriteObject = object2;

Ничего не случилось с object1 или object2. Мы вообще ничего не изменили. Все, что мы сделали, было переназначением того, что наш любимый объект. Важно знать, что объекты object2 и favoriteObject назначаются одному и тому же объекту. Мы можем изменить этот объект с помощью любой из этих переменных.

object2.name = 'Fred';
console.log(favoriteObject.name) // logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // logs Joe 

OK, теперь давайте посмотрим на примитивы, такие как строки, например

var string1 = 'Hello world';
var string2 = 'Goodbye world';

Опять же, мы выбираем любимую.

var favoriteString = string1;

Обе наши переменные favoriteString и string1 присваиваются «Hello world». Теперь, что, если мы хотим изменить наш любимыйString ??? Что произойдет ???

favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'

Э-э ... Что случилось. Мы не можем изменить string1, изменив функцию favoriteString ... Почему? потому что строки неизменяемы, и мы не мутировали их. Все, что мы сделали, это «RE ASSIGN» favoriteString для новой строки. Это существенно отключило его от string1. В предыдущем примере, когда мы переименовали наш объект, мы ничего не назначали. (Ну, на самом деле ... мы это сделали, мы присвоили свойство name новой строке.) Вместо этого мы просто мутировали объект, который поддерживает связи между двумя переменными и базовыми объектами.

Теперь, на функции и параметры передачи .... Когда вы вызываете функцию и передаете параметр, то, что вы по существу делаете, это «назначение» новой переменной, и она работает точно так же, как если бы вы просто назначили использование равного ( =).

Возьмем эти примеры.

var myString = 'hello';

// Assign to a new variable (just like when you pass to a function)
var param1 = myString; 
param1 = 'world'; // Re assignment

console.log(myString); // logs 'hello'
console.log(param1);   // logs 'world'

Теперь то же самое, но с функцией

function myFunc(param1) {
    param1 = 'world';

    console.log(param1);   // logs 'world'
}

var myString = 'hello';
// Calls myFunc and assigns param1 to myString just like param1 = myString
myFunc(myString); 

console.log(myString); // logs 'hello'

OK, теперь давайте несколько примеров с использованием объектов вместо этого ... во-первых, без функции.

var myObject = {
    firstName: 'Joe',
    lastName: 'Smith'
};

// Assign to a new variable (just like when you pass to a function)
var otherObj = myObject;

// Let's mutate our object
otherObj.firstName = 'Sue'; // I guess Joe decided to be a girl

console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Sue'

// Now, let's reassign
otherObj = {
    firstName: 'Jack',
    lastName: 'Frost'
};

// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object no longer mutates the other
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Jack';

Теперь то же самое, но с вызовом функции

function myFunc(otherObj) {

    // Let's mutate our object
    otherObj.firstName = 'Sue';
    console.log(otherObj.firstName); // Logs 'Sue'

    // Now let's re-assign
    otherObj = {
        firstName: 'Jack',
        lastName: 'Frost'
    };
    console.log(otherObj.firstName); // Logs 'Jack'

    // Again, otherObj and myObject are assigned to 2 very different objects
    // And mutating one object no longer mutates the other
}

var myObject = {
    firstName: 'Joe',
    lastName: 'Smith'
};

// Calls myFunc and assigns otherObj to myObject just like otherObj = myObject
myFunc(myObject);

console.log(myObject.firstName); // Logs 'Sue', just like before

OK, если вы прочитайте весь этот пост, возможно, теперь у вас есть лучшее понимание того, как вызовы функций работают в javascript. Не имеет значения, передается ли что-то по ссылке или по значению ... Что важно, так это назначение vs mutation.

Каждый раз, когда вы передаете переменную функции, вы «назначаете» любое имя переменной параметра, как если бы вы использовали знак равенства (=).

Всегда помните, что знак равенства (=) означает назначение. Всегда помните, что передача параметра функции также означает назначение. Они одинаковы, и 2 переменные связаны точно так же.

Единственный раз, когда изменение переменной влияет на другую переменную, - это когда основной объект мутирован.

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

Единственный gotcha - это когда имя переменной, которую вы передаете в функцию, совпадает с именем параметра функции. Когда это происходит, вы должны обрабатывать параметр внутри функции, как если бы это была целая новая переменная, закрытая для функции (потому что это так)

function myFunc(myString) {
    // myString is private and does not affect the outer variable
    myString = 'hello';
}

var myString = 'test';
myString = myString; // Does nothing, myString is still 'test';

myFunc(myString);
console.log(myString); // logs 'test'
84
ответ дан Rahul R. 16 August 2018 в 00:53
поделиться
  • 1
    @Rimbuaj - У меня действительно есть блог. Сейчас я все равно. Один из них содержит обсуждения по кодированию. Я только что опубликовал свой первый пост о кодировании. constalink.com/blog – Ray Perea 11 February 2015 в 09:37
  • 2
    Для любых программистов на C, подумайте о char *. foo(char *a){a="hello";} ничего не делает, но если вы делаете foo(char *a){a[0]='h';a[1]='i';a[2]=0;}, это изменяется вне, потому что a - это ячейка памяти, переданная по значению, которая ссылается на строку (массив символов). Передача структур (подобно объектам js) по значению в C разрешена, но не рекомендуется. JavaScript просто применяет эти лучшие практики и скрывает ненужные и обычно нежелательные трещины ... и это, безусловно, облегчает чтение. – technosaurus 26 March 2015 в 10:49
  • 3
    Это правильно - термины pass-by-value и pass-by-reference имеют значения в дизайне языка программирования, и эти значения не имеют ничего общего с мутацией объекта , Это все о том, как работают параметры функции. – Pointy 28 November 2015 в 00:52
  • 4
    Теперь, когда я понимаю, что obj1 = obj2 означает, что оба obj1 и obj2 теперь указывают на одно и то же место ссылки, и если я изменяю внутренние элементы obj2, ссылка на obj1 будет выставлять одни и те же внутренние элементы. Как скопировать объект таким образом, что, когда я source = { "id":"1"}; copy = source /*this is wrong*/; copy.id="2", этот источник все еще {& quot; id & quot;: & quot; 1 & quot;}? – Machtyn 22 February 2016 в 21:23
  • 5
    Я добавил еще один ответ с традиционными определениями, чтобы надеяться уменьшить путаницу. Традиционные определения "pass-by-value" и "pass-by-reference" были определены в день указателей памяти перед автоматическим разыменованием. Было совершенно понятно, что значение переменной объекта фактически было местоположением указателя памяти, а не объектом. Несмотря на то, что ваше обсуждение выбора и мутации, возможно, полезно, нет необходимости выкидывать традиционные термины или их определения. Мутация, назначение, пропускная способность, передача по ссылке и т. Д. Не должны противоречить друг другу. – C Perkins 30 May 2017 в 19:36

Легкий способ определить, является ли что-то «пройденным по ссылке», можно ли написать функцию «своп». Например, в C вы можете сделать:

void swap(int *i, int *j)
{
    int t;
    t = *i;
    *i = *j;
    *j = t;
}

Если вы не можете сделать эквивалент этого в Javascript, это не «передать по ссылке».

0
ответ дан Ross 16 August 2018 в 00:53
поделиться
  • 1
    Это действительно не проходит по ссылке. Вы передаете указатели в функцию, и эти указатели передаются по значению. Лучшим примером может служить C ++ и amp; оператора или C # '' ref ' ключевое слово, оба действительно проходят по ссылке. – Matt Greer 26 April 2010 в 20:35
  • 2
    Еще проще, что все передается по значению в JavaScript. – Scott Marcus 5 April 2018 в 17:21
  • 3
    [Д0] stackoverflow.com/questions/42045586/… – Scott Marcus 5 April 2018 в 17:21

Переменная не «удерживает» объект, он содержит ссылку. Вы можете назначить эту ссылку другой переменной, теперь оба ссылаются на один и тот же объект. Он всегда проходит по значению (даже если это значение является ссылкой ...).

Невозможно изменить значение, удерживаемое переменной, переданной как параметр, что было бы возможно, если бы JS поддерживала передачу по ссылке.

132
ответ дан Shog9 16 August 2018 в 00:53
поделиться
  • 1
    Меня это немного смущает. Не передается ли ссылка по ссылке? – user 2 October 2017 в 13:13
  • 2
    Автор имеет в виду, что, передавая ссылку, вы передаете значение ссылки (другой способ думать о его прохождении значения адреса памяти). Поэтому, если вы обновляете объект, оригинал не изменяется, потому что вы создаете новый объект в другом месте памяти. Если вы измените свойство, исходный объект изменится, потому что вы изменили его в исходной ячейке памяти (которая не была переназначена). – Huy-Anh Hoang 10 October 2017 в 21:09

Я читал эти ответы несколько раз, но НЕ ДЕЙСТВИТЕЛЬНО добирался до тех пор, пока не узнал о техническом определении «Вызов путем совместного использования» , как это называется Барбарой Лисков

< blockquote>

Семантика вызова путем совместного использования отличается от вызова по ссылке в том, что назначения для аргументов функции внутри функции не отображаются вызывающему (в отличие от ссылочной семантики) [например, если переменная была передана, невозможно смоделировать присвоение этой переменной в области вызывающего. Однако, поскольку функция имеет доступ к тому же объекту, что и вызывающий (без копирования), мутации для этих объектов, если объекты изменяемы, внутри функции видны вызывающему, которые могут отличаться от вызова по значению семантика. Мутации изменяемого объекта внутри функции видны вызывающему, потому что объект не копируется и не клонируется - он является общим.

То есть, ссылки на параметры изменяются, если вы идете и получаете доступ к самого параметра. С другой стороны, назначение параметра исчезает после оценки и не доступно для вызывающего функции.

2
ответ дан steviejay 16 August 2018 в 00:53
поделиться
  • 1
    Нет, не изменен ли объект или нет, это не проблема. Все всегда передается по значению. Это зависит от того, что вы проходите (значение или ссылка). См. это . – Scott Marcus 5 April 2018 в 17:33

Он всегда проходит по значению, но для объектов значение переменной является ссылкой. Из-за этого, когда вы передаете объект и меняете его членов , эти изменения сохраняются вне функции. Это делает выглядеть как пропуск по ссылке. Но если вы действительно измените значение переменной объекта, вы увидите, что это изменение не сохраняется, доказывая, что оно действительно передается по значению.

Пример:

function changeObject(x) {
  x = {member:"bar"};
  alert("in changeObject: " + x.member);
}

function changeMember(x) {
  x.member = "bar";
  alert("in changeMember: " + x.member);
}

var x = {member:"foo"};

alert("before changeObject: " + x.member);
changeObject(x);
alert("after changeObject: " + x.member); /* change did not persist */

alert("before changeMember: " + x.member);
changeMember(x);
alert("after changeMember: " + x.member); /* change persists */

Выход:

before changeObject: foo
in changeObject: bar
after changeObject: foo

before changeMember: foo
in changeMember: bar
after changeMember: bar
376
ответ дан Tim Goodman 16 August 2018 в 00:53
поделиться
  • 1
    @daylight: Вообще-то, вы ошибаетесь; если он был передан командой const ref, чтобы попытаться сделать changeObject, это приведет к ошибке, а не просто к сбою. Попробуйте присвоить новое значение константной ссылке в C ++, и компилятор отклонит ее. В пользовательских терминах это разница между передачей по значению и передачей по ссылке const. – deworde 18 July 2011 в 09:56
  • 2
    @daylight: Это не константа ref. В changeObject я изменил x, чтобы содержать ссылку на новый объект. x = {member:"bar"}; эквивалентно x = new Object(); x.member = "bar"; То, что я говорю, также относится и к C #. – Tim Goodman 19 July 2011 в 22:47
  • 3
    @daylight: для C # вы можете видеть это извне функции, если вы используете ключевое слово ref, вы можете передать ссылку по ссылке (вместо значения по умолчанию для передачи ссылки по значению), а затем изменить на пункт a new Object() будет сохраняться. – Tim Goodman 19 July 2011 в 22:55
  • 4
    @adityamenon Трудно ответить «почему», но я хотел бы отметить, что дизайнеры Java и C # сделали аналогичный выбор; это не просто странность JavaScript. На самом деле, он очень последовательно передается по значению, то, что делает его запутанным для людей, заключается в том, что значение может быть ссылкой. Это не сильно отличается от передачи указателя вокруг (по значению) на C ++, а затем разыменования его для установки членов. Никто не удивится, что это изменение сохранится. Но поскольку эти языки абстрагируют указатель и молча делают разыменование для вас, люди путаются. – Tim Goodman 28 July 2013 в 12:11
  • 5
    Другими словами, запутанная вещь здесь не является передачей по значению / передачей по ссылке. Все проходит по значению, полная остановка. Путаница заключается в том, что вы не можете передать объект и не можете хранить объект в переменной. Каждый раз, когда вы думаете , вы делаете это, вы фактически передаете или сохраняете ссылку на этот объект. Но когда вы идете к доступу к своим членам, происходит молчаливое разыменование, которое увековечивает фикцию о том, что ваша переменная удерживает фактический объект. – Tim Goodman 28 July 2013 в 12:27
  1. Примитивы (Number, Boolean) передаются по значению. Строки неизменяемы, поэтому для них это не имеет особого значения.
  2. Объекты передаются по ссылке (ссылка передается по значению)
-1
ответ дан uriz 16 August 2018 в 00:53
поделиться
  • 1
    Нет, все всегда передается по значению. Это зависит от того, что вы проходите (значение или ссылка). См. это . – Scott Marcus 5 April 2018 в 17:25

Примитивы передаются по значению, а объекты передаются по ссылке. Это сильно отличается от других языков, таких как C, VB или Delphi. Я не могу сказать, как они точно обрабатывают объекты и примитивы, но я знаю VB и Delphi, что он может (и должен) быть указан.

php делает что-то подобное с версии 5: все объекты передаются но все примитивы могут быть переданы по ссылке, если предшествует амперсанд (& amp;). В противном случае примитивы передаются по значению.

Итак, в javascript, если передать объект X в функцию через параметр, он все равно будет X. Если вы меняете данные внутри функция (или любой другой объект, но это не важно), что новое значение также доступно вне функции.

-4
ответ дан user 16 August 2018 в 00:53
поделиться
  • 1
    «что новое значение также доступно вне функции», Это неверно. См. jsfiddle.net/rdarc Значение не изменяется, вместо этого ссылка изменяется. – Tom 29 August 2011 в 12:13
  • 2
    @Tom, изменение вашего кода на var x = {hi : 'hi'}; change(x); console.log(x.hi); function change(x) { x.hi = 'changed'; } изменяет поведение. – Olgun Kaya 6 September 2017 в 09:01
  • 3
    [Д0] stackoverflow.com/questions/42045586/… – Scott Marcus 5 April 2018 в 17:21

разделяет то, что я знаю о ссылках в javascript

В Javascript объекты хранятся в виде ссылок:

var a = {
  a: 1,
  b: 2,
  c: 3
};
var b = a;

//b.c is referencing to a.c value
console.log(b.c) //output: 3
//changing value of b.c
b.c = 4
//also changes the value of a.c
console.log(a.c) //output: 4

1
ответ дан Victor 16 August 2018 в 00:53
поделиться
  • 1
    Это слишком упрощенный ответ, который ничего не говорит о том, что более ранние ответы не объяснили лучше. Я смущен тем, почему вы вызываете массивы как особый случай. – Quentin 10 August 2017 в 12:48

В JavaScript тип значения исключительно определяет, будет ли это значение присвоено копией значения или копией-копией.

Примитивные значения всегда назначаются / передаются с помощью copy-копии :

  • null
  • undefined
  • string
  • number
  • boolean
  • символ в ES6

Соединение значения всегда назначаются / передаются с помощью reference-copy

  • объектов
  • массивов
  • function

Например

var a = 2;
var b = a; // `b` is always a copy of the value in `a`
b++;
a; // 2
b; // 3

var c = [1,2,3];
var d = c; // `d` is a reference to the shared `[1,2,3]` value
d.push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]

В приведенном выше фрагменте, поскольку 2 является скалярным примитивом, a содержит одну начальную копию этого значения, а b присваивается другая копия значения , При изменении b вы никоим образом не изменяете значение в a.

Но оба c и d являются отдельными ссылками на одно и то же общее значение [1,2,3], которое является составная величина. Важно отметить, что ни c, ни d больше не «владеют» значением [1,2,3] - оба равны равным равноправным ссылкам на значение. Таким образом, при использовании любой ссылки для изменения (.push(4)) фактического общего значения array, это влияет только на одно общее значение, и обе ссылки будут ссылаться на вновь измененное значение [1,2,3,4].

var a = [1,2,3];
var b = a;
a; // [1,2,3]
b; // [1,2,3]

// later
b = [4,5,6];
a; // [1,2,3]
b; // [4,5,6]

Когда мы выполняем присваивание b = [4,5,6], мы ничего не делаем, чтобы повлиять на a, где [1,2,3] все еще ссылается. Для этого b должен быть указателем на a, а не ссылкой на array, но в JS нет такой возможности

function foo(x) {
    x.push( 4 );
    x; // [1,2,3,4]

    // later
    x = [4,5,6];
    x.push( 7 );
    x; // [4,5,6,7]
}

var a = [1,2,3];

foo( a );

a; // [1,2,3,4]  not  [4,5,6,7]

Когда мы проходим аргумент a, он присваивает копию ссылки a на x. x и a - отдельные ссылки, указывающие на то же значение [1,2,3]. Теперь внутри функции мы можем использовать эту ссылку для мутации самого значения (push(4)). Но когда мы выполняем присваивание x = [4,5,6], это никоим образом не влияет на то, где указывается начальная ссылка a, - все еще указывает на значение (теперь измененное) [1,2,3,4].

Чтобы эффективно пройти составное значение (например, array) по копированию значения, вам нужно вручную сделать его копию, чтобы переданная ссылка не все еще указывала на оригинал. Например:

foo( a.slice() );

Составное значение (объект, массив и т. Д.), Которое может быть передано посредством reference-copy

function foo(wrapper) {
    wrapper.a = 42;
}

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

Здесь obj действует как обертка для скалярное примитивное свойство a. Когда передано foo(..), копия ссылки obj передается и устанавливается в параметр wrapper. Теперь мы можем использовать ссылку wrapper для доступа к общему объекту и обновить его свойство. После завершения функции obj.a вы увидите обновленное значение 42.

Источник

12
ответ дан zangw 16 August 2018 в 00:53
поделиться
  • 1
    Вы сначала указываете, что «составные значения всегда назначаются / передаются посредством копии-копии», а затем вы указываете «присваиваете копию ссылки на x». В случае того, что вы называете «составным значением», фактическое значение переменной IS является ссылкой (то есть указателем памяти). Так же, как вы объяснили, ссылка копируется ... поэтому значения переменных копируются , снова подчеркивая, что ССЫЛКА - ЗНАЧЕНИЕ. Это означает, что JavaScript является сквозной для всех типов. Передача по значению означает передачу копии значения переменных. Не имеет значения, что значение является ссылкой на объект / массив. – C Perkins 30 May 2017 в 19:11
  • 2
    Вы вводите новую терминологию (value-copy / reference-copy), и это только усложняет ситуацию. Есть только копии, период. Если вы передадите примитив, вы передали копию фактических примитивных данных, если вы передадите объект, вы передали копию местоположения памяти объекта. Это все, что вам нужно сказать. Все, что еще более смущает людей. – Scott Marcus 5 April 2018 в 17:32
0
ответ дан morteza ataiy 6 September 2018 в 00:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: