Является ли JavaScript языком передачи по ссылке или передачей по значению?


1405

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

Хотя в конце это не имеет большого значения, я хочу знать, как правильно представлять аргументы, передавая соглашения. Есть ли выдержка из спецификации JavaScript, которая определяет, какой должна быть семантика в отношении этого?


2
Я думаю, что вы случайно перевернули определения «передано по значению и передано по ссылке ...» передано по значению (в случае, если мы считаем, что переменная, содержащая объект, на самом деле является ссылкой на объект) и передано по ссылке (когда мы считаем, что переменная объекта содержит сам объект) "
Нико Беллик

5
Да. Независимо от синтаксиса, при любом вызове функции на любом языке программирования передача по ссылке означает, что данные, связанные с переданной переменной, не копируются при передаче в функцию, и, таким образом, любые изменения, сделанные функцией переданной переменной, будут сохранены. в программе после завершения вызова функции. Передача по значению означает, что данные, связанные с переменной, фактически копируются при передаче в функцию, и любые изменения, внесенные такой функцией в такую ​​переменную, будут потеряны, когда переменная выйдет из области видимости тела функции, когда функция вернется.
Джон Сондерсон

5
Этот старый вопрос несколько токсичен, потому что его в значительной степени неправильный ответ. JavaScript строго передается по значению .
Заостренный

6
@DanailNachev К сожалению, терминология сбивает с толку. Дело в том, что термины «передача по значению» и «передача по ссылке» предшествуют многим более современным функциям языка программирования. Слова «значение» и «ссылка» относятся конкретно к параметру, как он появляется в выражении вызова функции. JavaScript всегда оценивает каждое выражение в списке параметров вызова функции перед вызовом функции, поэтому параметры всегда являются значениями. Смущает то, что ссылки на объекты являются общими значениями JavaScript. Это не делает его языком «передачи по ссылке», однако.
Заостренный

2
@DanailNachev «передать по ссылке», в частности, означает, что если у вас есть, var x=3, y=x; f(x); alert(y === x);то функция f()может сделать отчет о предупреждении, falseа не true. В JavaScript это невозможно, поэтому это не передача по ссылке. Хорошо, что можно передавать ссылки на изменяемые объекты, но это не то, что означает «передача по ссылке». Как я уже сказал, это позор, что терминология настолько запутанная.
Заостренный

Ответы:


1599

Это интересно в 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бы это вообще не было ссылкой, то изменение obj1.itemне повлияло бы на obj1внешние функции.
  • Если бы аргумент был правильной ссылкой, то все бы изменилось. numбыло бы 100и obj2.itemбудет читать "changed".

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

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


32
Это точно так же (или, по крайней мере, семантически), как C #. Объект имеет два типа: Value (примитивные типы) и Reference.
Питер Ли

53
Я думаю, что это также используется в Java: ссылка по значению.
2012 года

297
настоящая причина в том, что внутри changeStuff ссылки num, obj1 и obj2. Когда вы изменяете itemсвойство объекта, на который ссылается obj1, вы меняете значение свойства элемента, которое изначально было установлено как «неизменное». Когда вы присваиваете obj2 значение {item: "ified "}, вы меняете ссылку на новый объект (который сразу выходит из области видимости при выходе из функции). Становится более очевидным, что происходит, если вы называете функцию params такими вещами, как numf, obj1f и obj2f. Затем вы видите, что параметры скрывали внешние имена переменных.
jinglesthula

