Czy JavaScript przechodzi przez odniesienie? [duplikat]

to pytanie ma już odpowiedzi tutaj : czy JavaScript jest językiem pass-by-reference czy pass-by-value? (32 odpowiedzi) Zamknięty 1 rok temu .

Czy JavaScript przekazuje referencje czy przekazuje wartości?

Oto przykład z JavaScript: dobre części. Jestem bardzo zdezorientowany co do parametru my dla funkcji prostokąt. Jest ona w rzeczywistości undefined i przedefiniowana wewnątrz funkcji. Nie ma oryginalnych odniesień. Jeśli usunę go z parametru function, funkcja obszaru wewnętrznego nie będzie miała do niego dostępu.

Czy to zamknięcie? Ale żadna funkcja nie jest zwracana.

var shape = function (config) {
    var that = {};
    that.name = config.name || "";
    that.area = function () {
        return 0;
    };
    return that;
};

var rectangle = function (config, my) {
    my = my || {};
    my.l = config.length || 1;
    my.w = config.width || 1;
    var that = shape(config);
    that.area = function () {
        return my.l * my.w;
    };
    return that;
};

myShape = shape({
    name: "Unhnown"
});

myRec = rectangle({
    name: "Rectangle",
    length: 4,
    width: 6
});

console.log(myShape.name + " area is " + myShape.area() + " " + myRec.name + " area is " + myRec.area());
Author: Peter Mortensen, 2012-10-27

13 answers

Prymitywy są przekazywane przez wartość, a obiekty są przekazywane przez "kopię referencji".

W szczególności, gdy przekazujesz obiekt (lub tablicę), przekazujesz (niewidocznie) odniesienie do tego obiektu i można modyfikować zawartość tego obiektu, ale jeśli spróbujesz nadpisać odniesienie, nie wpłynie to na kopię odniesienia posiadaną przez wywołujący-tzn. samo odniesienie jest przekazywane przez wartość:

function replace(ref) {
    ref = {};           // this code does _not_ affect the object passed
}

function update(ref) {
    ref.key = 'newvalue';  // this code _does_ affect the _contents_ of the object
}

var a = { key: 'value' };
replace(a);  // a still has its original value - it's unmodfied
update(a);   // the _contents_ of 'a' are changed
 739
Author: Alnitak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-16 02:10:32

Pomyśl o tym TAK:

Ilekroć tworzysz obiekt W Ecmascripcie, obiekt ten powstaje w mistycznym uniwersalnym miejscu ECMAscript, do którego nikt nigdy nie będzie w stanie dotrzeć. Wszystko co dostajesz to odniesienie do tego obiektu w tym mistycznym miejscu.

var obj = { };

Even obj jest tylko odniesieniem do obiektu (który znajduje się w tym szczególnym cudownym miejscu) i dlatego można tylko przekazać to odniesienie wokół. Skutecznie, każdy kawałek kodu który dostęp objzmodyfikuje obiekt , który jest daleko, daleko.

 64
Author: jAndy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-27 21:55:52

Moje dwa centy.... Nie ma znaczenia, czy JavaScript przekazuje parametry według referencji czy wartości. Najważniejsze jest przypisanie a mutacja.

Napisałem dłuższe, bardziej szczegółowe wyjaśnienie w tym linku.

Kiedy przekazujesz cokolwiek (niezależnie od tego, czy jest to obiekt, czy prymityw), JavaScript przydziela nową zmienną wewnątrz funkcji... podobnie jak używanie znaku równości (=).

Jak ten parametr zachowuje się wewnątrz funkcji jest dokładnie taki sam zachowałoby się, gdybyś tylko przypisał nową zmienną za pomocą znaku równości... Weź te proste przykłady.

var myString = 'Test string 1';

// Assignment - A link to the same place as myString
var sameString = myString;

// If I change sameString, it will not modify myString,
// it just re-assigns it to a whole new string
sameString = 'New string';

console.log(myString); // Logs 'Test string 1';
console.log(sameString); // Logs 'New string';

