Почему этот объект не передается по ссылке, когда ему присваивается что-то еще? - PullRequest
52 голосов
/ 25 февраля 2012

Я знаю, что в JS объекты передаются по ссылке, например:

function test(obj) {
    obj.name = 'new name';
}

var my_obj = { name: 'foo' };
test(my_obj);
alert(my_obj.name); // new name

Но почему не работает следующее:

function test(obj) {
    obj = {};
}

var my_obj = { name: 'foo' };
test(my_obj);
alert(my_obj.name); // foo

Я установил объектна {} (пусто), но все равно говорится foo.

Может ли кто-нибудь объяснить логику, стоящую за этим?

Ответы [ 4 ]

66 голосов
/ 25 февраля 2012

Если вы знакомы с указателями, вы можете воспользоваться этой аналогией.Вы фактически передаете указатель, поэтому obj.someProperty разыменовывает это свойство и фактически переопределяет его, тогда как простое переопределение obj приведет к уничтожению указателя и не перезапишет объект.

30 голосов
/ 25 февраля 2012

Поскольку JavaScript фактически передает объекты путем передачи по копии ссылки.

Когда вы передаете my_obj в функцию test, копия ссылка на этот объект передается. В результате, когда вы переопределяете объект в test, вы на самом деле только переопределяете копию ссылки на исходный объект;Ваш оригинал my_obj остается неизменным.

27 голосов
/ 25 февраля 2012

Поскольку вы перезаписываете ссылку, а не объект.

// Create a new object and assign a reference to it
// to the variable my_obj
var my_obj = { name: 'foo' };

// Pass the reference to the test function
test(my_obj);

// Assign the reference to a variable called obj
// (since that is the first argument)
function test(obj) {
// Create a new (empty) object and assign a reference to it to obj
// This replaces the existing REFERENCE
    obj = {};
}
// my_obj still has a reference to the original object, 
// because my_obj wasn't overwritten
alert(my_obj.name); // foo
5 голосов
/ 19 ноября 2012

В Javascript отсутствует поддержка для передачи по ссылке (хотя объекты передаются по ссылке и ссылка сохраняется до тех пор, пока она не переписана с помощью присваивания, например, с использованием =), но вы можете имитировать ключевое слово ref в C #, используяследующая техника:

function test(obj) {
  obj.Value = {};
  //obj.Value = {name:"changed"};
}

var my_obj = { name: 'foo' };

(function ()
{
  my_obj = {Value: my_obj};
  var $return = test(my_obj);
  my_obj = my_obj.Value;
  return $return;
}).call(this);

alert(my_obj.name); // undefined, as expected
                    // In the question this returns "foo" because
                    // assignment causes dereference

Конечно, вы можете использовать глобальные переменные и вызывать функцию без аргументов, и в этом случае ссылки не будут пропущены следующим образом:

var obj = { name: 'foo' };
function test() {
    obj = {};
}
test();
alert(obj.name); // undefined

Если у вас есть все вашикод в замыкании, тогда все проще и выше, как глобальные переменные не загрязняют глобальное пространство имен:

(function(){
    var obj = { name: 'foo' };
    function test() {
        obj = {};
    }
    test();
    alert(obj.name); // undefined
}).call(this);

Приведенная выше методика «глобальные внутри замыкания» хороша, если вам нужно портировать на Javascript некоторый код C #имеет ref аргументов.Например.Следующий код C #:

void MainLoop()
{
   // ...
   MyStruct pt1 = CreateMyStruct(1);
   MyStruct pt2 = CreateMyStruct(2);
   SwapPoints(ref pt1, ref pt2);
   // ...
}
void SwapPoints(ref MyStruct pt1, ref MyStruct pt2)
{
    MyStruct tmp = pt1;
    pt1 = pt2;
    pt2 = tmp;
}

может быть перенесен в Javascript, используя что-то вроде:

(function(){
    var pt1, pt2;
    function CreateMyStruct(myvar)
    {
      return {"myvar":myvar}  
    }
    function MainLoop()
    {
       // ...
       pt1 = CreateMyStruct(1);
       pt2 = CreateMyStruct(2);
       console.log("ORIG:",pt1,pt2); 
       SwapPoints(); 
       console.log("SWAPPED:",pt1,pt2);
       // ...
    }
    function SwapPoints()
    {
        var tmp = pt1;
        pt1 = pt2;
        pt2 = tmp;
    }
    MainLoop();

}).call(this);

или, если важно использовать локальные переменные и аргументы функции, тогда решение может быть основано напервый пример моего ответа, подобного этому:

(function(){
    function CreateMyStruct(myvar)
    {
      return {"myvar":myvar}  
    }
    function MainLoop()
    {
      // ...
      var pt1 = CreateMyStruct(1);
      var pt2 = CreateMyStruct(2);
      console.log("ORIG:",pt1,pt2); 

      (function ()
      {
        pt1 = {Value: pt1};
        pt2 = {Value: pt2};
        var $return = SwapPoints(pt1, pt2);
        pt1 = pt1.Value;
        pt2 = pt2.Value;
        return $return;
      }).call(this);

      console.log("SWAPPED:",pt1,pt2);
      // ...
    }
    function SwapPoints(pt1, pt2)
    {
      var tmp = pt1.Value;
      pt1.Value = pt2.Value;
      pt2.Value = tmp;
    }
    MainLoop();
}).call(this);

Действительно нужно сказать, что Javascript очень не хватает, когда у него нет нативного ref!Код был бы намного проще.

...