Является ли JavaScript языком передачи по ссылке или передачей по значению? - PullRequest
1259 голосов
/ 06 февраля 2009

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

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

Ответы [ 30 ]

7 голосов
/ 25 июля 2018

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

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

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

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

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


Обновление

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

В JavaScript отсутствует "передача по ссылке". a

4 голосов
/ 06 февраля 2009

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

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

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

3 голосов
/ 01 ноября 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;
}
3 голосов
/ 23 декабря 2016

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2 голосов
/ 16 сентября 2014

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

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

    var var1 = 13;
    var var2 = { prop: 2 };
    
    //13 and var2's content (reference) are being passed here
    foo(var1, var2); 
    
  • Внутри функции переменные параметров inVar1 и inVar2 получают передаваемое содержимое.

    function foo(inVar1, inVar2){
        //changing contents of inVar1 and inVar2 won't affect variables outside
        inVar1 = 20;
        inVar2 = { prop: 7 };
    }
    
  • Поскольку inVar2 получил ссылку на { prop: 2 }, вы можете изменить значение свойства объекта.

    function foo(inVar1, inVar2){
        inVar2.prop = 7; 
    }
    
2 голосов
/ 25 сентября 2018

Это немного больше объяснения для Pass by value и Pass by reference (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
  • применяется ко всем типам примитивов в JS (строка, число, логическое значение, неопределенное значение, ноль).
  • 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" }
  • Движок JS назначает объект переменной c, он указывает на некоторую память, скажем (0x012)
  • когда d = c, на этом шаге d указывает на то же место (0x012).
  • изменение значения любого изменения значения для обеих переменных.
  • функции являются объектами

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

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

делюсь тем, что я знаю о ссылках в 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
2 голосов
/ 19 октября 2016

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

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

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

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

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

Узнать больше

2 голосов
/ 28 июля 2017

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

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

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

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

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

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

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

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

по ссылке

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

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

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

2 голосов
/ 29 октября 2016

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

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

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

...