【问题标题】:does javascript objects passed by reference or valuejavascript 对象是否通过引用或值传递
【发布时间】:2013-09-30 05:01:13
【问题描述】:

我尝试了以下代码,但它会提醒旧对象名称属性?我知道对象是通过引用传递的,但是它是通过引用传递的,那么在函数内部更改的对象也应该在函数外部更改,不是吗?

function setName(obj) {
 obj.name = "raziq";
 obj = new Object();
 obj.name = "abdul";
}
var person = new Object();
setName(person);
alert(person.name); //still yields raziq

如果对象是通过引用传递的,我有点困惑,那么应该提醒新名称为什么它仍然提醒 raziq 作为对象的名称?

【问题讨论】:

  • 为什么要在 setName 中创建一个新对象?
  • @ThomasWood 为了说明问题,我会冒险猜测
  • 看看它是否改变了函数外部的人对象,因为如果对象是通过引用传递的,那么函数内部的新对象应该反映在函数外部不是吗?
  • 请阅读post中的一些答案

标签: javascript object


【解决方案1】:

在您的代码中:

> function setName(obj) {

调用中第一个参数的值被赋值给局部变量obj。如果传递了一个对象,则 obj 的值是对该对象的引用。

>   obj.name = "raziq";

这会将值“raziq”分配给传递给obj的对象的name属性。如果 name 属性不存在,则会创建它。

>   obj = new Object(); 

这会分配一个新的对象引用作为 obj 的值,因此它不再引用传递给函数的对象。

>   obj.name = "abdul";

这会将值“abdul”分配给 obj 引用的对象(创建的新对象)的 name 属性(如果该属性不存在,则创建该属性)并在上面的行中分配)。

由于没有其他对该对象的引用,因此一旦函数结束,它就可用于垃圾回收。

> }
>
> var person = new Object();

创建一个新对象并将其分配给变量personperson 的值是对新对象的引用。

> setName(person);

调用 setName 并将上面一行创建的对象传递给它。该函数将 raziq 分配给对象的 name 属性(见上文)。

> alert(person.name); //still yields raziq

提醒上面创建并分配给person的对象的name属性值。由于 raziq 被指定为值,因此返回的就是这个值。

请注意,在函数中创建了一个新对象,并且在赋值语句中创建了一个 name 属性,但是该对象没有被分配到任何地方,也没有从函数中返回它,所以之后的所有内容:

  obj = new Object();

实际上什么都不做。

注意,更常见的写法:

  obj = {};

与上一行的结果完全相同,但输入更少,使用更广泛,因此可能(略微)更易于阅读和维护。

【讨论】:

    【解决方案2】:

    当您将 new Object() 分配给变量 obj 时,您实际上并没有交换原始对象。计算机为您刚刚实例化的对象在内存中创建一个新位置,并为 name 属性分配一个值“abdul”,但这不会更改先前的对象,因为它驻留在内存中的不同位置。新创建的对象永远不会离开函数。

    不要将obj 变量视为容纳对象的容器,而是将其视为具有对象位置的数字地址的占位符。当您将person 传递给函数时,您传递的是该地址,而不是对象本身。因此,在函数内部,当您创建新对象时,您将该新对象的地址存储在占位符obj 中。函数外的变量person 仍然包含原始对象的地址,而不是您在函数中创建的新对象。

    【讨论】:

    • 对象不是通过引用传递的吗?
    • @abdul:不。传递的 value 是对对象的引用,但不称为“按引用传递”。那仍然是“按值传递”。见en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference
    • 是的,但该函数使用 ADDRESS 的副本来引用对象。当您更改函数内部的变量时,您正在更改地址。
    • @abdul:它改变了对象的属性。为什么?因为obj 是对对象的引用,正如我们刚才提到的。如果 JS 是按引用传递的,person 将引用您使用 obj = new Object(); 创建的同一个对象,但事实并非如此。我真的建议阅读我链接的维基百科文章,它很好地描述了 IMO 的差异。
    • @abdulraziq 是的,除非您使用 var,否则您将创建一个新的全局变量。但是,有一个例外,如果您使用参数之一的名称,则您没有使用全局变量。示例function foo(a){a = 7} 只是回收了参数使用的变量a,并没有创建新的全局变量。
    【解决方案3】:

    JavaScript 中没有“通过引用传递”。您可以传递一个对象(也就是说,您可以通过值传递对对象的引用),然后让函数修改对象内容。

    Source for reference

    在 JavaScript 中,我们有函数,并且我们有传递给这些函数的参数。但是 JavaScript 如何处理你传入的内容并不总是很清楚。当您开始进行面向对象的开发时,您可能会发现自己对为什么有时可以访问值但有时不能访问感到困惑。

    当传入像字符串或数字这样的原始类型变量时,值是按值传入的。这意味着在函数中对该变量的任何更改都与函数外部发生的任何事情完全分开。我们来看下面的例子:

    function myfunction(x)
    {
          // x is equal to 4
          x = 5;
          // x is now equal to 5
    }
    
    var x = 4;
    alert(x); // x is equal to 4
    myfunction(x); 
    alert(x); // x is still equal to 4
    

    然而,传递一个对象是通过引用传递的。在这种情况下,该对象的任何属性都可以在函数内访问。我们再看一个例子:

    function myobject()
    {
        this.value = 5;
    }
    var o = new myobject();
    alert(o.value); // o.value = 5
    function objectchanger(fnc)
    {
        fnc.value = 6;
    }
    objectchanger(o);
    alert(o.value); // o.value is now equal to 6
    

    那么,当你传入一个对象的方法时会发生什么?大多数人会期望(或者至少我做到了)它将通过引用传递,从而允许该方法访问它所属的对象的其他部分。不幸的是,事实并非如此。看看这个例子:

    function myobject()
    {
        this.value = 5;
    }
    myobject.prototype.add = function()
    {
        this.value++;
    }
    var o = new myobject();
    alert(o.value); // o.value = 5
    o.add();
    alert(o.value); // o.value = 6
    function objectchanger(fnc)
    {
        fnc(); // runs the function being passed in
    }
    objectchanger(o.add);
    alert(o.value); // sorry, still just 6
    

    这里的问题是“this”关键字的使用。它是引用当前对象上下文的方便快捷方式。但是,当将函数作为参数传递时,上下文会丢失。更准确地说,this 现在指的是进行调用的对象的上下文,而不是我们刚刚传入的对象函数。对于独立函数,这将是窗口对象,对于从事件调用的函数,这将是事件对象。

    【讨论】:

    • “传递一个对象,但是,通过引用传递它。” 不! JavaScript 总是按值传递。碰巧在对象的情况下,传递了对该对象的引用。但是,这不是通过引用传递的。通过引用传递将是var foo = 42; (function(baz) { baz = baz / 2}(foo)); alert(foo); /* would alert 21 */,但这不是 JS 的工作方式。
    • @FelixKling:这也不完全是按值传递。真正的按值传递(如在 tcl 等语言中)会复制整个对象。我更喜欢将其称为“通过参考副本传递”,这就是您所说的。当您认为 javascript 始终传递引用的副本(或者,用您的术语,引用的值)时,它的行为始终相同 - 即使对于数字和字符串也是如此。
    猜你喜欢
    • 2014-02-08
    • 2011-09-27
    • 2012-07-16
    • 2020-04-10
    • 2012-10-31
    • 2016-09-27
    • 2018-04-03
    相关资源
    最近更新 更多