13
@BartoNaz Не совсем. Вам нужно передать ссылку по ссылке, а не передавать ее по значению. Но JavaScript всегда передает ссылку по значению, как и все остальное по значению. (Для сравнения, C # имеет поведение передачи по ссылке по значению, аналогичное JavaScript и Java, но позволяет вам указать передачу по ссылке с помощью refключевого слова.) Обычно вам просто нужно, чтобы функция вернула новый объект, и выполните назначение в точке, где вы вызываете функцию. Например, foo = GetNewFoo();вместоGetNewFoo(foo);
Тим Гудман

56
Хотя этот ответ является самым популярным, он может слегка сбить с толку, поскольку в нем говорится «Если бы это был чистый проход по значению». JavaScript является чистой передачей по значению. Но переданное значение является ссылкой. Это не ограничивается передачей параметров вообще. Вы можете просто скопировать переменную var obj1 = { item: 'unchanged' }; var obj2 = obj1; obj2.item = 'changed';и наблюдать такой же эффект, как в вашем примере. Поэтому я лично отсылаю ответ Тима Гудмана
chiccodoro

476

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

Пример:

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

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

var x = { member: "foo" };

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

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

Вывод:

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

before changeMember: foo
in changeMember: bar
after changeMember: bar

14
@ Daylight: На самом деле, вы не правы; если он был передан const ref, попытка сделать changeObject вызовет ошибку, а не просто потерпит неудачу. Попробуйте назначить новое значение константной ссылке в C ++, и компилятор отклонит его. С точки зрения пользователя, это разница между передачей по значению и передачей по константной ссылке.
deworde

5
@ Daylight: это не постоянный реф. В changeObject, я изменил, xчтобы содержать ссылку на новый объект. x = {member:"bar"};эквивалентно , x = new Object(); x.member = "bar"; что я говорю это также верно C #, кстати.
Тим Гудман

2
@daylight: для C # вы можете увидеть это снаружи функции; если вы используете refключевое слово, вы можете передать ссылку по ссылке (вместо передачи по умолчанию ссылки по значению), а затем изменение, указывающее на a new Object() , сохранится. ,
Тим Гудман

11
@adityamenon Трудно ответить «почему», но я хотел бы отметить, что разработчики Java и C # сделали аналогичный выбор; это не просто какая-то странность JavaScript. На самом деле, это очень последовательная передача по значению, вещь, которая делает его запутанным для людей, состоит в том, что значение может быть ссылкой. Это не сильно отличается от передачи указателя (по значению) в C ++ с последующим разыменованием его для установки членов. Никто не удивится, что это изменение сохраняется. Но поскольку эти языки отвлекают указатель и молча выполняют разыменование для вас, люди запутываются.
Тим Гудман

41
Другими словами, запутанная вещь здесь не является передачей по значению / передачей по ссылке. Все передается по значению, полная остановка. Смущает то, что вы не можете передать объект и не можете сохранить объект в переменной. Каждый раз, когда вы думаете , что делаете это, вы фактически передаете или сохраняете ссылку на этот объект. Но когда вы обращаетесь к его членам, происходит тихая разыменование, которое увековечивает выдумку, что ваша переменная содержит фактический объект.
Тим Гудман

150

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

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


2
Это меня немного смущает. Не передается ли ссылка по ссылке?

8
Автор означает, что, передавая ссылку, вы передаете ссылочное значение (другой способ думать об этом - передать значение адреса памяти). Поэтому, если вы переопределите объект, оригинал не изменится, потому что вы создаете новый объект в другом месте памяти. Если вы изменяете свойство, оригинальный объект изменяется, потому что вы изменили его в исходной ячейке памяти (которая не была переназначена).
Хай-Ан Хоанг

113

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

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

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

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

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

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

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

var favoriteObject = object1;

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

favoriteObject = object2;

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

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

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

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

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

var favoriteString = string1;

Обе переменные favouriteString и string1 присвоены «Hello world». А что если мы захотим изменить нашу любимую строку ??? Что случится???

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

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

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

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

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'

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

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 the variable
otherObj = {
    firstName: 'Jack',
    lastName: 'Frost'
};

// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object has no influence on 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 doesn't magically mutate 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

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

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

Всегда помните, что знак равенства (=) означает присваивание. Всегда помните, что передача параметра в функцию в JavaScript также означает присваивание. Они одинаковы, и эти две переменные связаны одинаково (то есть они не связаны, если только вы не считаете, что они назначены одному и тому же объекту).

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

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

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

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'

2
Любой программист на C думает о char *. foo(char *a){a="hello";} ничего не делает, но если вы это сделаете, foo(char *a){a[0]='h';a[1]='i';a[2]=0;}это будет изменено снаружи, потому что aэто область памяти, переданная по значению, которое ссылается на строку (массив символов). Передача структур (аналогично объектам js) по значению в C допускается, но не рекомендуется. JavaScript просто применяет эти лучшие практики и скрывает ненужные и, как правило, нежелательные излишества ... и, несомненно, облегчает чтение.
технозавр

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

2
Теперь, когда я понимаю, что obj1 = obj2 означает, что и obj1, и obj2 теперь указывают на одно и то же ссылочное местоположение, и если я изменю внутреннюю часть obj2, ссылка на obj1 предоставит одинаковые внутренние компоненты. Как мне скопировать объект таким образом, чтобы при выполнении source = { "id":"1"}; copy = source /*this is wrong*/; copy.id="2"этого источника все еще {"id": "1"}?
Machtyn

1
Я опубликовал еще один ответ с традиционными определениями, чтобы надеяться уменьшить путаницу. Традиционные определения «передача по значению» и «передача по ссылке» были определены еще во времена указателей памяти перед автоматической разыменовкой. Было совершенно ясно, что значение переменной объекта на самом деле является указателем в памяти, а не объектом. Хотя ваше обсуждение «назначение против мутации», возможно, полезно, нет необходимости отбрасывать традиционные термины или их определения. Мутация, присваивание, передача по значению, передача по ссылке и т. Д. Не должны противоречить друг другу.
С Перкинс

«Число» тоже «неизменный»?
Эбрам Халил

72

Учтите следующее:

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

Итак, забудьте о «передаче по ссылке / значению» , не зацикливайтесь на «передаче по ссылке / значению», потому что:

  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

Дополнительные вопросы для дополнительного кредита;) Как работает сбор мусора? Если я прокручиваю переменную по миллиону {'George', 1}значений, но использую только одно из них одновременно, то как управляются остальные? И что происходит, когда я назначаю переменную значению другой переменной? Затем я указываю на указатель или указываю на правый операнд? В var myExistingVar = {"blah", 42}; var obj = myExistingVar;результате objуказывает на {"blah", 42}или myExistingVar?
Майкл Хоффманн

