为什么在重新分配时此对象是否复制为空?

时间:2017-03-25 23:38:47

标签: javascript javascript-objects

假设我创建了一个对象,复制它(通过引用)然后使其无效:



let obj = {
  prop: 'one'
}

let otherObj = obj

console.log(otherObj === obj); //true

console.log(obj.prop); //one

obj = null;

console.log(otherObj.prop); //shouldn't this be Uncaught TypeError: Cannot read property 'prop' of null"?




是不是otherObj也是空的,因为它们是同一个对象?

5 个答案:

答案 0 :(得分:1)

您必须区分对象和引用到该对象。变量objotherObj只保存对象的引用,该对象是指向内存的指针。 它们不是对象的副本,并且它们不是同一个对象。他们指向到同一个对象。

为了更清楚地说明这一点,我将逐行解释。当你这样做时:

let obj = {
    prop: 'one'
}

您正在创建一个新的引用,如下所示:

enter image description here

obj只指向对象所在的内存中的一个点,称为引用。接下来,你做:

let otherObj = obj

这相当于:

enter image description here

在此,您将 obj 的引用分配给otherObj。它们现在都指向内存中的相同对象,尽管它们完全相互独立。 otherObjobj obj = null 的引用,因此它们都引用相同的对象但是是分开的。根据链接:

  

在这种情况下,会创建一个新对象B,并将A的字段值复制到B。

     

[...]

     

如果字段值是对象的引用(例如,内存地址),则复制引用,因此引用与A相同的对象

最后你这样做:

obj

这是这样的:

shallow copy

obj到内存中对象的引用基本上已被切断,null现在指向obj,或者什么都没有。由于otherObjotherObj彼此独立,因此obj没有任何反应,它仍然指向内存中的对象。 otherObjrefreshStuff()本身是单独的引用,但引用相同的对象。当您修改内存中的对象时,它会反映在两个引用上,但是当您通过断开对内存位置的引用来修改引用时,另一个没有任何反应。

答案 1 :(得分:0)

不,因为在您进行新作业obj = null的确切时刻,参考文献会丢失,所以otherObj仍会包含旧参考文献。

换句话说,既然您修改了对象(例如,更改了某些字段),otherObjobj都会看到更新,但是当您重新分配其中一个时,就会中断债券和每一个都将指向记忆中的不同位置。

答案 2 :(得分:0)

不,要理解为什么你需要理解“参考”的概念。

在您的示例中,这段代码“创建”了您的对象:

let obj = {
    prop: 'one'
}

在这种情况下,“obj”不是对象本身(如内存位置),而是对象“引用” - 基本上它是指向指针的指针。

在将“obj”设置为null之前,还将“otherObj”指定为对SAME对象的引用。此时你有2个引用。

当您将“obj”设置为null时,该对象仍然存在并仍然被“otherObj”引用。它将被保存在内存中,至少在它不再被“otherObj”引用之前。如果将两个引用都设置为null,那么您将无法再访问该对象本身,并且可能会使其可供Javscript引擎释放。

这是一个非常重要的概念 - 如果将变量传递给函数,该参数是对象的“引用”(除了字符串和数字之类的东西,它们本质上是不可变的)。您可以在函数外部重新分配变量,参数将保持不变。

另外,在另一方面 - 虽然两个引用指向同一个对象,但成员的更改都会被两个引用反映出来。如果你想要两个不同的副本,你必须做一些事情,比如“克隆”一个对象 - 而不仅仅是引用它。

了解引用对于管理Javascript中的闭包至关重要。

答案 3 :(得分:0)

您应该区分深拷贝和浅拷贝。你正在做的事情被称为浅拷贝。这是可视化:

浅拷贝

enter image description here enter image description here enter image description here

深层复制

enter image description here enter image description here enter image description here

对于浅层副本,您的两个对象(objotherObj)都指向相同的内存位置。这就是为什么当你改变一个对象的值时,另一个对象也会被更新。

同时,使用深层副本,每个对象都有自己的内存位置。当您更改一个对象的值时,它不会影响另一个。

您可以从此post了解更多信息。

答案 4 :(得分:-1)

不,因为变量在JavaScript中是无类型的。这意味着JavaScript引擎可以根据其包含的信息确定变量的类型。在Visual Basic中,一种非常相似的变量称为"variant"

所以,如果你说

let otherObj = obj;

其中obj是一个对象值,你现在有两个变量,它们知道它们是对象并且具有相同的对象值(不考虑如何将对象实现为引用)。

所以如果你现在执行

obj = null;

obj的值覆盖了值null(顺便提一下,数据类型为“null”,只支持一个值: null )。

显然,为一个变量赋值是不应该改变另一个变量中保存的值。编程语言取决于此。

因此,在更新obj的值之后,otherObj包含与之前相同的对象值:具有值“prop”的属性为“prop”的对象。