关于javascript的引用类型

本人新手想问一个小白问题,先上一段演示代码:

javascript    var obj1={color:"red"};
    var obj2=obj1;
    obj2.color="green";
    alert(obj2.color);           //green
    obj2=null;
    alert(obj2.color);            //报错,undefined
    alert(obj1.color);            //green

有一个地方实在不是很清楚,就是当obj2=null后,为什么obj1任然存在?
按理说js的说法引用类型存放的是数据的地址,当我对obj2进行操作的时候实际是对obj2存放的地址那里的数据进行操作,所以我把obj2的颜色改了,obj1的颜色也一起改了。

可是当我把obj2设置为null后,obj1任然在?难道说=null操作是直接把obj2存的地址给清空了,而其他操作则是“寻址操作”?

阅读 7.2k
7 个回答

这个绝对不是 小白的问题
这涉及到了 ECMAScript = 这个运算符的原理了;
大家都知道赋值有 按值传递、按引用传递这两种类型,其实ECMAScript中还有一种 叫 按共享传递
即:修改参数的属性将会影响到外部,而重新赋值将不会影响到外部对象。

ECMAScript代码:

var foo = {x: 10, y: 20};
var bar = foo;

alert(bar === foo); // true

bar.x = 100;
bar.y = 200;

alert([foo.x, foo.y]); // [100, 200]

即两个标识符(名称绑定)绑定到内存中的同一个对象, 共享这个对象:

foo value: addr(0xFF) => {x: 100, y: 200} (address 0xFF) <= bar value: addr(0xFF)

而重新赋值分配,绑定是新的对象标识符(新地址),而不影响已经先前绑定的对象 :

bar = {z: 1, q: 2};

alert([foo.x, foo.y]); // [100, 200] – 没改变
alert([bar.z, bar.q]); // [1, 2] – 但现在引用的是新对象

即现在foo和 bar,有不同的值和不同的地址:

foo value: addr(0xFF) => {x: 100, y: 200} (address 0xFF)
bar value: addr(0xFA) => {z: 1, q: 2} (address 0xFA)

再强调一下,这里所说对象的值是地址(address),而不是对象结构本身,将变量赋值给另外一个变量——是赋值值的引用。因此两个变量引用的是同一个内存地址。下一个赋值却是新地址,是解析与旧对象的地址绑定,然后绑定到新对象的地址上,这就是和按引用传递的最重要区别。

此外,如果只考虑ECMA-262标准所提供的抽象层次,我们在算法里看到的只有“值”这个概念,实现传递的“值”(可以是原始值,也可以是对象),但是按照我们上面的定义,也可以完全称之为“按值传递”,因为引用地址也是值。

然而,为了避免误解(为什么外部对象的属性可以在函数内部改变),这里依然需要考虑实现层面的细节——我们看到的按共享传递,或者换句话讲——按安全指针传递,而安全指针不可能去解除引用和改变对象的,但可以去修改该对象的属性值。

参考阅读: 深入理解JavaScript系列(19):求值策略(Evaluation strategy)

before
obj2 = null之后
after
其实质是改变引用的值,但是如果是用obj2.color = 'gray'之类的,.操作符是间接访问了处在堆内存的对象本身,所以会变,但操作引用本身就是这样了。

当你定义obj2 = obj1的时候,表示的是这两个变量同时指向 {color:"red"} 这个对象,所以你对对象进行操作的时候两个变量都会有反应。当你做obj2 = null的时候,表示的是将obj2指向null,这个时候obj1还是指向老地方的,所以是存在的。

题主可以试试delete obj2.color,应该会更明白一点:

clipboard.png

用堆栈回答一下吧,生成的实例如obj1obj2是放在栈空间里,对象是放在堆空间里。
var obj2=obj1;说明obj2实例也指向了obj1在堆空间里的那个对象。
obj2=null;这段代码是转折点,把null赋值给obj2,此时obj2不再指向堆空间中的任何对象,而是一个空的引用。

我说的有点乱,不知道能理解吗?

可以这么理解, obj2 = null,只是销毁这个引用

Js高级程序设计第四章最开始就讲了
复制基本类型的时候会再变量对象上创建一个新值,然后复制到新的位置上,两个变量就不会互相影响。

复制引用类型的时候,复制的是一个指针,指向存储在堆中得对象,所以将会引用同一个对象。这时候设置null,相当于切断了联系

javascript共享传值.
obj2 = obj1的效果,如果换成指针写法相当于 obj2 = *obj1。
而obj2 = null,也只是
obj2 = null。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题