pass-by-reference passar - O JavaScript é uma linguagem de passagem por referência ou de passagem por valor?




variavel referencia (25)

Eu diria que é passar por cópia -

Considere argumentos e objetos variáveis ​​são objetos criados durante o contexto de execução criado no início da invocação da função - e seu valor / referência real passado para a função é armazenado nesses argumentos + objetos variáveis.

Simplesmente falando, para tipos primitivos, os valores são copiados no início da chamada de função, para o tipo de objeto, a referência é copiada.

Os tipos primitivos (Number, String, etc.) são passados ​​por valor, mas Objects são desconhecidos, porque podem ser passados ​​por valor (no caso de considerarmos que uma variável que contém um objeto é de fato uma referência ao objeto ) e passado por referência (quando consideramos que a variável para o objeto contém o próprio objeto).

Embora isso realmente não importe no final, eu quero saber qual é a maneira correta de apresentar os argumentos passando as convenções. Existe um trecho da especificação JavaScript, que define qual deve ser a semântica sobre isso?


Isso é pouco mais explicação para Passar por valor e Passar por referência (Javascript). Neste conceito, eles estão falando sobre passar a variável por referência e passar a variável por referência.

Passar por valor (tipo primitivo)

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
  • aplica-se a todos os tipos primitivos em JS (string, number, boolean, undefined, null).
  • a é alocada uma memória (digamos 0x001) eb cria uma cópia do valor na memória (digamos 0x002).
  • Assim, alterar o valor de uma variável não afeta o outro, pois ambos residem em dois locais diferentes.

Passe por referência (objetos)

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" }
  • Motor JS atribui o objeto para a variável c, ele aponta para alguma memória dizer (0x012)
  • quando d = c, neste passo d aponta para o mesmo local (0x012).
  • alterando o valor de qualquer valor de alteração para a variável.
  • funções são objetos

Caso especial, Passe por referência (objetos)

c = {"name" : "jane"}; 
console.log(c); // { "name" : "jane" }    
console.log(d); // { "name" : "doe" }
  • O operador equal (=) configura um novo espaço de memória ou endereço

É sempre passar por valor, mas para objetos o valor da variável é uma referência. Por causa disso, quando você passa um objeto e altera seus membros , essas alterações persistem fora da função. Isso faz com que pareça passar por referência. Mas se você realmente alterar o valor da variável de objeto, verá que a alteração não persiste, provando que é realmente passar por valor.

Exemplo:

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

Saída:

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

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

Eu encontrei o método extend da biblioteca Underscore.js muito útil quando eu quero passar um objeto como um parâmetro que pode ser modificado ou substituído inteiramente.

