JavaScript é uma linguagem passagem por referência ou passagem por valor?

Feb 06 2009

Os tipos primitivos (número, string, etc.) são passados ​​por valor, mas os objetos são desconhecidos, pois podem ser passados ​​por valor (no caso de considerarmos que uma variável que contém um objeto é na verdade 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 por convenções. Existe um trecho da especificação JavaScript, que define qual deve ser a semântica em relação a isso?

Respostas

1665 deworde Sep 04 2010 at 00:17

É 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 obj1não fosse uma referência, a mudança obj1.itemnão teria efeito no obj1exterior da função.
  • Se o argumento fosse uma referência adequada, tudo teria mudado. numseria 100, e obj2.itemleria "changed".

Em vez disso, a situação é que o item passado é passado por valor. Mas o item que é passado por valor é ele próprio uma referência. Tecnicamente, isso é chamado de chamada por compartilhamento .

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

493 TimGoodman Mar 15 2011 at 23:38

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

Exemplo:

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

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

var x = { member: "foo" };

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

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

Resultado:

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

before changeMember: foo
in changeMember: bar
after changeMember: bar
156 Shog9 Feb 06 2009 at 04:37

A variável não "mantém" o objeto; contém uma referência. Você pode atribuir essa referência a outra variável, e agora ambos fazem referência ao mesmo objeto. É sempre passado 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 JavaScript suportasse a passagem por referência.

115 RayPerea Aug 04 2014 at 18:06

Meus dois centavos ... É assim que eu entendo. (Sinta-se à vontade para me corrigir se eu estiver errado)

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

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

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

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

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

Agora, digamos que gostamos mais de object1 ... Então, "atribuímos" uma nova variável.

var favoriteObject = object1;

Em seguida, por qualquer motivo, decidimos que gostamos mais do objeto 2. Então, fazemos uma pequena redefinição.

favoriteObject = object2;

Nada aconteceu com object1 ou object2. Não alteramos nenhum dado. Tudo o que fizemos foi reatribuir qual é o nosso objeto favorito. É importante saber que object2 e favoriteObject são atribuídos ao mesmo objeto. Podemos mudar esse objeto por meio de qualquer uma 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 para primitivos como strings, por exemplo

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

Novamente, escolhemos um favorito.

var favoriteString = string1;

Ambas as variáveis ​​favoriteString e string1 são atribuídas a 'Hello world'. Agora, e se quisermos mudar nosso 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 string1 alterando favoriteString ... Por quê ?? Porque não mudamos nosso objeto string . Tudo o que fizemos foi "RE ASSIGN" a variável favoriteString para uma nova string. Isso essencialmente o desconectou da string1. No exemplo anterior, quando renomeamos nosso objeto, não atribuímos nada. (Bem, não para a variável em si , ... nós, no entanto, atribuímos a propriedade name a uma nova string.) Em vez disso, alteramos o objeto que mantém as conexões entre as 2 variáveis ​​e os objetos subjacentes. (Mesmo se quiséssemos modificar ou transformar o próprio objeto string , não poderíamos, porque as strings são, na verdade, imutáveis ​​em JavaScript.)

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

Veja esses 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 ao invés ... 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 the variable
otherObj = {
    firstName: 'Jack',
    lastName: 'Frost'
};

// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object has no influence on 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 doesn't magically mutate 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ê leu 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.

Cada 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ê usasse 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 em JavaScript também significa atribuição. Eles são iguais e as 2 variáveis ​​estão conectadas exatamente da mesma maneira (o que quer dizer que não são, a menos que você conte que elas estão atribuídas ao mesmo objeto).

A única vez que "modificar uma variável" afeta uma variável diferente é quando o objeto subjacente é modificado (nesse caso, você não modificou a variável, mas o próprio objeto.

Não faz sentido fazer uma distinção entre objetos e primitivos, porque funciona exatamente 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.

O único problema é 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ê deve tratar o parâmetro dentro da função como se fosse uma variável totalmente 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'
75 geg Sep 26 2015 at 11:06

Considere o seguinte:

  1. Variáveis ​​são indicadores de valores na memória.
  2. Reatribuir uma variável meramente aponta esse ponteiro para um novo valor.
  3. Reatribuir uma variável nunca afetará outras variáveis ​​que estavam apontando para o mesmo objeto

Portanto, esqueça "passar por referência / valor" , não se preocupe com "passar por referência / valor" porque:

  1. Os termos são usados ​​apenas para descrever o comportamento de uma linguagem, não necessariamente a implementação real subjacente. Como resultado desta abstração, os detalhes críticos que são essenciais para uma explicação decente são perdidos, o que inevitavelmente leva à situação atual onde um único termo não descreve adequadamente o comportamento real e informações suplementares devem ser fornecidas
  2. Esses conceitos não foram definidos originalmente com a intenção de descrever o javascript em particular e, portanto, não me sinto obrigado a usá-los, pois só aumentam a confusão.

Para responder à sua pergunta: ponteiros são passados.


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

Alguns comentários finais:

  • É tentador pensar que os primitivos são impostos por regras especiais enquanto os objetos não, mas os primitivos são simplesmente o fim da cadeia de ponteiros.
  • Como um exemplo final, considere por que uma tentativa comum de limpar um array não funciona conforme o esperado.


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
24 user779764 Jun 03 2011 at 06:04

Um 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 externo de forma alguma, porque tudo o que você fez foi redirecionar a referência para outra coisa.

22 PhilMander Feb 13 2015 at 18:00

Pense assim: Sempre é passado por valor. No entanto, o valor de um objeto não é o objeto em si, mas uma referência a esse objeto.

Aqui está um exemplo, passando um número (um tipo primitivo)

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

Repetir isso com um objeto produz resultados diferentes:

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 }

Mais um exemplo:

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}
20 igor May 13 2011 at 05:20

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 manipulação de objetos e matrizes por referência, precisamos esclarecer um ponto de nomenclatura.