Gdybym przekazał myString jako parametr do funkcji, zachowywałoby się to tak, jakbym po prostu przypisał go do nowej zmiennej. Teraz zróbmy to samo, ale z funkcją zamiast prostego zadania

function myFunc(sameString) {

  // Reassignment... Again, it will not modify myString
  sameString = 'New string';
}

var myString = 'Test string 1';

// This behaves the same as if we said sameString = myString
myFunc(myString);

console.log(myString); // Again, logs 'Test string 1';

Możesz modyfikować obiekty po przekazaniu ich do funkcji tylko dlatego, że nie przypisujesz ich ponownie... Zamiast tego obiekty mogą być zmieniane lub mutowane.... Znowu, to działa w ten sam sposób.

var myObject = { name: 'Joe'; }

// Assignment - We simply link to the same object
var sameObject = myObject;

// This time, we can mutate it. So a change to myObject affects sameObject and visa versa
myObject.name = 'Jack';
console.log(sameObject.name); // Logs 'Jack'

sameObject.name = 'Jill';
console.log(myObject.name); // Logs 'Jill'

// If we re-assign it, the link is lost
sameObject = { name: 'Howard' };
console.log(myObject.name); // Logs 'Jill'

Gdybym przekazał myObject jako parametr do funkcji, zachowywałoby się to tak, jakbym po prostu przypisał go do nowej zmiennej. Znowu to samo z dokładnie tym samym zachowaniem, ale z funkcją.

function myFunc(sameObject) {
  // We mutate the object, so the myObject gets the change too... just like before.
  sameObject.name = 'Jill';

  // But, if we re-assign it, the link is lost
  sameObject = {
    name: 'Howard'
  };
}

var myObject = {
  name: 'Joe'
};

// This behaves the same as if we said sameObject = myObject;
myFunc(myObject);
console.log(myObject.name); // Logs 'Jill'

Za każdym razem, gdy przekazujesz zmienną do funkcji, "przypisujesz" dowolną nazwę parametru, tak jak w przypadku użycia znaku równości =.

Zawsze pamiętaj że znak równości = oznacza przypisanie. A przekazanie parametru do funkcji oznacza również przypisanie. Są one takie same i obie zmienne są połączone w dokładnie taki sam sposób.

Modyfikowanie zmiennej wpływa na inną zmienną tylko wtedy, gdy obiekt bazowy jest zmutowany.

Nie ma sensu rozróżniać między obiektami i prymitywami, ponieważ działa to dokładnie tak samo, jak gdybyś nie miał funkcji i po prostu użył znaku równości do przypisanie do nowej zmiennej.

 51
Author: Ray Perea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-16 02:48:13

Argumenty funkcji są przekazywane przez wartość lub przez dzielenie, ale nigdy nigdy przez odniesienie w JavaScript!

Call-by-Value

Typy prymitywne są przekazywane przez-wartość:

var num = 123, str = "foo";

function f(num, str) {
  num += 1;
  str += "bar";
  console.log("inside of f:", num, str);
}

f(num, str);
console.log("outside of f:", num, str);

Przypisania wewnątrz zakresu funkcji nie są widoczne w otaczającym go zakresie.

Dotyczy to również Strings, które są złożonym typem danych, a jednak niezmiennym:

var str = "foo";

function f(str) {
  str[0] = "b"; // doesn't work, because strings are immutable
  console.log("inside of f:", str);
}

f(str);
console.log("outside of f:", str);

Call-by-Sharing

Obiekty, czyli wszystkie typy, które nie są prymitywami, są przekazywane przez-dzielenie się. Zmienna, która zawiera odniesienie do obiektu, w rzeczywistości posiada jedynie kopię tego odniesienia. Jeśli JavaScript realizowałby strategię oceny call-by-reference, zmienna utrzymywałaby oryginalne odniesienie. Jest to zasadnicza różnica między by-sharing I by-reference.

Jakie są praktyczne konsekwencje tego rozróżnienia?