function replaceOrModify(aObj) {
  if (modify) {

    aObj.setNewValue('foo');

  } else {

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

Uma maneira fácil de determinar se algo é "passar por referência" é se você pode escrever uma função "swap". Por exemplo, em C, você pode fazer:

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

Se você não pode fazer o equivalente a isso em Javascript, não é "passar por referência".


A variável não "mantém" o objeto, ele contém uma referência. Você pode atribuir essa referência a outra variável, agora ambos fazem referência ao mesmo objeto. É sempre passar por valor (mesmo quando esse valor é uma referência ...).

Não há como alterar o valor mantido por uma variável passada como parâmetro, o que seria possível se JS suportasse a passagem por referência.


JavaScript passa tipos primitivos por valor e tipos de objeto por referência

Agora, as pessoas gostam de brigar incessantemente sobre se "passar por referência" é a maneira correta de descrever o que Java et al. realmente fazer. O ponto é este:

  1. Passar um objeto não copia o objeto.
  2. Um objeto passado para uma função pode ter seus membros modificados pela função.
  3. Um valor primitivo passado para uma função não pode ser modificado pela função. Uma cópia é feita.

No meu livro, isso é chamado de passagem por referência.

- Brian Bi - Quais linguagens de programação são passadas por referência?


  1. Primitivos (Número, Booleano) são passados ​​por valor.
    • As cordas são imutáveis, por isso não importa para elas.
  2. Objetos são passados ​​por referência (a referência é passada por valor)

Primitivos são passados ​​por valor e objetos são passados ​​por referência. Isso é bem diferente de outras linguagens como C, VB ou Delphi. Eu não posso dizer como eles lidam com objetos e primitivos exatamente, mas eu sei que VB e Delphi podem (e devem) ser especificados.

O php faz algo similar desde a versão 5: todos os objetos são passados ​​por referência, mas todos os primitivos podem ser passados ​​por referência, se precedidos por um e comercial (&). Caso contrário, as primitivas são passadas por valor.

Então, em javascript, se eu passar um objeto X para uma função através de um parâmetro, ele ainda será X. Se você estiver alterando dados dentro da função (ou qualquer outro objeto, mas isso não é importante) esse novo valor também está disponível fora do função.


Eu li essas respostas várias vezes, mas não consegui entender até que eu aprendi sobre a definição técnica de "Call by sharing" como denominada por Barbara Liskov.

A semântica de chamada por compartilhamento difere de chamada por referência em que atribuições para função argumentos dentro da função não são visíveis para o chamador (ao contrário da semântica de referência), por exemplo, se uma variável foi passada, não é possível para simular uma atribuição nessa variável no escopo do chamador. No entanto, como a função tem acesso ao mesmo objeto que o chamador (nenhuma cópia é feita), as mutações para esses objetos, se os objetos são mutáveis, são visíveis para o chamador, o que pode parecer diferente da chamada por valor. semântica. Mutações de um objeto mutável dentro da função são visíveis para o chamador porque o objeto não é copiado ou clonado - ele é compartilhado.

Ou seja, as referências de parâmetro são alteráveis ​​se você acessar o próprio valor do parâmetro. Por outro lado, a atribuição a um parâmetro desaparecerá após a avaliação e não será acessível ao chamador da função.


Em uma linguagem de baixo nível, se você quiser passar uma variável por referência, você tem que usar uma sintaxe específica na criação da função:

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

O &ageé uma referência para myAge, mas se você quiser o valor que você tem que converter a referência, usando *age.

Javascript é uma linguagem de alto nível que faz essa conversão para você. Portanto, embora os objetos sejam passados ​​por referência, o idioma converte o parâmetro de referência no valor. Você não precisa usar &, na definição de função, para passá-lo por referência, nem *, no corpo da função, para converter a referência para o valor, JS faz isso para você.

É por isso que quando você tenta alterar um objeto dentro de uma função, substituindo seu valor (ie age = {value:5}), a mudança não persiste, mas se você alterar suas propriedades (ie age.value = 5), isso acontece.

Saber mais


Semântica!! Definir definições concretas fará com que algumas respostas e comentários sejam incompatíveis, já que eles não estão descrevendo a mesma coisa, mesmo quando usam as mesmas palavras e frases, mas é fundamental superar a confusão (especialmente para novos programadores).

Primeiro de tudo, há vários níveis de abstração que nem todos parecem entender. Programadores mais novos que aprenderam em linguagens de 4ª ou 5ª geração podem ter dificuldade em se concentrar em conceitos familiares a assembly ou programadores C que não são divididos por ponteiros em ponteiros para ponteiros. Passagem por referência não significa simplesmente a capacidade de alterar um objeto referenciado usando uma variável de parâmetro de função.

Variável : Conceito combinado de um símbolo que faz referência a um valor em um determinado local na memória. Este termo é geralmente muito carregado para ser usado sozinho na discussão de detalhes.

Símbolo : String de texto usada para se referir a variável (ou seja, nome da variável).

Valor : Bits particulares armazenados na memória e referenciados usando o símbolo da variável.

Localização da memória : onde o valor de uma variável é armazenado. (O local em si é representado por um número separado do valor armazenado no local.)

Parâmetro de função : Variável declarada em uma definição de função, usada para referenciar variáveis ​​passadas para a função.

Argumento da função : Variável fora da função que é passada para a função pelo chamador.

Variável de objeto : Variável cujo valor subjacente básico não é o "objeto" em si, mas seu valor é um ponteiro (valor de localização da memória) para outro local na memória onde os dados reais do objeto são armazenados. Na maioria das linguagens de geração mais alta, o aspecto "ponteiro" é efetivamente ocultado pela desconexão automática em vários contextos.

Variável primitiva : variável cujo valor é o valor real. Mesmo esse conceito pode ser complicado por contextos de auto-boxing e objetos de várias linguagens, mas as ideias gerais são de que o valor da variável é o valor real representado pelo símbolo da variável, em vez de um ponteiro para outra localização de memória.

Argumentos e parâmetros de função não são a mesma coisa. Além disso, o valor de uma variável não é o objeto da variável (como já foi apontado por várias pessoas, mas aparentemente ignorado). Essas distinções são críticas para o entendimento adequado.

Valor por passagem ou Chamada por compartilhamento (para objetos): O valor do argumento da função é COPIED para outro local da memória que é referenciado pelo símbolo do parâmetro da função (independentemente de estar na pilha ou no heap). Em outras palavras, o parâmetro da função recebeu uma cópia do valor do argumento passado ... E (crítico) o valor do argumento NÃO É NUNCA ATUALIZADO / ALTERADO / MUDADO pela função de chamada. Lembre-se, o valor de uma variável de objeto NÃO é o objeto em si, e sim o ponteiro para o objeto, portanto, passar uma variável de objeto por valor copia o ponteiro para a variável de parâmetro de função. O valor do parâmetro da função aponta para exatamente o mesmo objeto na memória. Os dados do objeto em si podem ser alterados diretamente através do parâmetro da função, MAS o valor do argumento da função NÃO É NUNCA ATUALIZADO, então ele continuará apontando para o mesmoobjeto ao longo e até mesmo após a chamada de função (mesmo se os dados do objeto foram alterados ou se o parâmetro de função foi atribuído a um objeto diferente). É incorreto concluir que o argumento da função foi passado por referência apenas porque o objeto referenciado é atualizável por meio da variável do parâmetro da função.

Chamada / passagem por referência : O valor do argumento da função pode / será atualizado diretamente pelo parâmetro da função correspondente. Se isso ajudar, o parâmetro da função se torna um "alias" efetivo para o argumento - eles efetivamente se referem ao mesmo valor no mesmo local de memória. Se um argumento de função é uma variável de objeto, a capacidade de alterar os dados do objeto não é diferente do caso de passagem por valor, pois o parâmetro da função ainda apontará para o mesmo objeto que o argumento. Mas, no caso da variável de objeto, se o parâmetro da função estiver definido para um objeto completamente diferente, o argumento também apontará para o objeto diferente - isso não acontece no caso de passagem por valor.

JavaScript não passa por referência. Se você ler atentamente, perceberá que todas as opiniões contrárias entendem mal o que se entende por passagem por valor e concluem falsamente que a capacidade de atualizar os dados de um objeto por meio do parâmetro function é sinônimo de "passagem por valor".

Objeto clone / copy : Um novo objeto é criado e os dados do objeto original são copiados. Esta pode ser uma cópia profunda ou uma cópia superficial, mas o ponto é que um novo objeto é criado. Criar uma cópia de um objeto é um conceito separado de passagem por valor. Algumas linguagens distinguem entre objeto de classe e estruturas (ou similares) e podem ter comportamento diferente para passar variáveis ​​dos diferentes tipos. Mas o JavaScript não faz nada assim automaticamente ao passar variáveis ​​de objeto. Mas a ausência de clonagem automática de objetos não se traduz em passagem por referência.


Em alguns casos, isso pode ser útil para alterar anArg:

function alterMyArg(func) {
    // process some data
    // ...
    func(data);
}

alertMyArg(function(d) {anArg = d;});

Minha maneira simples de entender isso ...

  • Ao chamar uma função, você está passando o conteúdo (referência ou valor) das variáveis ​​de argumento, não as variáveis ​​em si.

    var var1 = 13;
    var var2 = { prop: 2 };
    
    //13 and var2's content (reference) are being passed here
    foo(var1, var2); 
  • Dentro da função, variáveis ​​de parâmetro inVar1e inVar2receba o conteúdo sendo passado.

    function foo(inVar1, inVar2){
        //changing contents of inVar1 and inVar2 won't affect variables outside
        inVar1 = 20;
        inVar2 = { prop: 7 };
    }
  • Desde que inVar2recebeu a referência de { prop: 2 }, você pode alterar o valor da propriedade do objeto.

    function foo(inVar1, inVar2){
        inVar2.prop = 7; 
    }

Para os advogados de linguagens de programação, passei pelas seguintes seções do ECMAScript 5.1 (que é mais fácil de ler do que a edição mais recente), e ir tão longe quanto asking na lista de discussão do ECMAScript.

TL; DR : Tudo é passado por valor, mas as propriedades dos Objetos são referências, e a definição de Objeto está faltando assustadoramente no padrão.

Construção de listas de argumentos

A Seção 11.2.4 "Listas de Argumentos" diz o seguinte ao produzir uma lista de argumentos consistindo de apenas 1 argumento:

A ArgumentList de produção: AssignmentExpression é avaliada da seguinte maneira:

  1. Seja ref o resultado da avaliação de AssignmentExpression.
  2. Seja arg seja GetValue (ref).
  3. Devolve uma lista cujo único item é arg.

A seção também enumera casos em que a lista de argumentos tem 0 ou> 1 argumentos.

Assim, tudo é passado por referência.

Acesso de propriedades do objeto

Seção 11.2.1 "Accessors de Propriedade"

A produção MemberExpression: MemberExpression [Expression] é avaliada da seguinte maneira:

  1. Seja o baseReference o resultado da avaliação do MemberExpression.
  2. Seja baseValue seja GetValue (baseReference).
  3. Deixe propertyNameReference ser o resultado da avaliação de Expressão.
  4. Deixe propertyNameValue ser GetValue (propertyNameReference).
  5. Chame CheckObjectCoercible (baseValue).
  6. Deixe propertyNameString ser ToString (propertyNameValue).
  7. Se a produção sintática que está sendo avaliada estiver contida no código do modo estrito, seja estrito ser verdadeiro, senão se estrito seja falso.
  8. Retorna um valor do tipo Reference cujo valor base é baseValue e cujo nome referenciado é propertyNameString e cujo sinalizador de modo estrito é estrito.

Assim, as propriedades dos objetos estão sempre disponíveis como referência.

Na referência

É descrito na seção 8.7 "O tipo de especificação de referência", que as referências não são tipos reais no idioma - elas são usadas apenas para descrever o comportamento dos operadores delete, typeof e assignment.

Definição de "Objeto"

É definido na edição 5.1 que "Um Objeto é uma coleção de propriedades". Portanto, podemos inferir que o valor do objeto é a coleção, mas quanto ao que é o valor da coleção é mal definido na especificação e requer um pouco de effort para entender.


Uma explicação muito detalhada sobre como copiar, passar e comparar por valor e por referência está neste capítulo do livro "JavaScript: The Definitive Guide".

Antes de deixarmos o tópico de manipular objetos e matrizes por referência, precisamos esclarecer um ponto de nomenclatura. A frase "passar por referência" pode ter vários significados. Para alguns leitores, a frase refere-se a uma técnica de invocação de função que permite que uma função atribua novos valores a seus argumentos e tenha esses valores modificados visíveis fora da função. Esta não é a maneira como o termo é usado neste livro. Aqui, queremos dizer simplesmente que uma referência a um objeto ou matriz - não ao objeto em si - é passada para uma função. Uma função pode usar a referência para modificar propriedades do objeto ou elementos da matriz. Mas se a função substitui a referência por uma referência a um novo objeto ou matriz, essa modificação não é visível fora da função. Leitores familiarizados com o outro significado deste termo podem preferir dizer que objetos e matrizes são passados ​​por valor, mas o valor que é passado é na verdade uma referência em vez do próprio objeto.

Uma coisa que ainda não consigo descobrir. Verifique o código abaixo. Alguma ideia?

function A() {}
A.prototype.foo = function() {
    return 'initial value';
}


function B() {}
B.prototype.bar = A.prototype.foo;

console.log(A.prototype.foo()); //initial value
console.log(B.prototype.bar()); //initial value

A.prototype.foo = function() {
    return 'changed now';
}

console.log(A.prototype.foo()); //changed now
console.log(B.prototype.bar()); //Why still 'initial value'???

compartilhando o que eu sei de referências em javascript

Em Javascript, os objetos são armazenados como referências:

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


É interessante em Javascript. Considere este exemplo:

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

Isso produz a saída:

10
changed
unchanged
  • Se fosse puro passar por valor, então alterar obj1.item não teria efeito sobre o obj1 fora da função.
  • Se fosse pura passagem por referência, então tudo teria mudado. num seria 100 , e obj2.item seria "changed" .

Em vez disso, a situação é que o item passado é passado por valor. Mas o item que é passado por valor é em si uma referência. Tecnicamente, isso é chamado de call-by-sharing .

Em termos práticos, isso significa que, se você alterar o próprio parâmetro (como num e obj2 ), isso não afetará o item que foi alimentado no parâmetro. Mas se você alterar os INTERNOS do parâmetro, isso se propagará de volta (como com obj1 ).


Meus 2 centavos ... É assim que eu entendo. (Sinta-se livre para me corrigir se eu estiver errado)

É hora de jogar fora tudo o que você sabe sobre passar por valor / referência.

Porque em JavaScript, não importa se é passado por valor ou por referência ou qualquer outra coisa. O que importa é a mutação vs atribuição dos parâmetros passados ​​em uma função.

OK, deixe-me fazer o meu melhor para explicar o que quero dizer. Vamos dizer que você tenha alguns objetos.

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

O que fizemos foi "atribuição" ... Nós atribuímos 2 objetos vazios separados às variáveis ​​"objeto1" e "objeto2".

Agora, digamos que gostamos de object1 melhor ... Então, "designamos" uma nova variável.

var favoriteObject = object1;

Em seguida, por qualquer motivo, decidimos que gostamos mais do objeto 2. Então, nós simplesmente fazemos uma pequena reatribuição.

favoriteObject = object2;

Nada aconteceu com object1 ou object2. Nós não alteramos nenhum dado. Tudo o que fizemos foi reatribuir qual é o nosso objeto favorito. É importante saber que object2 e favoriteObject são ambos atribuídos ao mesmo objeto. Podemos mudar esse objeto por meio dessas variáveis.

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

OK, agora vamos olhar primitivos como strings por exemplo

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

Mais uma vez, escolhemos um favorito.

var favoriteString = string1;

Ambas as nossas variáveis ​​favoriteString e string1 são atribuídas a 'Hello world'. Agora, e se quisermos mudar a nossa favoriteString ??? O que vai acontecer???

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

Uh oh .... o que aconteceu. Não foi possível alterar a string1 alterando favoriteString ... Por que ?? porque as strings são imutáveis ​​e nós não a transformamos. Tudo o que fizemos foi "RE ASSIGN" favoriteString para uma nova string. Isso essencialmente desconectou da string1. No exemplo anterior, quando renomeamos nosso objeto, não atribuímos nada. (Bem, na verdade ... nós fizemos, atribuímos a propriedade name a uma nova string.) Em vez disso, simplesmente transformamos o objeto que mantém as conexões entre as duas variáveis ​​e os objetos subjacentes.

Agora, para funções e parâmetros de passagem ... Quando você chama uma função, e passa um parâmetro, o que você está fazendo essencialmente é "atribuição" para uma nova variável, e ela funciona exatamente como se você simplesmente tivesse designado usando a função sinal igual (=).

Tome estes exemplos.

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'

Agora, a mesma coisa, mas com uma função

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, agora vamos dar alguns exemplos usando objetos ... primeiro, sem a função.

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

Agora, a mesma coisa, mas com uma chamada de função

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, se você ler todo este post, talvez agora você tenha um melhor entendimento de como as chamadas de função funcionam em javascript. Não importa se algo é passado por referência ou por valor ... O que importa é atribuição vs mutação.

Toda vez que você passa uma variável para uma função, você está "Atribuindo" a qualquer que seja o nome da variável de parâmetro, como se você tivesse usado o sinal de igual (=).

Lembre-se sempre de que o sinal de igual (=) significa atribuição. Lembre-se sempre de que passar um parâmetro para uma função também significa atribuição. Eles são iguais e as duas variáveis ​​são conectadas exatamente da mesma maneira.

A única vez que modificar uma variável afeta uma variável diferente é quando o objeto subjacente é mutado.

Não faz sentido fazer uma distinção entre objetos e primitivos, porque funciona da mesma maneira como se você não tivesse uma função e apenas usasse o sinal de igual para atribuir a uma nova variável.

A única pegadinha é quando o nome da variável que você passa para a função é o mesmo que o nome do parâmetro da função. Quando isso acontece, você tem que tratar o parâmetro dentro da função como se fosse uma variável inteiramente nova privada para a função (porque é)

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'

Há alguma discussão sobre o uso do termo "passar por referência" em JS here , mas para responder à sua pergunta:

Um objeto é automaticamente passado por referência, sem a necessidade de especificá-lo

(Do artigo mencionado acima.)


Em JavaScript, o tipo do valor controla apenas se esse valor será atribuído por cópia de valor ou por cópia de referência .

Os valores primitivos são sempre atribuídos / passados ​​por cópia de valor :

  • null
  • undefined
  • corda
  • número
  • boleano
  • símbolo no ES6

Valores compostos são sempre atribuídos / passados ​​por cópia de referência

  • objetos
  • matrizes
  • função

Por exemplo

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]

No trecho acima, como 2 é uma primitiva escalar, a contém uma cópia inicial desse valor e b recebe outra cópia do valor. Ao mudar b , você não está alterando o valor em a .

Mas c e d são referências separadas para o mesmo valor compartilhado [1,2,3] , que é um valor composto. É importante notar que nem c nem d mais "possui" o valor [1,2,3] - ambos são apenas iguais referências iguais ao valor. Portanto, ao usar qualquer referência para modificar ( .push(4) ) o próprio valor da array compartilhada, ele afetará apenas o valor compartilhado e as duas referências farão referência ao valor recém-modificado [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]

Quando fazemos a atribuição b = [4,5,6] , não estamos fazendo absolutamente nada para afetar onde a ainda está fazendo referência ( [1,2,3] ). Para fazer isso, b teria que ser um ponteiro para uma referência ao invés de uma array - mas essa capacidade não existe no 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]

