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

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

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


person Danail Nachev    schedule 05.02.2009    source источник
comment
Я думаю, что у нас есть множество доказательств того, какова точная семантика языка. Сейчас мы упускаем только отрывок из спецификации EcmaScript, которая определяет его, и у нас будет ответ на этот вопрос.   -  person Danail Nachev    schedule 04.08.2014
comment
Я думаю, вы случайно перевернули свои определения переданного по значению и переданного по ссылке ... переданного по значению (в случае, если мы считаем, что переменная, содержащая объект, на самом деле является ссылкой на объект) и передала- по ссылке (когда мы считаем, что переменная объекта содержит сам объект)   -  person Niko Bellic    schedule 24.08.2014
comment
да. Независимо от синтаксиса, при любом вызове функции на любом языке программирования передача по ссылке означает, что данные, связанные с переданной переменной, не копируются при передаче в функцию, и, таким образом, любые изменения, внесенные функцией в переданную переменную, будут сохранены. в программе после завершения вызова функции. Передача по значению означает, что данные, связанные с переменной, фактически копируются при передаче в функцию, и любые изменения, внесенные такой функцией в такую ​​переменную, будут потеряны, когда переменная выходит за пределы тела функции при возврате функции.   -  person John Sonderson    schedule 29.10.2014
comment
Еще одна интересная вещь, которую следует выяснить: когда функция возвращает переменную, является ли возвращаемое значение ссылкой на переменную, найденную в теле функции, или копией переменной, найденной в теле функции?   -  person John Sonderson    schedule 29.10.2014
comment
@JohnSonderson, я считаю, что объем возвращаемой переменной по умолчанию такой же, как и у функции, возвращающей переменную (вы можете проверить это, определив функцию как переменную и вернув ее). Это наводит меня на мысль, что возвращаемое значение обрабатывается так же, как передача аргумента функции - оно копирует значение (передается по значению), но если значение относится к объекту, оно копирует ссылку на этот объект, а не на сам объект. ДАЛЕЕ: AFAIK, object.create - единственный механизм, который клонирует объект в Javascript (см. stackoverflow.com/q/728360/2155068 ).   -  person MjrKusanagi    schedule 13.03.2015
comment
@MjrKusanagi Я не думаю, что Object.create можно считать правильной техникой клонирования, т.е. если вы измените исходную копию объекта, это повлияет на клон, только изменения клона не повлияют на исходный объект. Конечно, он имеет свое применение, и JavaScript разработан вокруг этой концепции (прототипное наследование), но я думаю, что называть Object.create единственным механизмом клонирования объекта - это заблуждение.   -  person Danail Nachev    schedule 10.11.2015
comment
Этот старый вопрос несколько токсичен, потому что его ответ, получивший множество голосов, неверен. JavaScript - это строго передача по значению.   -  person Pointy    schedule 28.11.2015
comment
@Pointy Я не вижу, как поведение JavaScript, описанное в ответе, неверно. Однако, я согласен, это мало что дает - просто повторяет вопрос. Ответ, на который вы ссылались, утверждает, что JavaScript строго передается по значению. Однако это основано на интерпретации того, как это работает. Та же ошибка делает сообщение в блоге. До сих пор нет выдержки из спецификации, которая поддерживает ту или иную интерпретацию (передача по значению для всего, а объектные переменные - это ссылки или передача по значению для примитивов и передача по ссылке для объектов).   -  person Danail Nachev    schedule 16.12.2015
comment
@DanailNachev Терминология, к сожалению, сбивает с толку. Дело в том, что передача по значению и передача по ссылке - это термины, которые предшествуют появлению многих более современных функций языка программирования. Слова значение и ссылка относятся конкретно к параметру, как он появляется в выражении вызова функции. JavaScript всегда оценивает каждое выражение в списке параметров вызова функции перед вызовом функции, поэтому параметры всегда являются значениями. Непонятная часть заключается в том, что ссылки на объекты являются общими значениями JavaScript. Тем не менее, это не означает, что он проходит через справочный язык.   -  person Pointy    schedule 16.12.2015
comment
@DanailNachev передача по ссылке, в частности, означает, что если у вас есть var x=3, y=x; f(x); alert(y === x);, тогда функция f() может создавать отчет о предупреждениях false, а не true. В JavaScript это невозможно, поэтому это не передача по ссылке. Хорошо, что можно передавать ссылки на изменяемые объекты, но это не то, что означает передача по ссылке. Как я уже сказал, жаль, что терминология такая запутанная.   -  person Pointy    schedule 16.12.2015
comment
@Pointy, я не думаю, что не согласен с тем, что вы говорите. Но я думаю, вам все же следует прочитать ссылку на википедию call-by-sharing, на которую ссылается сообщение, на которое вы жалуетесь.   -  person Danail Nachev    schedule 22.12.2015
comment
@DanailNachev У меня нет проблем с этой терминологией (call-by-sharing), и очевидно, что людям действительно нужен такой термин. Однако, как говорится в статье, он не используется повсеместно. Спасибо, что указали на это!   -  person Pointy    schedule 22.12.2015
comment
Число и Строка не являются примитивами. Это объекты-оболочки, которые заключают в себя число или строку (нижний регистр), которые являются примитивами.   -  person Scott Marcus    schedule 23.12.2015
comment
Это одна из многих причин, по которым JavaScript - отстой. С другими языками, такими как C и даже PHP, вы можете НЕОБХОДИМО установить передачу аргументов по значению или по ссылке. В JS это семантический беспорядок. Я не могу дождаться, когда WebAssembly станет мейнстримом, забив первый гвоздь в гроб JS.   -  person RyanNerd    schedule 11.07.2018
comment
@RyanNerd: Вы не можете использовать C. C всегда передается по значению. Да, в PHP есть передача по ссылке на стороне вызываемого, и это ужасно. C # - это пример языка, который делает все правильно, явно указывая ref и делая различие для out.   -  person Ry-♦    schedule 12.12.2019
comment
@RyanNerd - Вы совершенно не правы. JavaScript - это не семантический беспорядок. В данном случае это просто и последовательно: JavaScript передается по значению. Вот и все. Больше говорить не о чем. Такое поведение будет полностью знакомо всем, кто использовал Java, C # или PHP.   -  person Ben Aston    schedule 26.04.2020