@MichaelHoffmann Они заслуживают своих собственных вопросов SO и, вероятно, уже ответили лучше, чем я могу управлять. При этом 1)я запустил профиль памяти в инструментах разработчика браузера для функции цикла, такой как описанная вами, и увидел скачки в использовании памяти на протяжении всего цикла. Казалось бы, это указывает на то, что новые идентичные объекты действительно создаются на каждой итерации цикла. Когда шипы внезапно падают, сборщик мусора просто очищает группу от этих неиспользуемых объектов.
ГЕГ

1
@MichaelHoffmann 2)Что касается чего-то подобного var a = b, javascript не предоставляет механизм для использования указателей, и поэтому переменная никогда не может указывать на указатель (как вы можете в C), хотя базовый движок javascript, несомненно, использует их. Так что ... var a = bукажут a«к pointee правого операнда»
гэг

Я задал вопрос № 1 здесь (в частности, о Chrome, потому что реализация, вероятно, отличается в каждом браузере) stackoverflow.com/q/42778439/539997, и я все еще пытаюсь придумать, как сформулировать вопрос № 2. Любая помощь приветствуется.
Майкл Хоффманн

1
Не нужно забывать о «передаче по ссылке / значению» ! Эти термины имеют историческое значение, которое описывает именно то, что вы пытаетесь описать. Если мы отбрасываем исторические термины и определения и становимся слишком ленивыми, чтобы понять, что они изначально имели в виду, тогда мы теряем способность эффективно общаться между поколениями. Не было бы хорошего способа обсудить различия между разными языками и системами. Вместо этого начинающим программистам необходимо изучить и понять традиционные термины, а также причины и причины их появления. В противном случае мы все вместе теряем знания и понимание.
С Перкинс

24

Объект вне функции передается в функцию путем предоставления ссылки на внешний объект.

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


20

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

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

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 }

Еще один пример:

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}

19

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

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

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

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

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


Вау, это невероятно запутанно. Кто в здравом уме определит устоявшийся термин для обозначения полной противоположности и затем использует его таким образом? Неудивительно, что так много ответов здесь на этот вопрос так запутаны.
Йорг Миттаг

16

JavaScript всегда передается по значению ; все имеет значение типа.

Объекты являются значениями, а функции-члены объектов сами являются значениями (помните, что функции являются первоклассными объектами в JavaScript). Кроме того, относительно концепции, что все в JavaScript является объектом ; это не верно. Строки, символы, числа, логические значения, значения NULL и неопределенные значения являются примитивами .

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

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

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


12
-1, оно не всегда передается по значению. Из MDC: «Если вы передаете объект (то есть не примитивное значение, такое как Array или определенный пользователем объект) в качестве параметра, ссылка на объект передается функции».
Ник

