请教关于对象是引用类型的一点小疑惑

var aa = {a: 1};
var bb = aa;
bb = {};
console.log(aa); // {a: 1}
var aa = {a: 1};
var bb = aa;
bb.a = 2;
console.log(aa); // {a: 2}


有些不解, 为什么第一段代码的aa不是{}, 遇见{}就会重新在堆中建立一个新内容吗?


顺便问下利用这种特性, 有哪些衍生的奇淫巧技?



高级编程3中4.1.3中关于函数参数传递的部分解释的好像有误啊, 如果按照大家给出的答案, 不知道是不是翻译错了, 书里用参数是值传递来解释上面的问题(其实书里关于这里的描述有一段本身就有语病, 不知道是不是翻译错了?)

阅读 2.2k
3 个回答

{}相当于一个新的对象,而bb = {}相当于修改了 bb 的指向地址。

所以现在b和a不指向同一堆内存了,bb 只是一个指向另一个对象的指针。

aa是不变的。

第二个中,bb.a修改了内存的内容,此时 bb 和 aa 还是指向同一内存的,所以修改bb.a后 aa.a 也会修改。

顺便问下利用这种特性, 有哪些奇淫巧技?

这个方面应用还是挺多的,不好的地方也挺多。

  1. 比如使用原型构造对象(并非纯粹的原型构造),其中属性定义在对象上,而方法定义在对象的原型上。
    每次实例化的对象,他们的方法不会发生拷贝(属性会进行拷贝),省很多内存。但是随之而来的也会存在问题,比如一个对象修改了原型的内容,则其他的所有对象都会随之一起修改。

  2. 比如 vue2.0中,子组件不允许修改父组件的值,但是传递引用过去之后,通过修改对象的属性,就可以实现修改父组件的值。(对象的引用是不会变的,就想上面,aa没变化,但是aa.a变化了)

这样的应用还很多。

关于 《高级教程》中

这本书有些地方翻译的不是很好,有些生硬。当时我看这本书的时候这部分也比较疑惑。

其让人费解的部分其实就是他对下面的解释

    var person = new Object(); 
    person.name = "postbird";
    function changeName(obj){
        obj.name="new "+obj.name;
        obj = new Object();
        obj.name = "obj Name";
    }
    console.log(person.name) // postbird
    changeName(person)
    console.log(person.name); // new postbird

我个人的理解是,函数参数是对象(表面上看是一个对象)的时候,比如obj,obj 他的确是和person指向同一个堆内存,因此第一个修改是一样的。

而实际上person是一个指针,而obj也是一个指针类型(我不确定在javascript中描述指针是否正确),如果你接触c比较多的话就能够明白。

person和obj也可以理解为特殊的变量,因此他们也有值。本身指针也可以重新赋值。因此,当上面的函数中obj被重新赋值之后,指向的内容就不同了。这就充分说明,obj实际上就是一个指针变量,传递过来的是指针变量的值(这个值的概念我也不确定这样描述是否有问题).

很简单,b先指向a,然后指向一个空对象
-->是其引用指向
b-->a
b-->{}
第二段代码的指向没有变化,修改其引用上的某个key值时,可以找到其引用对象并修改。

补充
函数的传递是另外一回事情了吧。。
实参传递给形参之间并不是引用,而是传值,形参即使是引用类型也是函数作用域下的独立变量了。

第一段代码变量bb和aa不是指向同一块内存,而第二段代码指向同一块内存。

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