Ответы (32)


В 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".

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

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

person Community    schedule 03.09.2010
comment
Это точно так же (или, по крайней мере, семантически), что и C #. Объект имеет два типа: значение (примитивные типы) и ссылка. - person Peter Lee; 24.12.2011
comment
Я думаю, что это также используется в Java: ссылка по значению. - person Jpnh; 04.01.2012
comment
настоящая причина в том, что в changeStuff num, obj1 и obj2 являются ссылками. Когда вы изменяете свойство item объекта, на который ссылается obj1, вы изменяете значение свойства элемента, которое изначально было установлено на неизменное. Когда вы присваиваете obj2 значение {item: changed}, вы меняете ссылку на новый объект (который немедленно выходит за пределы области видимости при выходе из функции). То, что происходит, станет более очевидным, если вы назовете параметры функции, например, numf, obj1f и obj2f. Затем вы видите, что параметры скрывали внешние имена переменных. - person jinglesthula; 30.01.2012
comment
Я достаточно тупой, чтобы знать, имеет ли практическое значение использование let вместо var в этом примере. - person ruffin; 16.04.2012
comment
Не думаю, насколько я когда-либо мог сказать, единственная разница в том, что let дает вам область видимости на уровне цикла C / C ++, тогда как var дает вам только область видимости на уровне функций. Я думаю, что есть некоторые необычные особенности, но я избегал их достаточно долго, чтобы не волноваться. - person deworde; 16.04.2012
comment
Просто мне или кому-то еще кажется, что Javascript довольно странный при прохождении ссылки ...? - person will824; 02.05.2012
comment
Проголосовали. Я споткнулся об этом, думая, что передача по ссылке была истинной передачей по ссылке - я думал, что обновление ссылки перезапишет исходное обновление (обновление всех ссылок). Теперь я вижу. Теперь, думаю, я могу исправить свой код! - person jedd.ahyoung; 19.06.2013
comment
Спасибо за хорошее объяснение. Есть ли способ заменить obj2 новым изнутри функции changeStuff? - person BartoNaz; 01.08.2013
comment
@BartoNaz Не совсем. Вы хотите передать ссылку по ссылке, а не передавать ссылку по значению. Но JavaScript всегда передает ссылку по значению, как и все остальное по значению. (Для сравнения, C # имеет поведение передачи ссылки по значению, аналогичное JavaScript и Java, но позволяет указать ссылку передачи по ссылке с помощью ключевого слова ref.) Обычно функция просто возвращает новый объект, и выполните присвоение в точке, где вы вызываете функцию. Например, foo = GetNewFoo(); вместо GetNewFoo(foo); - person Tim Goodman; 05.08.2013
comment
Я полагаю, вы также можете обойти это, назначив объект свойству некоторого объекта-оболочки. Затем вы передаете объект-оболочку и обновляете его свойство, чтобы оно указывало на новый объект. (Конечно, любые другие переменные, которые содержат ссылки на старый объект, по-прежнему будут содержать ссылку на старый объект.) Но, как правило, я бы рекомендовал вместо этого просто вернуть новый объект - он более четко передает ваше намерение и сохраняет вашу функцию без побочных эффектов. - person Tim Goodman; 05.08.2013
comment
Спасибо, Тим. Вот как я заставил это работать. Просто возвращаю измененный объект ... - person BartoNaz; 05.08.2013
comment
ах! JavaScript - это чистый язык передачи значений. Просто передаваемые значения являются ссылками, когда не имеют дело с примитивами. - person Matt Greer; 14.01.2014
comment
@MattGreer Вместо этого ситуация такова, что переданный элемент передается по значению. Но элемент, который передается по значению, сам по себе является ссылкой, я думаю, мы здесь согласны. - person deworde; 14.01.2014
comment
Хотя этот ответ является наиболее популярным, он может немного сбивать с толку, потому что в нем указано, был ли это чистый проход по значению. JavaScript - это чистая передача по значению. Но переданное значение является ссылкой. Это вообще не ограничивается передачей параметров. Вы можете просто скопировать переменную с помощью var obj1 = { item: 'unchanged' }; var obj2 = obj1; obj2.item = 'changed'; и наблюдать тот же эффект, что и в вашем примере. Поэтому я лично отсылаю к ответу Тима Гудмана. - person chiccodoro; 02.05.2014
comment
Очень интересно ... Я просмотрел ответы и комментарии, но ссылки на ECMA нет. Может ли кто-нибудь предоставить ресурс для стандарта, в котором определено это поведение? Я не очень хорошо умею находить такие вещи. Я думаю, было бы очень полезно иметь ссылку в этом ответе :) - person Chris Cirefice; 27.05.2014
comment
Для программистов PHP - этот пример будет работать так же в PHP. - person Anthony Scaife; 27.06.2014
comment
@chiccodoro Утверждение, что это чистый переход по значению, за исключением того, что вы передаете ссылку по значению, сбивает с толку любого, кто действительно задает этот вопрос. С точки зрения наблюдаемого поведения я бы хотел, чтобы чистая передача по значению (в той мере, в какой этот термин имеет какое-либо значение) была глубокой копией. Очевидно, что это реализовано как чистая передача по значению на уровне реализации движка JavaScript, но если вы работаете на этом уровне, вы не задаете этот вопрос (надеюсь, возможно, пожалуйста) - person deworde; 15.04.2015
comment
@deworde - я понимаю вашу точку зрения. На мой взгляд, передача по ссылке означает, что вы можете изменить значение параметра. Вы можете сделать это на таких языках, как VB и C # (с помощью модификатора ref). Таким образом, вы можете делать такие вещи, как var a = 2; CallAFunction(ref a);, и после этого a больше не 2. Точно так же можно изменить ссылку: var a = new A(); CallAnotherFunction(ref a), и после этого a больше не будет указывать на вновь созданный объект. Ни то, ни другое не может происходить в JavaScript - поэтому я утверждаю, что это чистый переход по значению. - person chiccodoro; 15.04.2015
comment
В языках высокого уровня скаляры почти всегда передаются по значению или копированию (часто COW внизу). Это хорошо известно. Объекты всегда автоматически передаются по ссылке. Клонировать объект не так-то просто. Базовые нескалярные типы, такие как карты и массивы, могут быть разными. Если они передаются по значению, часто будет синтаксис для явной передачи по ссылке. Наконец, если нет явной поддержки для передачи некоторых типов по ссылке, они могут быть упакованы / обернуты. Передача скалярных типов по ссылке редко бывает полезной, если язык сценариев может использовать COW, поэтому иногда он не поддерживается. - person jgmjgm; 01.07.2015
comment
@jgmjgm это не то, что означает передача по ссылке. Я понимаю, что это сбивает с толку, но эта терминология была придумана до того, как в языках программирования появились такие вещи, как объекты. Передача по ссылке означает, что вызываемая среда может изменять значение переменной в вызывающей среде. Обратите внимание, что я написал значение переменной - я имею в виду не значение объекта, а переменную, например символ, объявленный с var в JavaScript. Поскольку это невозможно, в JavaScript нет передачи по ссылке. (C ++ делает, вроде как, через & параметров.) - person Pointy; 28.11.2015
comment
См. Ответ Тима Гудмана ниже. Это правильно. Всегда передавайте по значению. - person Matthew Oakley; 02.08.2016
comment
@Pointy Вы могли бы быть в этом отношении и для фразы с точки зрения канона. По сравнению с реализациями, обращение на простом английском языке вызывает больше затруднений. Определение, которое вы включаете, включает цель (изменение), но ссылка является ссылкой независимо от конечной цели. Это также может быть связано с производительностью или со стороны чтения, когда что-то в другой ветке меняет это. Говоря простым языком, в таких контекстах он имеет тенденцию просто означать, по сути, передачу указателя. Термин ссылка абстрагирует точный механизм указателя. Перформанс - это главное место, где возникает конфликт значений. - person jgmjgm; 16.02.2017
comment
Я нашел это полезно, поскольку объясняет, что копируется при передаче аргументов функции. Важно для строк, поскольку передается копия ссылки на строку. (Но поскольку строки javascript неизменяемы, строка не используется совместно, сохраняется только память.) Обратите внимание, что в статье передается по ссылке не вызов по ссылке: передается копия ссылки на объект, а не ссылка на переменную в вызывающей стороне. - person Orafu; 19.08.2017
comment
Независимо от того, как люди хотят описать передаваемую вещь, ПРИМЕР в этом ответе гениально ясен: он позволяет читателям сразу распознавать наличие некоторой тонкости и сообщает им, как обрабатываются 3 общие ситуации. Я возвращаюсь к этому всякий раз, когда сомневаюсь. - person Eureka; 21.09.2017
comment
Это не так, как работает C # (.NET). В .NET да, у вас есть значения и ссылочные типы, но в .NET вы можете контролировать, хотите ли вы, чтобы один из них передавался по значению или по ссылке, что вы не можете сделать в JavaScript, потому что все всегда передается только по значению. . Передача по ссылке не существует в JavaScript. См. это. - person Scott Marcus; 05.04.2018
comment
@chiccodoro Я взял на себя смелость удалить формулировку «чистый пропуск по значению» и захватить этот пост, поскольку так популярно объяснять более точно. - person phant0m; 16.06.2019
comment
@ phant0m Хотя я нашел детали вашего ответа действительно интересными, я думаю, что он потерял ясность, которая сделала этот ответ полезным (при 10897 символах ваше изменение было фактически сообщением в блоге) В некотором смысле, я думаю, что это будет иметь больше смысла как отдельный ответ . Обсуждение «чистой» передачи по значению велось более года назад, и я не видел необходимости обновлять его, так как описание после термина довольно четкое. Если вас это действительно беспокоит, то, вероятно, более подходящим вариантом будет более простое изменение аргумента, если аргумент вообще не был ссылкой. - person deworde; 18.06.2019
comment
Это может быть старый вопрос, но я думаю, что это действительно лучший ответ в Интернете на то, как передача по значению (когда значение является ссылкой) в Интернете - person Wayneio; 15.12.2019
comment
@Wayneio Спасибо! Это более чем компенсирует тот факт, что я без нужды избегал получения тысяч репутаций, сделав это сообществом вики. - person deworde; 18.12.2019
comment
@BenAston Я нашел ваш ответ действительно интересным, но мне кажется, что в нем не хватает той прямолинейности, которая, по мнению некоторых, была полезной. Если вы хотите дать свой ответ на этот вопрос, я буду поддерживать его. - person deworde; 25.04.2020
comment
Справедливо. Но JavaScript передается по значению. Вот и все. Полная остановка. Я думаю, что в вашем ответе необходимо указать это заранее. Также: JavaScript ведет себя так же, как поведение по умолчанию для Java, C # и PHP, поэтому называть его «интересным» предполагает новизну, которой нет. Для будущих читателей мы ссылаемся на версию 19 здесь. - person Ben Aston; 25.04.2020
comment
Да, мы обсуждаем этот спор примерно раз в год. Я пришел к своему выводу по этому поводу в 2015 году и с тех пор не менял. stackoverflow.com/questions/518000/ - person deworde; 26.04.2020
comment
Это не личное заключение. Это очевидный факт. JavaScript передается по значению. Вот и все. Все проистекает из этого факта. А поведение JavaScript не «интересно». Он точно соответствует поведению Java (а также C # и PHP) по умолчанию и аналогичен Python. - person Ben Aston; 26.04.2020
comment
фраза - это личное заключение. Ваша формулировка соответствует учебнику, который явно не помог людям, которые задаются этим вопросом, иначе они бы не стали его искать. JavaScript может передаваться по значению в его параметрах (как указано в ответе), но поскольку JS обрабатывает все непростые типы как ссылки, сосредоточение внимания на его простой передаче по значению не может объяснить довольно фундаментальное поведение, показанное выше. И точное совпадение поведения этих языков не делает его неинтересным. Эффект от манипулирования параметрами интересен сам по себе. - person deworde; 26.04.2020
comment
Ого, это действительно странно. - person cs1349459; 10.11.2020

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

Пример:

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
person Tim Goodman    schedule 15.03.2011
comment
Привет, Тим, спасибо за отличный ответ. У меня есть небольшое предложение для ясности - не могли бы вы поменять местами порядок объявлений функций или порядок вызовов, чтобы они соответствовали друг другу? Мне потребовалось время, чтобы понять, что результат не соответствует вашему заключению! :) - person artur; 23.05.2011
comment
@daylight: На самом деле ты ошибаешься; если он был передан с помощью const ref, попытка выполнить changeObject приведет к ошибке, а не просто к сбою. Попробуйте присвоить новое значение константной ссылке в C ++, и компилятор отклонит его. С точки зрения пользователя, это разница между передачей по значению и передачей по константной ссылке. - person deworde; 18.07.2011
comment
@daylight: это не постоянный реф. В changeObject я изменил x, чтобы он содержал ссылку на новый объект. x = {member:"bar"}; эквивалентно x = new Object(); x.member = "bar"; То, что я говорю, также верно и для C #. - person Tim Goodman; 20.07.2011
comment
@daylight: для C # вы можете увидеть это извне функции, если вы используете ключевое слово ref, вы можете передать ссылку по ссылке (вместо стандартной передачи ссылки по значению), а затем изменить, чтобы указать на new Object() будет сохраняться. - person Tim Goodman; 20.07.2011
comment
хорошо, теперь я понял ... но; _; почему это делает JavaScript ?! Почему он ведет неоднозначную грань между передачей по ссылке / значению? - person Aditya M P; 28.07.2013
comment
@adityamenon Трудно ответить почему, но я хотел бы отметить, что разработчики Java и C # сделали аналогичный выбор; это не просто странность JavaScript. На самом деле, это очень последовательная передача по значению, что сбивает людей с толку, так это то, что значение может быть ссылкой. Это не сильно отличается от передачи указателя (по значению) в C ++ с последующим разыменованием его для установки членов. Никого не удивит, что это изменение сохраняется. Но поскольку эти языки абстрагируют указатель и молча выполняют разыменование за вас, люди запутаются. - person Tim Goodman; 28.07.2013
comment
Другими словами, сбивает с толку не передача по значению / передача по ссылке. Все по стоимости, точка. Заблуждение заключается в том, что вы не можете передать объект или сохранить объект в переменной. Каждый раз, когда вы думаете, что делаете это, вы фактически передаете или сохраняете ссылку на этот объект. Но когда вы обращаетесь к его членам, происходит тихое разыменование, которое увековечивает фикцию того, что ваша переменная содержала реальный объект. - person Tim Goodman; 28.07.2013
comment
Очень красноречивые комментарии, которые открыли мне глаза на что-то действительно крутое и неизвестное мне в JS: all object manipulation happens via pointers to those objects, я очень мало вижу в этом разговоре (по крайней мере, там, где я читал)! Когда мы говорим о прототипах, на самом деле это ссылки на «родительские» объекты, верно? Так являются ли они внутренними ссылками на ссылки? У этих таинственных существ, которых мы называем ссылками, другое внутреннее имя? - person Aditya M P; 28.07.2013
comment
Как вы правильно утверждаете, все по стоимости, точка! Тот факт, что объекты хранятся как ссылки, вовсе не ограничивает передачу параметров. Чтобы прояснить мысль, вы можете добавить такой пример: var x = { member: 'foo' }; var y = x; y.member = 'bar';. x.foo будет иметь новое значение, даже если мы вообще не передали параметры. Никто не будет утверждать, что присвоение переменной было выполнено по ссылке (надеюсь) - person chiccodoro; 02.05.2014
comment
Я думаю, что это то же самое, что и передача параметров в Java. - person Peng; 08.04.2018

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

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