Quando passamos no argumento a , ele atribui uma cópia da referência a para x . x e a são referências separadas apontando para o mesmo valor [1,2,3] . Agora, dentro da função, podemos usar essa referência para alterar o próprio valor ( push(4) ). Mas quando fazemos a atribuição x = [4,5,6] , isso não afeta de forma alguma onde a referência inicial a está apontando - ainda aponta para o valor (agora modificado) [1,2,3,4] .

Para transmitir efetivamente um valor composto (como uma array ) por cópia de valor, você precisa fazer uma cópia manualmente, para que a referência passada ainda não aponte para o original. Por exemplo:

foo( a.slice() );

Valor composto (objeto, matriz, etc) que pode ser passado por cópia de referência

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

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

Aqui, obj age como um wrapper para a propriedade primitiva escalar a . Quando passado para foo(..) , uma cópia da referência obj é passada e configurada para o parâmetro wrapper . Agora podemos usar a referência do wrapper para acessar o objeto compartilhado e atualizar sua propriedade. Depois que a função terminar, obj.a verá o valor atualizado 42 .

Source


Objeto fora de uma função é passado para uma função, dando uma referência ao objeto externo. Quando você usa essa referência para manipular seu objeto, o objeto externo é afetado. No entanto, se dentro da função você decidiu apontar a referência para outra coisa, você não afetou o objeto de fora, porque tudo que você fez foi redirecionar a referência para outra coisa.


