Javascript por referência vs. por valor

Eu estou procurando algum bom material de leitura abrangente sobre quando o JavaScript passa algo por valor e quando por referência e ao modificar um item passado afeta o valor fora de uma function e quando não. Eu também estou interessado em quando atribuir a outra variável é por referência vs. por valor e se isso segue quaisquer regras diferentes do que passar como um parâmetro de function.

Fiz muita pesquisa e encontrei muitos exemplos específicos (muitos deles aqui no SO) a partir dos quais posso começar a juntar peças das regras reais, mas ainda não encontrei um documento único e bem escrito que descreve tudo.

Além disso, existem maneiras na linguagem para controlar se algo é passado por referência ou por valor?

Aqui estão alguns dos tipos de perguntas que quero entender. Esses são apenas exemplos – na verdade, estou procurando entender as regras pelas quais a linguagem passa, não apenas as respostas para exemplos específicos. Mas aqui estão alguns exemplos:

function f(a,b,c) { a = 3; b.push("foo"); c.first = false; } var x = 4; var y = ["eeny", "miny", "mo"]; var z = {first: true}; f(x,y,z); 

Quando os conteúdos de x, yez são alterados fora do escopo de f para todos os tipos diferentes?

 function f() { var a = ["1", "2", "3"]; var b = a[1]; a[1] = "4"; // what is the value of b now for all possible data types that the array in "a" might hold? } function f() { var a = [{yellow: "blue"}, {red: "cyan"}, {green: "magenta"}]; var b = a[1]; a[1].red = "tan"; // what is the value of b now and why? b.red = "black"; // did the value of a[1].red change when I assigned to b.red? } 

Se eu quiser fazer uma cópia totalmente independente de um object (sem referências), qual é a melhor maneira de fazer isso?

Meu entendimento é que isso é realmente muito simples:

  • Javascript é sempre passar por valor, mas quando uma variável se refere a um object (incluindo matrizes), o “valor” é uma referência ao object.
  • Alterar o valor de uma variável nunca altera a primitiva ou object subjacente, apenas aponta a variável para uma nova primitiva ou object.
  • No entanto, alterar uma propriedade de um object referenciado por uma variável altera o object subjacente.

Então, para trabalhar com alguns dos seus exemplos:

 function f(a,b,c) { // Argument a is re-assigned to a new value. // The object or primitive referenced by the original a is unchanged. a = 3; // Calling b.push changes its properties - it adds // a new property b[b.length] with the value "foo". // So the object referenced by b has been changed. b.push("foo"); // The "first" property of argument c has been changed. // So the object referenced by c has been changed (unless c is a primitive) c.first = false; } var x = 4; var y = ["eeny", "miny", "mo"]; var z = {first: true}; f(x,y,z); console.log(x, y, z.first); // 4, ["eeny", "miny", "mo", "foo"], false 

Exemplo 2:

 var a = ["1", "2", {foo:"bar"}]; var b = a[1]; // b is now "2"; var c = a[2]; // c now references {foo:"bar"} a[1] = "4"; // a is now ["1", "4", {foo:"bar"}]; b still has the value // it had at the time of assignment a[2] = "5"; // a is now ["1", "4", "5"]; c still has the value // it had at the time of assignment, ie a reference to // the object {foo:"bar"} console.log(b, c.foo); // "2" "bar" 

Javascript sempre passa por valor. No entanto, se você passar um object para uma function, o “valor” é realmente uma referência a esse object, portanto, a function pode modificar as propriedades desse object, mas não fazer com que a variável fora da function aponte para algum outro object .

Um exemplo:

 function changeParam(x, y, z) { x = 3; y = "new string"; z["key2"] = "new"; z["key3"] = "newer"; z = {"new" : "object"}; } var a = 1, b = "something", c = {"key1" : "whatever", "key2" : "original value"}; changeParam(a, b, c); // at this point a is still 1 // b is still "something" // c still points to the same object but its properties have been updated // so it is now {"key1" : "whatever", "key2" : "new", "key3" : "newer"} // c definitely doesn't point to the new object created as the last line // of the function with z = ... 

Sim, Javascript sempre passa por valor, mas em uma matriz ou object, o valor é uma referência a ele, então você pode ‘mudar’ o conteúdo.

Mas acho que você já leu no SO; aqui você tem a documentação que você quer:

http://snook.ca/archives/javascript/javascript_pass

  1. Variável do tipo primitivo como string, number são sempre passados ​​como pass by value.
  2. Matriz e Objeto são passados ​​como passar por referência ou passar por valor com base nessas duas condições.

    • Se você estiver alterando o valor desse object ou matriz com novo object ou matriz, ele será passado por valor.

      object1 = {item: "car"}; array1=[1,2,3];

    aqui você está atribuindo um novo object ou array a um antigo.você não está alterando o valor da propriedade do object antigo.assim, ele é passado por valor.

    • Se você estiver alterando um valor de propriedade de um object ou matriz, ele será transmitido por Referência.

      object1.item= "car"; array1[0]=9;

    aqui você está alterando um valor de propriedade do object antigo. Você não está atribuindo um novo object ou matriz a um antigo. Portanto, ele é passado por referência.

Código

  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