person Shog9    schedule 05.02.2009
comment
Это меня немного смущает. Разве ссылка не передается по ссылке? - person ; 02.10.2017
comment
Автор означает, что, передавая ссылку, вы передаете ссылочное значение (другой способ думать об этом - передавать значение адреса памяти). Вот почему, если вы повторно объявите объект, оригинал не изменится, потому что вы создаете новый объект в другом месте памяти. Если вы измените свойство, исходный объект изменится, потому что вы изменили его в исходной ячейке памяти (которая не была переназначена). - person Huy-Anh Hoang; 11.10.2017
comment
Фраза, передающая ссылку по значению, кажется излишне запутанной и излишней. При передаче ссылки, конечно, должно быть передано какое-то значение. Хотя технически это верно, большинство людей, скорее всего, исходят из предположения, что все передается по значению, если не указано иное. Так что, конечно, ссылка передается по значению, если только она сама не передается по ссылке (вроде как указатель на указатель в C), но в этом случае Javascript даже не поддерживает это, поэтому я не думаю, что это помогает сделать концепция более четкая - person geg; 02.07.2020
comment
Проблема с JavaScript заключается в том, что он не дает выбора в этом вопросе, @geg: сложные типы будут всегда обрабатываться косвенно, простые типы всегда напрямую. Невозможно получить ссылку на целое число или предотвратить передачу ссылки на кортеж. Это ... Иногда будет неловко. - person Shog9; 02.07.2020
comment
Проще говоря, через десятилетие ссылка копируется по значению. - person snr; 24.08.2020
comment
Тем, кого смущает этот ответ: я считаю, что передача по ссылке в этом ответе конкретно означает передачу по ссылке в стиле C ++, например void swapNums(int &x, int &y) в C ++ или void increment(ref int arg) в C #. - person wlnirvana; 20.01.2021

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

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

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

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

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

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

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