var o = {x: "foo"}, p = {y: 123};

function f(o, p) {
  o.x = "bar"; // Mutation
  p = {x: 456}; // Reassignment
  console.log("o inside of f:", o);
  console.log("p inside of f:", p);
}

f(o, p);

console.log("o outside of f:", o);
console.log("p outside of f:", p);

Mutacja oznacza modyfikację pewnych właściwości istniejącego Object. Kopia odniesienia, do której jest powiązana zmienna i która odnosi się do tego obiektu, pozostaje taka sama. Mutacje są więc widoczne w zasięgu rozmówcy.

Ponowne przypisanie oznacza zastąpienie kopii odniesienia związanej ze zmienną. Ponieważ jest to tylko kopia, inne zmienne posiadające kopię tego samego odniesienia pozostają nienaruszone. W związku z tym zmiany nie są widoczne w zakresie rozmówcy, tak jak w przypadku oceny call-by-reference strategia.

Dalsze informacje na temat strategii oceny W ECMAScript.

 27
Author: Peter Mortensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-16 02:50:38

Podobnie jak w przypadku C, ostatecznie wszystko jest przekazywane przez wartość. W przeciwieństwie do C, nie można utworzyć kopii zapasowej i przekazać lokalizacji zmiennej, ponieważ nie ma ona wskaźników, tylko referencje.

I wszystkie odniesienia do niego są do obiektów, a nie zmiennych. Istnieje kilka sposobów osiągnięcia tego samego wyniku, ale należy je wykonać ręcznie, a nie tylko dodać słowo kluczowe na stronie wywołania lub deklaracji.

 20
Author: jmoreno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-16 02:13:10

JavaScript jest przekazywana przez wartość.

Dla prymitywów wartość primitives jest przekazywana. Dla obiektów przekazywana jest "wartość" referencyjna obiektu.

Przykład z obiektem:

var f1 = function(inputObject){
    inputObject.a = 2;
}

var f2 = function(){
    var inputObject = {"a": 1};
    f1(inputObject);
    console.log(inputObject.a);
}

Wywołanie f2 powoduje wypisanie wartości" a "jako 2 zamiast 1, gdy Referencja jest przekazywana i wartość" a " w referencji jest aktualizowana.

Przykład z primitive:

var f1 = function(a){
    a = 2;
}
var f2 = function(){
    var a = 1;
    f1(a);
    console.log(a);
}

Wywołanie f2 powoduje wypisanie wartości " a " jako 1.

 9
Author: yallam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-16 02:43:28

W interesie stworzenia prostego przykładu, który używa const...

const myRef = { foo: 'bar' };
const myVal = true;

function passes(r, v) {
  r.foo = 'baz';
  v = false;
}

passes(myRef, myVal);

console.log(myRef, myVal); // Object {foo: "baz"} true
 5
Author: 4m1r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-22 19:12:25

W praktyce, Alnitak jest poprawny i ułatwia zrozumienie, ale ostatecznie w JavaScript wszystko jest przekazywane przez wartość.

Jaka jest "wartość" obiektu? Jest to odniesienie do obiektu.

Kiedy przekazujesz obiekt, otrzymujesz kopię tej wartości (stąd 'Kopia referencji', którą opisał Alnitak). Jeśli zmienisz tę wartość, nie zmienisz oryginalnego obiektu; zmienisz kopię tego odniesienia.

 4
Author: Pete Campbell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-16 02:14:25

Zmienne"globalne" JavaScript są członkami obiektu window. Dostęp do referencji można uzyskać jako członek obiektu window.

var v = "initialized";

function byref(ref) {
  window[ref] = "changed by ref";
}

byref((function(){for(r in window){if(window[r]===v){return(r);}}})());
// It could also be called like... byref('v');
console.log(v); // outputs changed by ref

Uwaga, powyższy przykład nie będzie działał dla zmiennych zadeklarowanych w funkcji.

 3
Author: tony41780,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-16 02:44:29