A frase "passagem por referência" pode ter vários significados. Para alguns leitores, a frase se refere a uma técnica de invocação de função que permite a uma função atribuir novos valores a seus argumentos e ter esses valores modificados visíveis fora da função. Não é assim que o termo é usado neste livro.

Aqui, queremos dizer simplesmente que uma referência a um objeto ou array - não o 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 sobrescrever a referência com uma referência a um novo objeto ou matriz, essa modificação não será visível fora da função.

Os 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, e não o próprio objeto.

18 MichaelRoberts Feb 06 2009 at 04:49

JavaScript é sempre passado por valor ; tudo é do tipo valor.

Os objetos são valores e as funções-membro dos objetos são os próprios valores (lembre-se de que as funções são objetos de primeira classe em JavaScript). Além disso, em relação ao conceito de que tudo em JavaScript é um objeto ; isto está errado. Strings, símbolos, números, booleanos, nulos e indefinidos são primitivos .

Ocasionalmente, eles podem aproveitar algumas funções de membro e propriedades herdadas de seus protótipos básicos, mas isso é apenas por conveniência. Isso não significa que eles próprios sejam objetos. Experimente o seguinte para referência:

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

Em ambos os alertas, você encontrará o valor indefinido.

13 zangw Dec 30 2015 at 09:20

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 ​​pela cópia do valor :

  • null
  • undefined
  • fragmento
  • número
  • boleano
  • símbolo em ES6

Os 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 fragmento acima, por 2ser uma primitiva escalar, acontém uma cópia inicial desse valor e bé atribuída outra cópia do valor. Ao alterar b, você não está de forma alguma alterando o valor em a.

Mas ce dsão referências separadas para o mesmo valor compartilhado [1,2,3], que é um valor composto. É importante observar que nem cnem dmais "possui" o [1,2,3]valor - ambos são apenas referências de pares iguais ao valor. Portanto, ao usar qualquer uma das referências para modificar ( .push(4)) o próprio arrayvalor compartilhado real , ele está afetando apenas um valor compartilhado e ambas as 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 aainda está referenciando ( [1,2,3]). Para fazer isso, bteria que ser um ponteiro em avez de uma referência ao array- mas esse recurso 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 o argumento a, ele atribui uma cópia da areferência a x. xe asão referências separadas apontando para o mesmo [1,2,3]valor. 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 para onde a referência inicial aestá apontando - ainda aponta para o valor (agora modificado) [1,2,3,4].

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

