本人新手想问一个小白问题,先上一段演示代码:
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存的地址给清空了,而其他操作则是“寻址操作”?
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
这个绝对不是 小白的问题
这涉及到了 ECMAScript = 这个运算符的原理了;
大家都知道赋值有 按值传递、按引用传递这两种类型,其实ECMAScript中还有一种 叫 按共享传递;
即:修改参数的属性将会影响到外部,而重新赋值将不会影响到外部对象。
ECMAScript代码:
即两个标识符(名称绑定)绑定到内存中的同一个对象, 共享这个对象:
而重新赋值分配,绑定是新的对象标识符(新地址),而不影响已经先前绑定的对象 :
即现在foo和 bar,有不同的值和不同的地址:
再强调一下,这里所说对象的值是地址(address),而不是对象结构本身,将变量赋值给另外一个变量——是赋值值的引用。因此两个变量引用的是同一个内存地址。下一个赋值却是新地址,是解析与旧对象的地址绑定,然后绑定到新对象的地址上,这就是和按引用传递的最重要区别。
此外,如果只考虑ECMA-262标准所提供的抽象层次,我们在算法里看到的只有“值”这个概念,实现传递的“值”(可以是原始值,也可以是对象),但是按照我们上面的定义,也可以完全称之为“按值传递”,因为引用地址也是值。
然而,为了避免误解(为什么外部对象的属性可以在函数内部改变),这里依然需要考虑实现层面的细节——我们看到的按共享传递,或者换句话讲——按安全指针传递,而安全指针不可能去解除引用和改变对象的,但可以去修改该对象的属性值。
参考阅读: 深入理解JavaScript系列(19):求值策略(Evaluation strategy)
obj2 = null
之后其实质是改变引用的值,但是如果是用
obj2.color = 'gray'
之类的,.操作符
是间接访问了处在堆内存的对象本身,所以会变,但操作引用本身就是这样了。当你定义
obj2 = obj1
的时候,表示的是这两个变量同时指向{color:"red"}
这个对象,所以你对对象进行操作的时候两个变量都会有反应。当你做obj2 = null
的时候,表示的是将obj2
指向null
,这个时候obj1
还是指向老地方的,所以是存在的。题主可以试试
delete obj2.color
,应该会更明白一点:用堆栈回答一下吧,生成的实例如
obj1
,obj2
是放在栈空间里,对象是放在堆空间里。var obj2=obj1;
说明obj2
实例也指向了obj1
在堆空间里的那个对象。obj2=null;
这段代码是转折点,把null
赋值给obj2
,此时obj2
不再指向堆空间中的任何对象,而是一个空的引用。我说的有点乱,不知道能理解吗?
可以这么理解,
obj2 = null
,只是销毁这个引用Js高级程序设计第四章最开始就讲了
复制基本类型的时候会再变量对象上创建一个新值,然后复制到新的位置上,两个变量就不会互相影响。
复制引用类型的时候,复制的是一个指针,指向存储在堆中得对象,所以将会引用同一个对象。这时候设置null,相当于切断了联系
javascript共享传值.
obj2 = obj1的效果,如果换成指针写法相当于 obj2 = *obj1。
而obj2 = null,也只是obj2 = null。