js数组引用

var a = [
  {
    name: 'is_empty',
    items: ['1', '2', '3', '4', '5']
  },
  {
    name: 'is_true',
    items: ['6', '7', '8', '9', '10']
  }
]
var b = []

for (var i = 0; i < a.length; i++) {
  b[i] = a[i]
}

// 注释掉a[0] = [], 此时B 为{[], ['1', '2', '3', '4', '5']}
// 未注释掉的情况下,B为{[1, 2, 3, 4, 5]}, {[6, 7, 8, 9, 10]}

// a[0] = []
// console.log(b)  // {['6', '7', '8', '9', '10']}, {['6', '7', '8', '9', '10']}

// a[0].items = []
// console.log(b) // {[], [6, 7, 8, 9, 10]}

重置a[0] = []的时候,数组的引用被切断了,但是如果只重置a[0].items = []时候,引用却并未被切断,这是为什么?

阅读 2.9k
2 个回答

假设这有个数组[{},{}](就是你上面a引用的那个,我简写吧)

a是它的指针,指向这个数组所在的地址

然后你创建了一个变量b,把那个数组里面的元素地址放到了b里面,因为那个数组里面的元素是对象 所以b[i] = a[i]的操作也只是a[i]把某个地址赋值给了b[i]。他们都是一个指针

下面进入分支:

a[0] = []的情况:a[0] 本来是一个指向[{},{}]其中一个元素的指针,后被替换成[]空数组的指针。然后给这个指针所指的对象(也就是空数组)添加了一个属性item,这个属性是一个空数组的指针。b还是指向[{},{}],没有任何影响。

a[0] = []被注释的情况:下一条语句 a[0].item = []。在这条语句执行前,a[0]还是和b[0]一样,是指向[{},{}]一个元素的指针。执行这条语句之后,也就是a[0]指向的这个对象的item属性被覆盖为一个空数组的指针。但是b[0]指向的内存地址还是没有变的,还是跟a[0]一样的。所以b[0].item也还是指向那一块内存,所以b[0].item = a[0].item = []。
(取属性的操作会对对象所在内存地址块执行操作,个人总结。。)

需要注意的地方就是 引用类型的赋值是把对象的地址传递给变量,让变量成为它的指针。所以a[0] = b[0] 都一样都指向[{},{}]的一个元素。或许你之前很有心的先var b = []开辟了一个内存。但是这个新的内存里面存放的东西,都是指向[{},{}]的指针。也就是通篇涉及到的有三个地址块。一个是存放a数组的地址,一个是存放b数组的地址,一个是[{},{}]的地址。

参考关键字:Call by sharing

附上例子希望能看懂:
图片描述

欢迎指正,一起进步。刚刚开始接触可能描述不规范。

两个都不是同一个东西,a[0]指的是第一个数组元素,a[0].items指的是第一个数组元素的对象属性items,所以你赋值的时候得到的结果肯定不一样了。

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