Valores simples dentro de funções não alteram esses valores fora da função (eles são passados ​​por valor), enquanto os valores complexos (são passados ​​por referência).

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

A explicação mais sucinta que encontrei foi no guia de estilo do AirBNB :

  • Primitivos : Quando você acessa um tipo primitivo, você trabalha diretamente em seu valor

    • corda
    • número
    • boleano
    • nulo
    • Indefinido

Por exemplo:

var foo = 1,
    bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9
  • Complexo : Quando você acessa um tipo complexo, você trabalha em uma referência ao seu valor

    • objeto
    • matriz
    • função

Por exemplo:

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

bar[0] = 9;

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

Ou seja, tipos efetivamente primitivos são passados ​​por valor e tipos complexos são passados ​​por referência.


OK, 6 anos de idade fecha fã. Você quer ouvir o exemplo mais simples de fechamento?

Vamos imaginar a próxima situação: um motorista está sentado em um carro. Esse carro está dentro de um avião. Avião está no aeroporto. A capacidade do motorista de acessar as coisas fora de seu carro, mas dentro do avião, mesmo que esse avião saia de um aeroporto, é um fechamento. É isso aí. Quando você fizer 27 anos, veja a explicação mais detalhada ou o exemplo abaixo.

Aqui está como eu posso converter minha história de avião no código.

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");





javascript pass-by-reference pass-by-value