foo( a.slice() );

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

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

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

Aqui, objatua como um invólucro para a propriedade primitiva escalar a. Quando passada para foo(..), uma cópia da objreferência é passada e definida para o wrapperparâmetro. Agora podemos usar a wrapperreferência para acessar o objeto compartilhado e atualizar sua propriedade. Depois que a função terminar, obj.averá o valor atualizado 42.

Fonte

10 kianasirzadeh Nov 14 2019 at 07:48

bem, é sobre 'desempenho' e 'velocidade' e na palavra simples 'gerenciamento de memória' em uma linguagem de programação.

em javascript, podemos colocar valores em duas camadas: type1 - objectse type2 -todos os outros tipos de valor, como string& boolean& etc

se você imaginar a memória como abaixo de quadrados que em cada um deles apenas um valor type2 pode ser salvo:

cada valor type2 (verde) é um único quadrado, enquanto um valor type1 (azul) é um grupo deles :

o ponto é que se você quiser indicar um valor de tipo2, o endereço é simples, mas se você quiser fazer a mesma coisa para o valor de tipo1, isso não é nada fácil! :

e em uma história mais complicada:

então aqui as referências podem nos resgatar:

enquanto a seta verde aqui é uma variável típica, a roxa é uma variável de objeto, então porque a seta verde (variável típica) tem apenas uma tarefa (e isso está indicando um valor típico), não precisamos separar seu valor de então movemos a seta verde com o valor de que onde quer que vá e em todas as atribuições, funções e assim por diante ...

mas não podemos fazer a mesma coisa com a seta roxa, podemos querer mover a célula 'john' aqui ou muitas outras coisas ..., então a seta roxa ficará em seu lugar e apenas as setas típicas que foram atribuídas a ela se moverão ...

uma situação muito confusa é onde você não consegue perceber como sua variável referenciada muda, vamos dar uma olhada em um exemplo muito bom:

let arr = [1, 2, 3, 4, 5]; //arr is an object now and a purple arrow is indicating it
let obj2 = arr; // now, obj2 is another purple arrow that is indicating the value of arr obj
let obj3 = ['a', 'b', 'c'];
obj2.push(6); // first pic below - making a new hand for the blue circle to point the 6
//obj2 = [1, 2, 3, 4, 5, 6]
//arr = [1, 2, 3, 4, 5, 6]
//we changed the blue circle object value (type1-value) and due to arr and obj2 are indicating that so both of them changed
obj2 = obj3; //next pic below - changing the direction of obj2 array from blue circle to orange circle so obj2 is no more [1,2,3,4,5,6] and it's no more about changing anything in it but we completely changed its direction and now obj2 is pointing to obj3
//obj2 = ['a', 'b', 'c'];
//obj3 = ['a', 'b', 'c'];

8 AshishSinghRawat Sep 26 2018 at 00:31

Isso é um pouco mais de explicação para passagem por valor e passagem por referência (JavaScript). Nesse conceito, eles estão falando sobre passar a variável por referência e passar a variável por referência.

Passagem 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 JavaScript (string, número, booleano, indefinido e nulo).
  • a é alocada a uma memória (digamos 0x001) eb cria uma cópia do valor na memória (digamos 0x002).
  • Portanto, alterar o valor de uma variável não afeta a outra, pois ambas residem em dois locais diferentes.

Passagem 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" }
  • O mecanismo JavaScript atribui o objeto à variável ce aponta para alguma memória, digamos (0x012).
  • Quando d = c, nesta etapa daponta para o mesmo local (0x012).
  • Alterar o valor de qualquer valor altera para ambas as variáveis.
  • Funções são objetos

Caso especial, passagem por referência (objetos)

c = {"name" : "jane"};
console.log(c); // { "name" : "jane" }
console.log(d); // { "name" : "doe" }
  • O operador igual (=) configura um novo espaço de memória ou endereço
6 ZameerAnsari Aug 10 2017 at 19:43

compartilhando o que eu sei sobre referências em JavaScript

Em JavaScript, ao atribuir um objeto a uma variável, o valor atribuído à variável é uma referência ao objeto:

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