var favoriteObject = object1;

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

favoriteObject = object2;

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

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, изменив favouriteString ... Почему ?? Потому что мы не изменили нашу строку object. Все, что мы сделали, - это ПОВТОРИТЬ НАЗНАЧЕНИЕ переменной любимойString новой строки. Это по сути отключило его от 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'
person Ray Perea    schedule 04.08.2014
comment
Любому программисту на C следует подумать о char *. foo(char *a){a="hello";} ничего не делает, но если вы делаете foo(char *a){a[0]='h';a[1]='i';a[2]=0;}, он изменяется снаружи, потому что a - это ячейка памяти, переданная значением, которое ссылается на строку (массив символов). Передача структур (похожих на объекты js) по значению в C разрешена, но не рекомендуется. JavaScript просто применяет эти передовые методы и скрывает ненужные и обычно нежелательные хлам ... и это, безусловно, облегчает чтение. - person technosaurus; 26.03.2015
comment
Это правильно - термины передача по значению и передача по ссылке имеют значение в дизайне языка программирования, и эти значения не имеют ничего общего с изменением объекта. . Все дело в том, как работают параметры функции. - person Pointy; 28.11.2015
comment
Теперь, когда я понимаю, что obj1 = obj2 означает, что оба объекта obj1 и obj2 теперь указывают на одно и то же место ссылки, и если я изменю внутреннее устройство obj2, ссылка на obj1 откроет те же внутренние компоненты. Как мне скопировать объект так, чтобы, когда я делаю source = { "id":"1"}; copy = source /*this is wrong*/; copy.id="2", этим источником по-прежнему был {id: 1}? - person Machtyn; 22.02.2016
comment
Я опубликовал еще один ответ с традиционными определениями, чтобы, надеюсь, уменьшить путаницу. Традиционные определения передачи по значению и передачи по ссылке были определены еще во времена указателей памяти до автоматического разыменования. Было прекрасно понятно, что значение объектной переменной на самом деле было местоположением указателя в памяти, а не объектом. Хотя ваше обсуждение присваивания и мутации, возможно, полезно, нет необходимости отбрасывать традиционные термины или их определения. Мутация, присвоение, передача по значению, передача по ссылке и т. Д. Не должны противоречить друг другу. - person C Perkins; 30.05.2017
comment
Число тоже неизменяемо? - person ebram khalil; 16.06.2017
comment
Это может быть интересно читать, но гораздо сложнее, чем необходимо, и немного не по сути. На самом деле это довольно просто, если вы понимаете, что существует разница между наличием типа значения или ссылки и передачей этого типа. Все всегда передается по значению. Это просто зависит от того, что вы передаете (значение или ссылка). См. это. - person Scott Marcus; 05.04.2018
comment
Я попытался прояснить некоторые формулировки, например, больше не мутирует другой объект (другого объекта не было), чтобы попытаться уменьшить путаницу. Я оставил в комментариях, что передача по ссылке и передача по значению не имеют отношения к делу, потому что я не хотел полностью изменять ваше сообщение при редактировании. Это действительно имеет значение. Я думаю, что ваша сосредоточенность на том, чтобы отложить дискуссию о терминологии на мгновение и поговорить в первую очередь о регулярных заданиях (когда никто никогда не обсуждает, как один язык программирования ведет себя по сравнению с другим), великолепен! - person phant0m; 16.06.2019
comment
Однако передача по ссылке абсолютно изменит то, что происходит. Все ваше объяснение подчеркивает тот факт, что в JavaScript параметры функции являются отдельными переменными, и назначение разных переменных не влияет на другие. Да! Но: При передаче по ссылке эти параметры были бы не отдельными, они, по сути, были бы псевдонимом для переменной вызывающего. Таким образом, присвоение переменной параметра на самом деле является присвоением переменной вызывающего, а не отдельной независимой переменной. - person phant0m; 16.06.2019
comment
@ScottMarcus Что меня беспокоит в этом посте, так это то, что в нем говорится, что не имеет значения, п-б-р или п-б-в. В остальном, я думаю, что говорить о длинных заданиях - отличная идея. Люди (которые не делают различий между типами значение / ссылка) всегда вскакивают на эту тему в контексте передачи аргументов. Тот факт, что он ведет себя точно так же, и никто никогда не думал о том, что присвоение переменных работает иначе в Java, чем в Python / JavaScript / Ruby, откровенно немного удивляет, но они утверждают, что передача параметров является разные, хотя он тоже работает одинаково. - person phant0m; 16.06.2019

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

  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