37
@ Ник: Это всегда передается по значению. Период. Ссылка на объект передается по значению функции. Это не проходит по ссылке. «Передача по ссылке» почти может рассматриваться как передача самой переменной, а не ее значения; любые изменения, которые функция вносит в аргумент (включая его полную замену другим объектом!), будут отражены в вызывающей программе. Этот последний бит невозможен в JS, потому что JS не передается по ссылке - он передает ссылки по значению. Различие тонкое, но довольно важно для понимания его ограничений.
Чао

1
Для будущих укладчиков ... Об этой ссылке: x = "teste"; x.foo = 12;и т. Д. То, что свойство не является постоянным, не означает, что оно не является объектом. Как говорит MDN: в JavaScript почти все является объектом. Все примитивные типы, кроме null и undefined, рассматриваются как объекты. Им могут быть назначены свойства (назначенные свойства некоторых типов не являются постоянными), и они имеют все характеристики объектов. ссылка
slacktracer

9
MDN - это отредактированная пользователем вики, и там она не права. Нормативный справочник - ECMA-262. См. Раздел 8 «Тип спецификации ссылки», в котором объясняется, как разрешаются ссылки, а также 8.12.5 «[[Put]]», который используется для объяснения AssignmentExpression для ссылки, и для приведения объекта 9.9 ToObject. Для примитивных значений Майкл уже объяснил, что делает ToObject, как в спецификации. Но смотрите также с. 4.3.2 примитивная ценность.
Гаррет

1
@WonderLand: нет, он не. Люди, которые никогда не могли передавать по ссылке, могут никогда не понять различий между передачей по ссылке и передачей ссылки по значению. Но они есть, и они имеют значение. Я не хочу дезинформировать людей, потому что это звучит проще.
cHao

12

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

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

  • null
  • undefined
  • строка
  • число
  • логический
  • символ в ES6

Составные значения всегда присваиваются / передаются по ссылке-копии

  • объекты
  • массивы
  • функция

Например

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]значением - оба являются равными равноправными ссылками на значение. Таким образом, при использовании любой ссылки для modify ( .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] значение.

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

foo( a.slice() );

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

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

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

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

Источник


Сначала вы заявляете «Составные значения всегда присваиваются / передаются с помощью reference-copy», а затем вы заявляете «назначает копию ссылки на x». В случае того, что вы называете «составным значением», фактическое значение переменной является ссылкой (то есть указателем памяти). Как вы объяснили, ссылка копируется ... поэтому значение переменной копируется , снова подчеркивая, что ССЫЛКА - ЗНАЧЕНИЕ. Это означает, что JavaScript передается по значению для всех типов. Передача по значению означает передачу копии значения переменной. Неважно, что значение является ссылкой на объект / массив.
С Перкинс

Вы вводите новую терминологию (value-copy / reference-copy), и это только усложняет ситуацию. Есть только копии, точка. Если вы передаете примитив, вы передаете копию фактических данных примитива, если вы передаете объект, вы передаете копию расположения объекта в памяти. Это все, что тебе нужно сказать. Все остальное только еще больше сбивает с толку людей.
Скотт Маркус

9

ну, речь идет о «производительности» и «скорости» и в простом слове «управление памятью» в языке программирования.

в javascript мы можем поместить значения в два слоя: type1 - objectsи type2 - все другие типы значений, такие как string& boolean& etc

если вы представляете память в виде квадратов ниже, в каждом из которых может быть сохранено только одно значение type2:

введите описание изображения здесь

каждое значение type2 (зеленый) - это один квадрат, а значение type1 (синий) - их группа :

введите описание изображения здесь

Дело в том, что если вы хотите указать значение type2, адрес прост, но если вы хотите сделать то же самое для type1-value, это совсем не просто! :

введите описание изображения здесь

и в более сложной истории:

введите описание изображения здесь

так вот ссылки могут спасти нас: введите описание изображения здесь

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

но мы не можем сделать то же самое с фиолетовой стрелкой, мы можем захотеть переместить ячейку «Джон» здесь или много других вещей ... поэтому фиолетовая стрелка будет придерживаться своего места, и только типичные стрелки, которые были назначены ей, будут двигаться ...

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