4 CPerkins Dec 24 2016 at 01:43

Semântica!! Definir definições concretas necessariamente tornará algumas respostas e comentários incompatíveis, uma vez 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).

Em primeiro lugar, existem vários níveis de abstração que nem todos parecem compreender. Os programadores mais novos que aprenderam linguagens de 4ª ou 5ª geração podem ter dificuldade em compreender os conceitos familiares ao assembly ou aos programadores C que não são faseados por ponteiros para ponteiros para ponteiros. Passar 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. Esse termo geralmente é muito carregado para ser usado sozinho na discussão de detalhes.

Símbolo : string de texto usada para se referir à variável (ou seja, o 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 básico subjacente não é o "objeto" em si, mas seu valor é um ponteiro (valor do local da memória) para outro local na memória onde os dados reais do objeto estão armazenados. Na maioria das linguagens de geração superior, o aspecto de "ponteiro" é efetivamente oculto pela des-referência automática em vários contextos.

Variável primitiva : Variável cujo valor é o valor real. Até mesmo esse conceito pode ser complicado por contextos de caixa automática e semelhantes a objetos de várias linguagens, mas a ideia geral é que o valor da variável É o valor real representado pelo símbolo da variável em vez de um ponteiro para outro local da memória.

Os argumentos e parâmetros da 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á apontado por várias pessoas, mas aparentemente ignorado). Essas distinções são críticas para um entendimento adequado.