person geg    schedule 26.09.2015
comment
Дополнительные вопросы для получения дополнительной оценки;) Как работает сборка мусора? Если я циклически перебираю для переменной миллион {'George', 1} значений, но использую только одно из них за раз, то как управлять остальными? А что происходит, когда я присваиваю переменной значение другой переменной? Я тогда указываю на указатель или указываю на указатель правого операнда? var myExistingVar = {"blah", 42}; var obj = myExistingVar; приводит к тому, что obj указывает на {"blah", 42} или на myExistingVar? - person Michael Hoffmann; 05.03.2017
comment
@MichaelHoffmann Они заслуживают своих собственных вопросов SO, и, вероятно, на них уже даны ответы лучше, чем я могу. При этом 1) я запустил профиль памяти в инструментах разработчика браузера для функции цикла, такой как описанная вами, и увидел всплески использования памяти на протяжении всего цикла. Казалось бы, это указывает на то, что новые идентичные объекты действительно создаются на каждой итерации цикла. Когда шипы внезапно падают, сборщик мусора просто убирает группу этих неиспользуемых объектов. - person geg; 14.03.2017
comment
@MichaelHoffmann 2) Что касается чего-то вроде var a = b, javascript не предоставляет механизма для использования указателей, и поэтому переменная никогда не может указывать на указатель (как вы можете в C), хотя базовый механизм javascript, несомненно, использует их. Итак ..._ 3_ укажет a на указатель правого операнда - person geg; 14.03.2017
comment
Я задал вопрос №1 здесь (в частности, о Chrome, потому что реализация, вероятно, отличается в каждом браузере) stackoverflow.com/q/42778439/539997 и я все еще пытаюсь придумать, как сформулировать вопрос №2. Любая помощь приветствуется. - person Michael Hoffmann; 14.03.2017
comment
Не нужно забывать про передачу по ссылке / значению! Эти термины имеют историческое значение, которое точно описывает то, что вы пытаетесь описать. Если мы отбросим исторические термины и определения и станем слишком ленив, чтобы узнать, что они изначально значили, то мы потеряем способность эффективно общаться между поколениями. Не было бы хорошего способа обсуждать различия между разными языками и системами. Вместо этого новым программистам необходимо изучить и понять традиционные термины, а также почему и откуда они пришли. В противном случае мы все вместе потеряем знания и понимание. - person C Perkins; 30.05.2017

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

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

person user779764    schedule 02.06.2011

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

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

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

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

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

