variavel - valores por referencia javascript




O JavaScript é uma linguagem de passagem por referência ou de passagem por valor? (20)

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?


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


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. Variável de tipo primitivo como string, number sempre passam como passar por valor.
  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 objeto ou matriz com novo objeto ou matriz, ele será passado por valor.

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

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

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

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

    aqui você está alterando um valor de propriedade do objeto antigo. Você não está atribuindo um novo objeto 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

É 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 ).


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.


Considere o seguinte:

  1. Variáveis ​​são ponteiros para valores na memória.
  2. A reatribuição de uma variável meramente aponta esse ponteiro para um novo valor.
  3. A reatribuição de uma variável nunca afetará outras variáveis ​​que apontavam para o mesmo objeto

Então, esqueça "passar por referência / valor" não fique preso em "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 dessa 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 em que um único termo não descreve adequadamente o comportamento real e as informações complementares devem ser fornecidas
  2. Esses conceitos não foram originalmente definidos com a intenção de descrever o javascript em particular e, portanto, não me sinto obrigado a usá-los quando eles apenas 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 são, mas os primitivos são simplesmente o fim da cadeia de ponteiros.
  • Como último exemplo, considere por que uma tentativa comum de limpar uma matriz não funciona como 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

Javascript é sempre passagem por valor , tudo é do tipo valor. Objetos são valores, funções-membro de objetos são valores em si (lembre-se que funções são objetos de primeira classe em Javascript). Além disso, em relação ao conceito de que tudo no Javascript é um objeto , isso 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 de base, mas isso é apenas por conveniência, isso não significa que eles são objetos em si. Tente o seguinte para referência

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

Nos dois alertas, você encontrará o valor a ser indefinido.


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'

Pense nisso assim: é sempre passar 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}

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

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.


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.


Passar argumentos para uma função em JavaScript é análogo à passagem de parâmetros pelo valor do 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;
}

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

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

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

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

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

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

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.


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.


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".





pass-by-value