let arr = [1, 2, 3, 4, 5]; //arr is an object now and a purple arrow is indicating it
let obj2 = arr; // now, obj2 is another purple arrow that is indicating the value of arr obj
let obj3 = ['a', 'b', 'c'];
obj2.push(6); // first pic below - making a new hand for the blue circle to point the 6
//obj2 = [1, 2, 3, 4, 5, 6]
//arr = [1, 2, 3, 4, 5, 6]
//we changed the blue circle object value (type1-value) and due to arr and obj2 are indicating that so both of them changed
obj2 = obj3; //next pic below - changing the direction of obj2 array from blue circle to orange circle so obj2 is no more [1,2,3,4,5,6] and it's no more about changing anything in it but we completely changed its direction and now obj2 is pointing to obj3
//obj2 = ['a', 'b', 'c'];
//obj3 = ['a', 'b', 'c'];

введите описание изображения здесь введите описание изображения здесь


8

Это немного больше объяснения для передачи по значению и передачи по ссылке (JavaScript). В этой концепции они говорят о передаче переменной по ссылке и передаче переменной по ссылке.

Передача по значению (примитивный тип)

var a = 3;
var b = a;

console.log(a); // a = 3
console.log(b); // b = 3

a=4;
console.log(a); // a = 4
console.log(b); // b = 3
  • применяется ко всем примитивным типам в JavaScript (строка, число, логическое значение, неопределенное и нулевое значение).
  • a выделяется память (скажем, 0x001), а b создает копию значения в памяти (скажем, 0x002).
  • Таким образом, изменение значения переменной не влияет на другую, так как они находятся в двух разных местах.

Передача по ссылке (объекты)

var c = { "name" : "john" };
var d = c;

console.log(c); // { "name" : "john" }
console.log(d); // { "name" : "john" }

c.name = "doe";

console.log(c); // { "name" : "doe" }
console.log(d); // { "name" : "doe" }
  • Механизм JavaScript назначает объект переменной c, и он указывает на некоторую память, скажем (0x012).
  • Когда d = c, на этом этапе dуказывается на то же местоположение (0x012).
  • Изменение значения любого изменения значения для обеих переменных.
  • Функции являются объектами

Особый случай, передача по ссылке (объекты)

c = {"name" : "jane"};
console.log(c); // { "name" : "jane" }
console.log(d); // { "name" : "doe" }
  • Оператор равенства (=) устанавливает новое пространство памяти или адрес

В вашем так называемом особом случае выделение пространства памяти вызывает не оператор присваивания, а сам литерал объекта . Обозначение фигурной скобки вызывает создание нового объекта. Для свойства cустанавливается копия ссылки на новый объект.
georgeawg

6

делиться тем, что я знаю о ссылках в 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
Это слишком упрощенный ответ, который ничего не говорит о том, что более ранние ответы не объяснили лучше. Я не понимаю, почему вы вызываете массивы как особый случай.
Квентин,

1
« объекты хранятся в виде ссылок » вводит в заблуждение. Я думаю, что вы имеете в виду, что при назначении объекта переменной значение, присвоенное переменной, является ссылкой на объект.
RobG

это не решает проблему обновления объекта внутри функции, которая не обновляет объект вне функции. Вот и вся картина, где она работает как значения, а не как ссылка. Следовательно -1
Амастер

@amaster Спасибо, что указал на это! Можете ли вы предложить редактирование, пожалуйста?
xameeramir

Ха-ха, я пытался ... предложенное мной изменение изменилось слишком сильно, и не было разрешено
amaster

4

Семантика!! Установка конкретных определений обязательно сделает некоторые ответы и комментарии несовместимыми, поскольку они не описывают одно и то же, даже если используют одни и те же слова и фразы, но крайне важно преодолеть путаницу (особенно для новых программистов).

Прежде всего, существует несколько уровней абстракции, которые, кажется, понимают не все. Новым программистам, которые выучили языки 4-го и 5-го поколений, может быть трудно сосредоточиться на концепциях, знакомых ассемблеру или программистам на C, не ориентированным на указатели на указатели на указатели. Передача по ссылке не просто означает возможность изменения ссылочного объекта с помощью переменной параметра функции.

Переменная : объединенная концепция символа, который ссылается на значение в определенном месте в памяти. Этот термин обычно слишком загружен, чтобы использовать его отдельно при обсуждении деталей.

Символ : текстовая строка, используемая для ссылки на переменную (т.е. имя переменной).