person igor    schedule 12.05.2011
comment
Вау, это невероятно сбивает с толку. Кто в здравом уме определил бы устоявшийся термин для обозначения полной противоположности, а затем использовал бы его таким образом? Неудивительно, что здесь так много запутанных ответов на этот вопрос. - person Jörg W Mittag; 01.06.2020
comment
Этот ответ - ключ к пониманию того, что другие люди пишут на эту тему. Большинство людей не осознают, что существует два определения термина «передать по ссылке», поэтому, когда вы читаете их объяснение, вы должны сделать обоснованное предположение относительно того, какое значение термина они используют. Глава книги, на которую есть ссылка в этом ответе, также полезна для более глубокого понимания темы. - person Mark; 19.02.2021

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

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

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}
person Phil Mander    schedule 13.02.2015

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

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

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

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

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

person Michael Roberts    schedule 05.02.2009
comment
Передайте 5 в функцию, затем вызовите theParam.toPrecision (4), и она заработает. Это означает, что это объект. Если он может использовать что-либо из своего прототипа, то это должен быть объект. Это не похоже на Ruby в том, что вы можете использовать 5.someMethod (), но каждая переменная заключена в соответствующий объект. - person geowa4; 06.02.2009
comment
Это не объект для запуска, но когда для него вызывается метод, он оборачивается. - person geowa4; 06.02.2009
comment
Обертка отбрасывается после завершения вызова, однако это чисто соглашение и фактически не заменяет исходную строку объектом. - person Michael Roberts; 06.02.2009
comment
Я не знаю Ruby, но в js можно использовать (5) .someMethod () - person KooiInc; 06.02.2009
comment
-1, не всегда передается по значению. Из MDC: если вы передаете объект (т.е. не примитивное значение, такое как массив или определяемый пользователем объект) в качестве параметра, ссылка на объект передается в функцию. - person Nick; 14.10.2010
comment
@Nick: Это всегда передается по значению. Период. Ссылка на объект передается функции по значению. Это не по ссылке. Передачу по ссылке можно представить как передачу самой переменной, а не ее значения; любые изменения, которые функция вносит в аргумент (включая полную замену его другим объектом!), будут отражены в вызывающей стороне. Этот последний бит невозможен в JS, потому что JS не передает ссылки по ссылке - он передает ссылки по значению. Различие тонкое, но довольно важное для понимания его ограничений. - person cHao; 10.05.2012
comment
Для будущих укладчиков ... Об этой вашей ссылке: x = "teste"; x.foo = 12; и т. Д. Тот факт, что свойство не является постоянным, не означает, что оно не является объектом. Как говорит MDN: В JavaScript почти все является объектом. Все примитивные типы, кроме null и undefined, рассматриваются как объекты. Им можно назначать свойства (назначенные свойства некоторых типов не являются постоянными), и они имеют все характеристики объектов. ссылка - person slacktracer; 16.08.2012
comment
Майкл Робертс прав по обоим пунктам. Как обычно, заблуждения, кажется, всплывают на поверхность. - person Garrett; 14.12.2013
comment
MDN - это вики, редактируемая пользователями, и там она ошибочна. Нормативная ссылка - ECMA-262. См. S. 8 Тип спецификации ссылки, в котором объясняется, как разрешаются ссылки, а также 8.12.5 [[Put]], который используется для объяснения AssignmentExpression в ссылке, и для приведения объекта 9.9 ToObject. Для примитивных значений Майкл уже объяснил, что делает ToObject, как указано в спецификации. Но см. Также s. 4.3.2 примитивное значение. - person Garrett; 14.12.2013
comment
@cHao для array, переданного в качестве параметров. @Nick прав: если вы изменяете массив в функции назначения, также изменяется и исходный массив. (это звучит для меня как ссылка.) Это imho - это то, что люди хотят знать, когда они спрашивают о ссылках / значениях ... - person WonderLand; 05.05.2016
comment
@WonderLand: Нет, это не так. Люди, которые никогда не могли передавать по ссылке, могут никогда не понять различий между передачей по ссылке и передачей ссылки по значению. Но они есть, и они имеют значение. Я не хочу дезинформировать людей просто потому, что это звучит проще. - person cHao; 05.05.2016
comment
@cHao, если я передаю array в функции и изменю это array в своей функции, то исходный array также изменится. вы сказали, что передана ссылка на объект, это не означает, что передается само значение, а что-то похожее на указатель ... - person WonderLand; 06.05.2016
comment
@WonderLand: это означает, что массивы не являются значениями в JS. Ссылки на массивы являются значениями. И когда вы передаете массив, вы копируете и передаете это значение, а не сам массив. Возможно, вы не замечаете разницы, но эта разница делает невозможными некоторые вещи в JS, которые возможны в языках, допускающих передачу по ссылке. - person cHao; 06.05.2016
comment
Для тех из вас, кто, как и я, смущен: stackoverflow.com/questions/373419/, - подробно объясняется второй наиболее набранный ответ. - person LiweiZ; 27.07.2016
comment
В JS примитивы не являются объектами, но поскольку JS является динамическим языком (не имеет типов), когда вы пытаетесь использовать методы на примитиве, JS преобразует его в объект (pe int преобразуется в Number) при использовании метода . Тем не менее, эти примитивные объекты неизменяемы, поэтому вы не можете добавлять к ним какие-либо дополнительные методы. Я добавил ответ, в котором пытается объяснить передачу по ссылке на примере языка низкого уровня. Думаю, это легче понять. - person Narayon; 19.10.2016
comment
Нет, не все является ценностью. Есть примитивы, которые являются типами значений, и объекты, которые являются ссылочными типами. Но в любом случае при передаче все они передаются по значению. - person Scott Marcus; 05.04.2018
comment
@Narayon потому что JS - это динамический язык (не имеет типов) JavaScript не является динамическим языком - это интерпретируемый (компилируемый по запросу) язык, но это не это не значит, что у него нет типов. Несомненно. Он имеет примитивные типы и типы объектов. - person Scott Marcus; 11.04.2019

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

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

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

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

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

Источник