Passagem por valor ou Chamada por compartilhamento (para objetos) : O valor do argumento da função é COPIADO para outro local da memória que é referenciado pelo símbolo do parâmetro da função (independentemente de estar na pilha ou 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 NUNCA É ATUALIZADO / ALTERADO / ALTERADO pela função de chamada. Lembre-se de que o valor de uma variável de objeto NÃO é o próprio objeto, em vez disso, é 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 o mesmo objeto exato na memória. Os próprios dados do objeto podem ser alterados diretamente por meio do parâmetro da função, MAS o valor do argumento da função NUNCA É ATUALIZADO, então ele continuará a apontar para o mesmo objeto durante e mesmo após a chamada da função (mesmo se os dados do seu objeto foram alterados ou se o parâmetro de função é atribuído a um objeto completamente 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 ajudar, o parâmetro da função se torna um "alias" efetivo para o argumento - eles se referem efetivamente ao mesmo valor no mesmo local da memória. Se um argumento de função for 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 for definido para um objeto completamente diferente, então o argumento também apontará para o objeto diferente - isso não acontece no caso da passagem por valor.

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

Clone / cópia do objeto: 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 da passagem por valor. Algumas linguagens distinguem entre objeto de classe e estruturas (ou semelhantes) e podem ter comportamentos diferentes para passar variáveis ​​de tipos diferentes. Mas JavaScript não faz nada parecido com isso automaticamente ao passar variáveis ​​de objeto. Mas a ausência de clonagem automática de objetos não significa passagem por referência.

4 georgeawg Jul 25 2018 at 22:47

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

Agora, as pessoas gostam de discutir interminavelmente 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?


Atualizar

Aqui está uma refutação a isso:

Não há "passagem por referência" disponível em JavaScript.

3 dpp Sep 16 2014 at 16:19

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 próprias variáveis.

    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 inVar2recebem o conteúdo que está 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 }, pode-se alterar o valor da propriedade do objeto.

    function foo(inVar1, inVar2){
        inVar2.prop = 7; 
    }
    
3 JohnSonderson Nov 01 2014 at 19:43

Passar argumentos para uma função em JavaScript é análogo a passar parâmetros por valor de ponteiro em 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 DannyNiu Jul 28 2017 at 20:17

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

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

Construção de listas de argumentos

A Seção 11.2.4 "Listas de argumentos" diz o seguinte sobre a produção de uma lista de argumentos que consiste em apenas 1 argumento:

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

  1. Seja ref o resultado da avaliação de AssignmentExpression.
  2. Seja arg GetValue (ref).
  3. Retorne 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 às propriedades do objeto

Seção 11.2.1 "Acessores de propriedade"

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

  1. Deixe baseReference ser o resultado da avaliação de MemberExpression.
  2. Seja baseValue GetValue (baseReference).
  3. Deixe propertyNameReference ser o resultado da avaliação de Expression.
  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 de modo estrito, deixe estrito ser verdadeiro, caso contrário, seja estrito falso.
  8. Retorne 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 na linguagem - elas são usadas apenas para descrever o comportamento dos operadores de exclusão, typeof e atribuição.

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 a qual é o valor da coleção está mal definido na especificação, e requer um pouco de esforço para entender.

3 miguelr Apr 20 2019 at 13:06

Os documentos MDN explicam isso claramente, sem ser muito prolixo:

Os parâmetros de uma chamada de função são os argumentos da função . Os argumentos são passados ​​para funções por valor . Se a função alterar o valor de um argumento, essa alteração não será refletida globalmente ou na função de chamada. No entanto, as referências de objeto também são valores e são especiais: se a função altera as propriedades do objeto referido, essa alteração é visível fora da função, (...)

Fonte: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Description

2 JonasWilms Jul 26 2020 at 22:32

observação: se não houver uma maneira de um observador examinar a memória subjacente do motor, não há como determinar se um valor imutável foi copiado ou se uma referência foi passada.

JavaScript é mais ou menos agnóstico em relação ao modelo de memória subjacente. Não existe referência ². JavaScript tem valores . Duas variáveis ​​podem conter o mesmo valor (ou mais preciso: dois registros de ambiente podem vincular o mesmo valor). O único tipo de valor que pode ser alterado são os objetos por meio de suas operações abstratas [[Get]] e [[Set]]. Se você se esquecer dos computadores e da memória, isso é tudo de que você precisa para descrever o comportamento do JavaScripts e permite que você entenda a especificação.

 let a = { prop: 1 };
 let b = a; // a and b hold the same value
 a.prop = "test"; // the object gets mutated, can be observed through both a and b
 b = { prop: 2 }; // b holds now a different value
 

Agora você pode se perguntar como duas variáveis ​​podem manter o mesmo valor em um computador. Você pode então examinar o código-fonte de um mecanismo JavaScript e provavelmente encontrará algo que um programador da linguagem em que o mecanismo foi escrito chamaria de referência.

Então, na verdade, você pode dizer que JavaScript é "passagem por valor", enquanto o valor pode ser compartilhado, você pode dizer que JavaScript é "passagem por referência", o que pode ser uma abstração lógica útil para programadores de linguagens de baixo nível, ou você pode chamar o comportamento de "ligar compartilhando". Como não existe uma referência em JavaScript, todas essas opções não estão erradas nem objetivas. Portanto, não acho que a resposta seja particularmente útil para pesquisar.

² O termo Referência na especificação não é uma referência no sentido tradicional. É um contêiner para um objeto e o nome de uma propriedade, e é um valor intermediário (por exemplo, a.bavalia para Reference { value = a, name = "b" }). O termo referência às vezes também aparece na especificação em seções não relacionadas.

1 lid May 17 2014 at 08:01

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

    • fragmento
    • 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
    • variedade
    • função

Por exemplo:

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

bar[0] = 9;

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

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

1 steviejay Oct 29 2016 at 21:50

Eu li essas respostas várias vezes, mas não entendi REALMENTE até que aprendi sobre a definição técnica de "Ligar para compartilhar", como denominado por Barbara Liskov

A semântica da chamada por compartilhamento difere da chamada por referência em que as atribuições aos argumentos da função dentro da função não são visíveis para o chamador (ao contrário da semântica de referência) [carece de fontes], então, 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 nesses objetos, se os objetos forem mutáveis, dentro da função são visíveis para o chamador, o que pode parecer diferente da chamada por valor semântica. As 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 está acessível ao chamador da função.

1 Narayon Oct 19 2016 at 19:07

Em uma linguagem de baixo nível, se você deseja passar uma variável por referência, você deve 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, terá 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, a linguagem converte o parâmetro de referência em valor. Você não precisa usar &, na definição da função, para passá-la por referência, nem *, no corpo da função, para converter a referência em valor, o JavaScript faz isso por você.

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

Saber mais