Question JavaScript est-il un langage de référence ou de transmission par valeur?


Les types primitifs (Number, String, etc.) sont passés par valeur, mais les objets sont inconnus, car ils peuvent être tous deux passés par valeur (dans le cas où nous considérons qu'une variable contenant un objet est en fait une référence à l'objet ) et passé-par-référence (quand on considère que la variable à l'objet détient l'objet lui-même).

Bien que cela n'a pas vraiment d'importance à la fin, je veux savoir quelle est la bonne façon de présenter les arguments qui passent les conventions. Existe-t-il un extrait de la spécification JavaScript, qui définit ce que devrait être la sémantique à ce sujet?


1137
2018-02-05 21:23


origine


Réponses:


C'est intéressant en Javascript. Considérez cet exemple:

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

Cela produit la sortie:

10
changed
unchanged
  • Si c'était pur passer par la valeur, puis changer obj1.item n'aurait aucun effet sur le obj1 en dehors de la fonction.
  • Si c'était pur passage par référence, alors tout aurait changé. num serait 100, et obj2.item lirait "changed".

Au lieu de cela, la situation est que l'élément transmis est transmis par valeur. Mais l'élément qui est passé par valeur est se une référence. Techniquement, cela s'appelle appel par partage.

En termes pratiques, cela signifie que si vous modifiez le paramètre lui-même (comme avec num et obj2), cela n'affectera pas l'élément qui a été introduit dans le paramètre. Mais si vous changez le INTERNALS du paramètre, qui va se propager en arrière (comme avec obj1).


1359
2018-03-15 16:38



C'est toujours passer par la valeur, mais pour les objets la valeur de la variable est une référence. À cause de cela, quand vous passez un objet et changez son membres, ces changements persistent en dehors de la fonction. Cela le rend Regardez comme passe par référence. Mais si vous modifiez réellement la valeur de la variable d'objet, vous verrez que le changement ne persiste pas, prouvant qu'il est vraiment passé par la valeur.

Exemple:

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

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

var x = {member:"foo"};

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

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

Sortie:

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

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

376
2018-02-05 21:37



La variable ne "tient" pas l'objet, elle contient une référence. Vous pouvez assigner cette référence à une autre variable, maintenant les deux référencent le même objet. C'est toujours passer en valeur (même si cette valeur est une référence ...).

Il n'y a aucun moyen de modifier la valeur contenue dans une variable passée en paramètre, ce qui serait possible si JS supportait le passage par référence.


132
2017-08-04 11:06



Mes 2 Cents ... C'est ainsi que je le comprends. (N'hésitez pas à me corriger si je me trompe)

Il est temps de jeter tout ce que vous savez sur le passage en valeur / référence.

Parce que dans JavaScript, peu importe qu'il soit passé par valeur ou par référence ou autre. Ce qui compte, c'est la mutation par rapport à l'affectation des paramètres passés dans une fonction.

OK, laissez-moi faire de mon mieux pour expliquer ce que je veux dire. Disons que vous avez quelques objets.

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

Ce que nous avons fait est "affectation" ... Nous avons assigné 2 objets vides séparés aux variables "object1" et "object2".

Maintenant, disons que nous aimons mieux object1 ... Donc, nous "assignons" une nouvelle variable.

var favoriteObject = object1;

Ensuite, pour une raison quelconque, nous décidons que nous aimons mieux l'objet 2. Donc, nous faisons simplement une petite réaffectation.

favoriteObject = object2;

Rien n'est arrivé à object1 ou à object2. Nous n'avons pas changé de données du tout. Tout ce que nous avons fait, c'est ré-assigner quel est notre objet préféré. Il est important de savoir que object2 et favoriteObject sont tous deux affectés au même objet. Nous pouvons changer cet objet via l'une de ces variables.

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

OK, maintenant regardons les primitives comme les chaînes par exemple

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

Encore une fois, nous choisissons un favori.

var favoriteString = string1;

Nos variables favoriteString et string1 sont affectées à 'Hello world'. Maintenant, que se passe-t-il si nous voulons changer notre chaîne favorite ??? Qu'est-ce qui va arriver ???

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