person zangw    schedule 30.12.2015
comment
Сначала вы утверждаете, что составные значения всегда присваиваются / передаются копией ссылки, а затем вы заявляете, что назначает копию ссылки на x. В случае того, что вы называете составным значением, фактическое значение переменной ЯВЛЯЕТСЯ ссылкой (то есть указателем памяти). Как вы объяснили, ссылка копируется ... поэтому переменные значение копируются, снова подчеркивая, что ССЫЛКА - ЭТО ЗНАЧЕНИЕ. Это означает, что JavaScript передается по значению для всех типов. Передача по значению означает передачу копии значения переменных. Не имеет значения, что значение является ссылкой на объект / массив. - person C Perkins; 30.05.2017
comment
Вы вводите новую терминологию (значение-копия / ссылка-копия), и это только усложняет задачу. Есть только копии, и точка. Если вы передаете примитив, вы передаете копию фактических данных примитива, если вы передаете объект, вы передаете копию области памяти объекта. Это все, что вам нужно сказать. Все, что угодно, только еще больше сбивает людей с толку. - person Scott Marcus; 05.04.2018

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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'];

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

person kia nasirzadeh    schedule 14.11.2019

Это немного дополнительное объяснение передачи по значению и передачи по ссылке (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 (строка, число, логическое значение, неопределенное значение и значение null).
  • 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" }
  • Оператор равенства (=) устанавливает новое пространство памяти или адрес
person Ashish Singh Rawat    schedule 25.09.2018
comment
В вашем так называемом особом случае не оператор присваивания вызывает выделение пространства памяти, это литерал объекта. Обозначение фигурных скобок вызывает создание нового объекта. Свойство c устанавливается на копию ссылки на новый объект. - person georgeawg; 27.03.2019
comment
Это не передается по ссылке. Это передача по значению, значение которого оказывается ссылкой. - person gman; 16.12.2020

делюсь тем, что я знаю о ссылках в 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

person Zameer Ansari    schedule 10.08.2017
comment
Это слишком упрощенный ответ, который ничего не говорит о том, что более ранние ответы не объясняли лучше. Я не понимаю, почему вы называете массивы как особый случай. - person Quentin; 10.08.2017
comment
объекты хранятся как ссылки вводит в заблуждение. Я думаю, вы имеете в виду, что при присвоении объекта переменной значение, присвоенное переменной, является ссылкой на объект. - person RobG; 27.07.2019
comment
это не решает проблему обновления объекта внутри функции, которая не обновляет объект вне функции. Вот и вся картина, в которой кажется, что она работает как значения, а не как эталоны. Следовательно -1 - person amaster; 11.04.2020
comment
@amaster Спасибо, что указали на это! Не могли бы вы предложить правку, пожалуйста? - person Zameer Ansari; 11.04.2020
comment
Ха-ха, я пробовал ... предложенное мной редактирование слишком сильно изменилось, а не разрешено - person amaster; 13.04.2020
comment
@amaster Я не могу отследить ваше предложение! - person Zameer Ansari; 14.04.2020
comment
@xameeramir это потому, что он не был отправлен. Мое предложение слишком сильно изменило ваш ответ, поэтому оно было заблокировано SO. Здесь есть и другие хорошие ответы. Я могу добавить ответ позже, чтобы кратко выразить свою точку зрения - person amaster; 14.04.2020

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

person C Perkins    schedule 23.12.2016

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

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

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

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

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


Обновлять

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

В JavaScript нет возможности «передать по ссылке».

person georgeawg    schedule 25.07.2018
comment
@Amy Потому что это описывает передачу по значению, а не по ссылке. Этот ответ хорошо показывает разницу: stackoverflow.com/a/3638034/3307720 - person nasch; 27.03.2019
comment
@nasch Я понимаю разницу. # 1 и # 2 описывают семантику передачи по ссылке. # 3 описывает семантику передачи по значению. - person ; 27.03.2019
comment
@Amy 1, 2 и 3 согласуются с передачей по значению. Для передачи по ссылке вам также понадобится 4: присвоение ссылки новому значению внутри функции (с оператором =) также переназначает ссылку вне функции. Это не относится к Javascript, поэтому он передается исключительно по значению. При передаче объекта вы передаете указатель на объект и передаете этот указатель по значению. - person nasch; 27.03.2019
comment
Обычно это не то, что подразумевается под передачей по ссылке. Вы удовлетворили мой запрос, и я с вами не согласен. Спасибо. - person ; 27.03.2019
comment
В моей книге это называется передачей по ссылке. - В каждой книге по компилятору, книге по интерпретатору, книге по теории языков программирования и книге по информатике, когда-либо написанной, это не так. - person Jörg W Mittag; 01.06.2020

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

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

 let a = { prop: 1 };
 let b = a; // a and b hold the same value
 a.prop = "test"; // The object gets mutated, can be observed through both a and b
 b = { prop: 2 }; // b holds now a different value

Теперь вы можете спросить себя, как две переменные могут иметь одно и то же значение на компьютере. Затем вы можете заглянуть в исходный код движка JavaScript и, скорее всего, найдете что-то, что программист языка, на котором был написан движок, назвал бы ссылкой.

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

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

² Термин Ссылка в спецификации не является ссылкой в ​​традиционном смысле. Это контейнер для объекта и имени свойства, и это промежуточное значение (например, a.b оценивается как Reference { value = a, name = "b" }). Термин ссылка также иногда появляется в спецификации в несвязанных разделах.

person Jonas Wilms    schedule 26.07.2020

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

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

    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; 
    }
    
person dpp    schedule 16.09.2014

Передача аргументов функции в 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;
}
person John Sonderson    schedule 01.11.2014
comment
Я не думаю, что в JavaScript дело обстоит именно так: `` javascript var num = 5; - person Danail Nachev; 07.04.2015
comment
@DanailNachev: Хотя технически это может быть правдой, разница заметна только для изменяемых объектов, которых нет в примитивах ECMAScript. - person Jörg W Mittag; 01.06.2020

Для юристов по языкам программирования я просмотрел следующие разделы 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. Если оцениваемая синтаксическая продукция содержится в коде строгого режима, пусть strict будет true, иначе пусть strict будет false.
  8. Возвращает значение типа Reference, базовое значение которого - baseValue, имя, на которое ссылается, - propertyNameString, а флаг строгого режима - strict.

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

По ссылке

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

Определение «объекта»

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