Bez puryzmów, myślę, że najlepszym sposobem na emulację argumentu skalarnego przez odniesienie w JavaScript jest użycie obiektu, jak mówi poprzednia odpowiedź.

Jednak robię trochę inaczej:

Zrobiłem przypisanie obiektu wewnątrz wywołania funkcji, więc można zobaczyć parametry referencyjne w pobliżu wywołania funkcji. Zwiększa czytelność źródła.

W deklaracji funkcji, umieszczam właściwości jak komentarz, z tego samego powodu: czytelność.

var r;

funcWithRefScalars(r = {amount:200, message:null} );
console.log(r.amount + " - " + r.message);


function funcWithRefScalars(o) {  // o(amount, message)
  o.amount  *= 1.2;
  o.message = "20% increase";
}

W powyższy przykład, null wskazuje wyraźnie wyjściowy parametr odniesienia.

Wyjście:

240 - 20% Increase

Po stronie klienta, console.log należy zastąpić przez alert.

★ ★ ★

Inna metoda, która może być jeszcze bardziej czytelna:

var amount, message;

funcWithRefScalars(amount = [200], message = [null] );
console.log(amount[0] + " - " + message[0]);

function funcWithRefScalars(amount, message) {  // o(amount, message)
   amount[0]  *= 1.2;
   message[0] = "20% increase";
}

Tutaj nie musisz nawet tworzyć nowych fałszywych nazw, jak r powyżej.

 1
Author: Paulo Buchsbaum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-16 02:54:48

Prymitywy są przekazywane przez wartość. Ale w przypadku, gdy musisz tylko odczytać wartość primitve (a wartość nie jest znana w czasie, gdy funkcja jest wywoływana), możesz przekazać funkcję, która pobiera wartość w momencie, gdy jej potrzebujesz.

function test(value) {
  console.log('retrieve value');
  console.log(value());
}

// call the function like this
var value = 1;
test(() => value);
 0
Author: michal.jakubeczy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-24 12:08:55

Nie widzę pass-by-reference w przykładach, w których ludzie próbują to zademonstrować. Widzę tylko pass-by-value .

W przypadku zmiennych, które zawierają odniesienie do obiektu, odniesienie jest wartością tych zmiennych, a zatem odniesienie jest przekazywane, które jest wtedy pass-by-value.

W takim stwierdzeniu,

var a = {
  b: "foo",
  c: "bar"
};

Wartość " a " nie jest obiektem, lecz (jak dotąd) odniesieniem do niego. Innymi słowy, obiekt nie znajduje się w zmiennej a - jest do niej odniesienie. Myślę, że jest to coś, co wydaje się trudne dla programistów, którzy są głównie zaznajomieni z JavaScript. Ale jest to łatwe dla ludzi, którzy znają również np. Javę, C# i C.

 0
Author: Juhani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-16 02:56:55

Obiekty są zawsze przekazywane przez odniesienie, a prymitywy przez wartość. Po prostu zachowaj ten parametr pod tym samym adresem dla obiektów.

Oto kod do zilustrowania tego, co mam na myśli (spróbuj w piaskownicy JavaScript, takiej jak https://js.do/).

Niestety nie możesz zachować tylko adresu parametru; zachowujesz również wszystkie oryginalne wartości członkowskie.

a = { key: 'bevmo' };
testRetain(a);
document.write(' after function ');
document.write(a.key);


function testRetain (b)
{
    document.write(' arg0 is ');
    document.write(arguments[0].key);
    b.key = 'passed by reference';
    var retain = b; // Retaining the original address of the parameter

    // Address of left set to address of right, changes address of parameter
    b = {key: 'vons'}; // Right is a new object with a new address
    document.write(' arg0 is ');
    document.write(arguments[0].key);

    // Now retrieve the original address of the parameter for pass by reference
    b = retain;
    document.write(' arg0 is ');
    document.write(arguments[0].key);
}

Wynik:

Arg0 is bevmo arg0 is vons arg0 is passed by reference after function passed by odniesienie

 0
Author: user3015682,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-16 02:59:17