Oh oh ... Qu'est-ce qui est arrivé. Nous n'avons pas pu changer string1 en changeant favoriteString ... Pourquoi ?? parce que les chaînes sont immuables et nous ne l'avons pas muté. Tout ce que nous avons fait était "RE ASSIGN" favoriteString à une nouvelle chaîne. Cela l'a essentiellement déconnecté de string1. Dans l'exemple précédent, lorsque nous avons renommé notre objet, nous n'avons rien assigné. (Eh bien, en fait ... nous l'avons fait, nous avons assigné la propriété name à une nouvelle chaîne.) Au lieu de cela, nous avons simplement muté l'objet qui maintient les connexions entre les 2 variables et les objets sous-jacents.

Maintenant, sur les fonctions et les paramètres de passage .... Lorsque vous appelez une fonction, et passez un paramètre, ce que vous faites essentiellement est "affectation" à une nouvelle variable, et cela fonctionne exactement comme si vous avez simplement assigné en utilisant le signe égal (=).

Prenez ces exemples.

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'

Maintenant, la même chose, mais avec une fonction

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

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

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

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

OK, donnons maintenant quelques exemples en utilisant des objets à la place ... d'abord, sans la fonction.

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

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

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

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

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

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

Maintenant, la même chose, mais avec un appel de fonction

function myFunc(otherObj) {

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

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

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

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

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

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

OK, si vous lisez tout ce post, peut-être que vous avez maintenant une meilleure compréhension de la façon dont les appels de fonction fonctionnent en javascript. Peu importe que quelque chose soit passé par référence ou par valeur ... Ce qui compte, c'est l'affectation vs la mutation.

Chaque fois que vous passez une variable à une fonction, vous êtes "Affectation" à quel que soit le nom de la variable de paramètre, exactement comme si vous utilisiez le signe égal (=).

Rappelez-vous toujours que le signe égal (=) signifie l'affectation. Rappelez-vous toujours que le passage d'un paramètre à une fonction implique également une affectation. Ils sont identiques et les 2 variables sont connectées exactement de la même manière.

Le seul moment de la modification d'une variable affecte une variable différente lorsque l'objet sous-jacent est muté.

Il ne sert à rien de faire une distinction entre les objets et les primitives, car cela fonctionne de la même manière que si vous n'aviez pas de fonction et que vous utilisiez simplement le signe égal à assigner à une nouvelle variable.

Le seul gotcha est quand le nom de la variable que vous passez dans la fonction est le même que le nom du paramètre de la fonction. Lorsque cela se produit, vous devez traiter le paramètre dans la fonction comme s'il s'agissait d'une toute nouvelle variable privée à la fonction (parce qu'elle l'est)

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

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

myFunc(myString);
console.log(myString); // logs 'test'

84
2017-09-26 04:06



Considérer ce qui suit:

  1. Les variables sont pointeursaux valeurs en mémoire.
  2. Réaffecter une variable pointe simplement ce pointeur sur une nouvelle valeur.
  3. La réaffectation d'une variable n'affecte jamais les autres variables qui pointaient sur le même objet

Alors, oublie ça "passer par référence / valeur" ne vous accrochez pas à "passer par référence / valeur" parce que:

  1. Les termes ne sont utilisés que pour décrire comportement d'une langue, pas nécessairement la mise en œuvre sous-jacente réelle. À la suite de cette abstraction, les détails critiques qui sont essentiels pour une explication décente sont perdus, ce qui conduit inévitablement à la situation actuelle où un seul terme ne décrit pas adéquatement le comportement réel et des informations supplémentaires doivent être fournies
  2. Ces concepts n'ont pas été définis à l'origine dans le but de décrire javascript en particulier et je ne me sens donc pas obligé de les utiliser lorsqu'ils ne font qu'ajouter à la confusion.

Pour répondre à votre question: les pointeurs sont passés.


// 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'

Quelques derniers commentaires:

  • Il est tentant de penser que primitives sont appliquées par des règles spéciales tout en objets ne sont pas, mais les primitives sont simplement la fin de la chaîne de pointeur.
  • En dernier exemple, considérez pourquoi une tentative commune d'effacement d'un tableau ne fonctionne pas comme prévu.


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

a = [];
console.log(b); // [1,2]
// doesn't work because `b` is still pointing at the original array

57
2018-06-02 23:04



L'objet en dehors d'une fonction est passé dans une fonction en donnant une référence à l'obejct extérieur. Lorsque vous utilisez cette référence pour manipuler son objet, l'objet extérieur est donc affecté. Cependant, si à l'intérieur de la fonction vous avez décidé de pointer la référence vers quelque chose d'autre, vous n'avez pas du tout affecté l'objet extérieur, parce que tout ce que vous avez fait était de rediriger la référence vers quelque chose d'autre.


23
2018-02-13 11:00



Pensez-y comme ceci: ça passe toujours par la valeur. Cependant, la valeur d'un objet n'est pas l'objet lui-même, mais une référence à cet objet.

Voici un exemple, en passant un nombre (un type primitif)

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

Répéter cela avec un objet donne des résultats différents:

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 }

Un autre exemple:

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}

16
2018-02-05 21:49



Javascript est toujours passe-en-valeur, tout est de type valeur. Les objets sont des valeurs, les fonctions membres des objets sont des valeurs elles-mêmes (rappelez-vous que les fonctions sont des objets de première classe en Javascript). Aussi, en ce qui concerne le concept que tout en Javascript est un objet, c'est faux. Les chaînes, symboles, nombres, booléens, null et indéfinis sont primitives. À l'occasion, ils peuvent exploiter certaines fonctions membres et propriétés héritées de leurs prototypes de base, mais ce n'est que par commodité, cela ne signifie pas qu'ils sont eux-mêmes des objets. Essayez ce qui suit pour référence

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

Dans les deux alertes, vous trouverez la valeur non définie.


14
2017-12-30 02:20