Javascript 为什么不是';当为该对象分配其他对象时,是否通过引用传递该对象?

Javascript 为什么不是';当为该对象分配其他对象时,是否通过引用传递该对象?,javascript,pass-by-reference,Javascript,Pass By Reference,我知道在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); al

我知道在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


有人能解释这背后的逻辑吗?

因为JavaScript实际上通过pass-by-copy-reference传递对象


当您将
my_obj
传递到
test
函数中时,将传递该对象引用的副本。因此,当您在
测试中重新分配对象时,实际上只是将引用的副本重新分配给原始对象;您原来的
my_obj
保持不变

如果你熟悉指针,你可以用这个比喻。实际上,您正在传递一个指针,因此
obj.someProperty
将取消对该属性的引用并实际重写该属性,而仅仅重写
obj
将杀死指针而不重写对象。

因为您正在重写引用,而不是对象

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

Javascript缺乏对按引用传递的支持(尽管对象是按引用传递的,并且只要引用没有被赋值覆盖(例如使用
=
)就可以维护引用),但您可以使用以下技术模仿C的
ref
关键字:

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
当然,您可以使用globals并调用不带参数的函数,在这种情况下,引用不会像这样丢失:

var obj = { name: 'foo' };
function test() {
    obj = {};
}
test();
alert(obj.name); // undefined
(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);
如果您的所有代码都在闭包中,那么事情就会更简单,更重要的是,globals不会污染全局命名空间:

(function(){
    var obj = { name: 'foo' };
    function test() {
        obj = {};
    }
    test();
    alert(obj.name); // undefined
}).call(this);
如果您必须将一些具有
ref
参数的C#代码移植到Javascript,那么上述“globalsinsideclosure”技术是很好的。例如,以下C#代码:

可以使用以下内容将其移植到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);
或者,如果必须使用局部变量和函数参数,那么解决方案可以基于我答案的第一个示例,如下所示:

var obj = { name: 'foo' };
function test() {
    obj = {};
}
test();
alert(obj.name); // undefined
(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
时,它缺少很多东西!代码会简单得多。

如果它是复制的,那么它为什么在我发布的第一个示例中工作?在我的第一个例子中,它也应该保持不被触碰?@Dev555-它是对对象引用的一个副本-为了更清楚,我对它进行了编辑。在第一种情况下,obj是指向真实对象的引用的副本。添加属性可以正常工作。如果我亲自去的话,我可以画一些带箭头的盒子的图片,我想这会很有帮助:)那么如何初始化对象呢?最初我有这个
instance.initGrid($(instance.maintentitycontainer),instance.maintentitylist);instance.initGrid($(instance.DependentEntityContainer),instance.DependentEntityList),我必须将其转换为以下内容:
instance.maintentitylist=instance.initGrid($(instance.maintentitycontainer));instance.DependentEntityList=instance.initGrid($(instance.DependentEntityContainer))我仍然想知道如何从以前的初始化中“释放内存”。我是否只需要在某个地方设置instance.DependentityList=null?我在里面有“=new…”。这是因为对象不是通过引用传递的;)@德尔南,但是有。查看
currentObject
如何更改
$scope.countries
->@Imray,这不是通过引用传递的,下面的多个答案解释了这一点。奇怪的javascript。我喜欢它,同时又讨厌它……+1-做得很好,比我的答案更清楚(假设OP知道指针)@AdamRackis我+1想要你的答案,因为它使用了JS术语,让我想起了类比;)感谢这一条澄清了它:)为什么我在上周搜索时没有找到这个答案!?这最终也回答了我的问题,非常感谢!在这一点上最好记住的是,当一个人用一些参数(比如这里的obj)声明一个函数时,obj是一种新事物。这就像说:
var obj;//该函数中未定义的
。因此,如果我们在做一些赋值,我们实际上是在改变函数内部的局部变量,我们正在破坏“引用”(指针)。您正在覆盖引用的副本,而不是引用。如果你想覆盖引用本身,一切都会好起来。那么如果你想覆盖
my_obj
,你会如何覆盖呢?@CodyBugstein将它包装在另一个对象中。关于这个问题的另一个答案表明了这一点,以及其他一些可能的方法。或者,如果您不喜欢这些方法中的任何一种,我认为答案基本上是:您不能覆盖
my_obj