person DannyNiu    schedule 28.07.2017
comment
Меня никогда не перестает удивлять, сколько людей смущает различие между аргументами, передаваемыми по значению, аргументами, передаваемыми по ссылке, операциями с целыми объектами и операциями с их свойствами. В 1979 году я не получил ученой степени по информатике, вместо этого я решил добавить к моей программе MBA около 15 часов факультативов CS. Тем не менее, вскоре мне стало ясно, что мое понимание этих концепций было по крайней мере так же хорошо, как и у любого из моих коллег, имеющих ученые степени в области компьютерных наук или математики. Изучите Assembler, и все станет совершенно ясно. - person David A. Gray; 01.10.2017
comment
Ссылка в спецификации не имеет ничего общего с рассматриваемым поведением. Это промежуточная конструкция, объясняющая, почему a.b = 1 может знать, на каком объекте (a) установлено свойство (b) (поскольку a.b оценивается как Reference { a, "b" }). - person Jonas Wilms; 26.07.2020

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

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

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

person miguelr    schedule 20.04.2019

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

  • Примитивы: открывая примитивный тип, вы работаете непосредственно с его значением.

    • string
    • количество
    • логический
    • нулевой
    • неопределенный

E.g.:

var foo = 1,
    bar = foo;

bar = 9;

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

    • object
    • множество
    • функция

E.g.:

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

bar[0] = 9;

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

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

person lid    schedule 17.05.2014
comment
Нет, все всегда передается по значению. Это просто зависит от того, что вы передаете (значение или ссылка). См. это. - person Scott Marcus; 05.04.2018

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

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

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

person steviesh    schedule 29.10.2016
comment
Нет, на самом деле проблема не в том, является ли объект изменяемым. Все всегда передается по значению. Это просто зависит от того, что вы передаете (значение или ссылка). См. это. - person Scott Marcus; 05.04.2018
comment
Она описывает передачу ссылки ПО-ЗНАЧЕНИЮ. Нет причин вводить новую терминологию. - person Sanjeev; 17.06.2019

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

function replaceOrModify(aObj) {
  if (modify) {

    aObj.setNewValue('foo');

  } else {

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

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

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

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

JavaScript - это язык высокого уровня, который выполняет это преобразование за вас.

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

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

Подробнее…

person Narayon    schedule 19.10.2016
comment
Нет, разыменование ссылок в C ++ не требуется (и не разрешается). Либо разыменовываются указатели, либо ссылки нет. - person Peter Mortensen; 16.10.2020
comment
Этот ответ фактически неверен. JavaScript не выполняет такого преобразования. В JavaScript передать по ссылке невозможно. Вся точка передачи по ссылке предназначена для того, чтобы функция могла изменять значение myAge. Вы не можете сделать это в JavaScript. Вы можете изменить свойства и myAge ссылки на объект, но вы не можете изменить myAge саму переменную. Вот что означает передача по ссылке - возможность изменять значение переменной вне функции. - person gman; 16.12.2020

Я бы сказал, что это копия -

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

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

person lyslim    schedule 09.01.2015
comment
передача по копии === передача по значению - person Scott Marcus; 05.04.2018

  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
person Mukund Kumar    schedule 28.10.2014
comment
Оператор присваивания не следует путать с вызовом функции. Когда вы назначаете новые данные существующей переменной, количество ссылок на старые данные уменьшается, и новые данные связываются со старой переменной. По сути, переменная указывает на новые данные. То же самое и с переменными свойств. Поскольку эти назначения не являются вызовами функций, они не имеют ничего общего с передачей по значению или по ссылке. - person John Sonderson; 29.10.2014
comment
Нет, все всегда передается по значению. Это просто зависит от того, что вы передаете (значение или ссылка). См. это. - person Scott Marcus; 05.04.2018

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

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

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

person Jack Sleight    schedule 05.02.2009
comment
Связанная статья больше не включает эти утверждения и вообще избегает использования передачи по ссылке. - person C Perkins; 23.12.2016
comment
Значение является ссылкой - person ; 05.06.2019

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

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

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

person Ross    schedule 05.02.2009
comment
На самом деле это не передается по ссылке. Вы передаете указатели в функцию, и эти указатели передаются по значению. Лучшим примером может служить оператор & в C ++ или ключевое слово ref в C #, оба они действительно передаются по ссылке. - person Matt Greer; 26.04.2010
comment
Еще проще то, что в JavaScript все передается по значению. - person Scott Marcus; 05.04.2018
comment
stackoverflow.com/questions/42045586/ - person Scott Marcus; 05.04.2018

  1. Primitives (number, Boolean, etc.) are passed by value.
    • Strings are immutable, so it doesn't really matter for them.
  2. Объекты передаются по ссылке (ссылка передается по значению).
person uriz    schedule 25.02.2013
comment
Нет, все всегда передается по значению. Это просто зависит от того, что вы передаете (значение или ссылка). См. это. - person Scott Marcus; 05.04.2018
comment
Ваше второе утверждение противоречит самому себе. - person Jörg W Mittag; 01.06.2020

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

// 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 ) ); 
person Asad Raza    schedule 29.04.2020
comment
JSON.parse( JSON.stringify( obj ) ) - ужасный способ глубокого клонирования объектов. Это не только медленно, но и может привести к потере данных. - person D. Pardal; 28.05.2020
comment
Похоже, что это вообще не отвечает на вопрос, который был задан - person Quentin; 13.07.2020

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

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
person Olivera Kovacevic    schedule 27.04.2013
comment
Это смешно, y изменится из-за определения функционального уровня, он поднимается не потому, что передается по ссылке. - person Parijat Kalia; 10.11.2015
comment
Нет, все всегда передается по значению. Это просто зависит от того, что вы передаете (значение или ссылка). См. это. - person Scott Marcus; 05.04.2018

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

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

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

person Community    schedule 21.08.2009
comment
это новое значение также доступно вне функции. Это ложь. См. jsfiddle.net/rdarc. Значение не изменяется, вместо этого изменяется ссылка. - person Tom; 29.08.2011
comment
@Tom, изменение кода на var x = {hi : 'hi'}; change(x); console.log(x.hi); function change(x) { x.hi = 'changed'; } меняет поведение. - person Olgun Kaya; 06.09.2017
comment
stackoverflow.com/questions/42045586/ - person Scott Marcus; 05.04.2018