Значение : конкретные биты, хранящиеся в памяти и на которые ссылается символ переменной.

Расположение памяти : где хранится значение переменной. (Само местоположение представлено числом, отдельным от значения, хранящегося в этом месте.)

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

Аргумент функции : переменная вне функции, которая передается функции вызывающей стороной.

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

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

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

Передача по значению или вызов по совместному использованию (для объектов): Значение аргумента функции копируется в другое место в памяти, на которое ссылается символ параметра функции (независимо от того, находится он в стеке или в куче). Другими словами, параметр функции получил копию значения переданного аргумента ... И (критическое) значение аргумента НИКОГДА НЕ ОБНОВЛЯЕТСЯ / ИЗМЕНЕНО / ИЗМЕНЕНО вызывающей функцией. Помните, что значение переменной объекта НЕ является самим объектом, скорее это указатель на объект, поэтому передача переменной объекта по значению копирует указатель на переменную параметра функции. Значение параметра функции указывает на точно такой же объект в памяти. Сами данные объекта могут быть изменены непосредственно через параметр функции, НО значение аргумента функции НИКОГДА НЕ ОБНОВЛЯЕТСЯ, поэтому оно будет продолжать указывать на же самоеобъект во время и даже после вызова функции (даже если данные его объекта были изменены или если параметру функции назначен другой объект в целом). Неверно утверждать, что аргумент функции был передан по ссылке только потому, что указанный объект является обновляемым через переменную параметра функции.

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

JavaScript не передается по ссылке. Если вы внимательно прочитаете, вы поймете, что все противоположные мнения неправильно понимают, что подразумевается под передачей по значению, и они ошибочно заключают, что возможность обновления данных объекта с помощью параметра функции является синонимом «передачи по значению».

Клонирование / копирование объекта. Создается новый объект и копируются данные исходного объекта. Это может быть глубокая или мелкая копия, но дело в том, что создается новый объект. Создание копии объекта является отдельным понятием от передачи по значению. Некоторые языки различают объект класса и структуры (или тому подобное) и могут иметь разное поведение для передачи переменных разных типов. Но JavaScript не делает ничего подобного автоматически при передаче объектных переменных. Но отсутствие автоматического клонирования объектов не означает переход по ссылке.


4

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

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

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

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

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


Обновить

Вот опровержение этого:

В JavaScript нет «передачи по ссылке».


@ Amy Потому что это описание передачи по значению, а не передачи по ссылке. Это хороший ответ, который показывает разницу: stackoverflow.com/a/3638034/3307720
nasch

@nasch Я понимаю разницу. # 1 и # 2 описывают семантику pass-by-ref. № 3 описывает семантику передачи по значению.
Эми

@Amy 1, 2 и 3 все соответствуют передаче по значению. Для передачи по ссылке вам также понадобится 4: присвоение ссылки новому значению внутри функции (с помощью оператора =) также переназначает ссылку за пределы функции. Это не так в случае с Javascript, что делает его исключительно передаваемым по значению. При передаче объекта вы передаете указатель на объект, и вы передаете этот указатель по значению.
nasch

Обычно это не то, что подразумевается под «передачей по ссылке». Вы удовлетворили мой запрос, и я не согласен с вами. Спасибо.
Эми

«В моей книге это называется передачей по ссылке». - В каждой книге компилятора, книге интерпретатора, книге по теории языка программирования и книге по информатике это не так.
Йорг Миттаг

3

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

  • При вызове функции вы передаете содержимое (ссылку или значение) переменных аргумента, а не сами переменные.

    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; 
    }

3

Передача аргументов функции в 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;
}

1
Я не думаю, что это так в JavaScript: `` `javascript var num = 5;
Данаил Начев

@DanailNachev: Хотя технически это может быть правдой, разница заметна только для изменчивых объектов, которых нет у примитивов ECMAScript.
Йорг Миттаг

3

Для программирования языка юристов, я прошел через следующие разделы 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. Пусть propertyNameReference будет результатом вычисления Expression.
  4. Пусть propertyNameValue будет GetValue (propertyNameReference).
  5. Вызовите CheckObjectCoercible (baseValue).
  6. Пусть propertyNameString будет ToString (propertyNameValue).
  7. Если оцениваемая синтаксическая продукция содержится в коде режима строгого режима, то допустим, что строгий будет истинным, иначе пусть строгий будет ложным.
  8. Вернуть значение типа Reference , базовое значение которого равно baseValue, а ссылочное имя - propertyNameString, а флаг строгого режима - строгий.

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

По ссылке

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

Определение понятия "объект"

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


Меня не перестает удивлять то, как много людей смущают различия между аргументами, передаваемыми по значению, аргументами, передаваемыми по ссылке, операциями над целыми объектами и операциями над их свойствами. В 1979 году я не получил степень по информатике, вместо этого я решил добавить 15 часов факультативного обучения по программе CS в свою программу MBA. Тем не менее, вскоре мне стало ясно, что мое понимание этих концепций было, по крайней мере, таким же хорошим, как и у любого из моих коллег, имеющих ученые степени в области компьютерных наук или математики. Изучите Ассемблер, и это станет вполне понятно.
Дэвид А. Грей

3

Документы MDN объясняют это ясно, не будучи слишком многословным:

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

Источник: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Description


1

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

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

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

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

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

Учить больше


1

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

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

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


Нет, проблема в том, является ли объект изменчивым или нет. Все всегда передается по значению. Это зависит только от того, что вы передаете (значение или ссылка). Смотрите это .
Скотт Маркус

То, что она описывает, передает ссылку BY-VALUE. Нет причин вводить новую терминологию.
Санджив

1

В основном самый простой способ

// Copy JS object without reference
var first = {"a":"value1","b":"value2"};
var clone = JSON.parse( JSON.stringify( first ) ); 

var second = ["a","b","c"];
var clone = JSON.parse( JSON.stringify( second ) ); 

JSON.parse( JSON.stringify( obj ) )это ужасный способ глубоко клонировать объекты. Это не только медленно, но и может привести к потере данных.
Д. Пардал

0

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

function replaceOrModify(aObj) {
  if (modify) {

    aObj.setNewValue('foo');

  } else {

   var newObj = new MyObject();
   // _.extend(destination, *sources) 
   _.extend(newObj, aObj);
  }
}

0

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

  • Примитивы : когда вы обращаетесь к примитивному типу, вы работаете непосредственно с его значением

    • строка
    • число
    • логический
    • значение NULL
    • не определено

Например:

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

Я бы сказал, что это мимоходом -

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

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


1
«передача по копии» === передача по значению
Скотт Маркус

-1

Там какая - то дискуссия по поводу использования термина «передать по ссылке» в JavaScript здесь , но ответить на ваш вопрос:

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

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


7
Связанная статья больше не включает в себя эти утверждения и вообще избегает использования «передачи по ссылке».
С Перкинс

Значение является ссылкой

-2

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

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

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


21
Это на самом деле не передать по ссылке. Вы передаете указатели в функцию, и эти указатели передаются по значению. Лучшим примером может служить C ++ & operator или ключевое слово ref в C #, оба они действительно передаются по ссылке.
Мэтт Грир

Еще проще то, что все передается по значению в JavaScript.
Скотт Маркус


-3
  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

1
Оператор присваивания не следует путать с вызовом функции. Когда вы присваиваете новые данные существующей переменной, счетчик ссылок старых данных уменьшается, и новые данные связываются со старой переменной. По сути, переменная заканчивается указанием на новые данные. То же самое верно для переменных свойств. Поскольку эти назначения не являются вызовами функций, они не имеют ничего общего с передачей по значению или передачей по ссылке.
Джон Сондерсон

1
Нет, все всегда передается по значению. Это зависит только от того, что вы передаете (значение или ссылка). Смотрите это .
Скотт Маркус

-3
  1. Примитивы (число, логическое значение и т. Д.) Передаются по значению.
    • Строки неизменны, поэтому для них это не имеет значения.
  2. Объекты передаются по ссылке (ссылка передается по значению).

Нет, все всегда передается по значению. Это зависит только от того, что вы передаете (значение или ссылка). Смотрите это .
Скотт Маркус

Ваше второе утверждение противоречит само себе.
Йорг Миттаг

-5

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

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

это смешно, у изменится из-за функционального уровня, он поднимается не потому, что передается по ссылке.
Парижат Калия

Нет, все всегда передается по значению. Это зависит только от того, что вы передаете (значение или ссылка). Смотрите это .
Скотт Маркус
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.