js 变量分为值类型和引用类型,数组属于引用类型。
值类型
var a=100;
var b=a;
a=200;
console.log(b);//100 ** 值类型的特点:它每个变量都能存储各自的值,不会相互影响 **
引用类型
var a={age:20};
var b=a;
b.age=21;
console.log(a.age);//21 ** 引用类型的特点:不同变量之间的值,会相互影响 **`
值类型和引用类型的特点
特点:从内存中来说,值类型是把每一个值都存到变量内存的位置,比如 a 存了 100,把 b 赋值给 a,b 的位置又存了 100 这个数字,a 的位置把 100 改成 200,b 的位置等于 100,还是 100,所以它不会相互影响。引用类型他不一样,引用类型是把 a 赋值成一个对象,这个对象存在另一个地方,a 内存的位置是通过一个指针指向这个对象的地方,把 b 赋值成 a 的时候,其实是定义了一个 b,b 的指针又指向了那个对象的位置,所以这个 age=20 这个对象只有一份,a 和 b 同时指向了这个对象而已,所以说当执行第三行 b.age=21 的时候,那个 age 的值已经改成了 21,所以 a 也是指向这个对象,所以说 a.age 也是 21。
引用类型为什么要这样做,而不是直接拷贝也存储一份?
引用类型可以无限制扩展属性,比如现在它有个 age 属性,我们也可以加 name 属性啊,grade 属性啊,等等等等很多属性,属性加多了之后,会出现内存占用比较多的问题。在值类型中 a =100,把 b 赋值成 a,相当于把 100 又重新拷贝了一份存下,没有关系,因为 100 不会占用很多内存。如果这个地方把 a 赋值成一个对象,但是它又特别大,b 再赋值成 a,b 也拷贝复制一份,他就会占很大的空间,这是不合理的,所以说为了让内存共用空间,才会出现引用类型这种方式。
深拷贝
let arr=[{
name:'111',
title:'111',
children:[{
name:'111-1',
title:'111-1'
},{
name:'111-2',
title:'111-2'
}]
}]
let newArr=arr.slice(0)
for(let i of newArr){var arr2 = i.children.filter((item2) => {return item2.name === '111-1'})
i.children=arr2
}
console.log('arr',arr)
console.log('newArr',newArr)
根据上面打印可以看到,深拷贝之后还是改变了 arr 的值,这个时候我们可以用 JSON.parse 和 JSON.stringify 来实现。
let arr=[{
name:'111',
title:'111',
children:[{
name:'111-1',
title:'111-1'
},{
name:'111-2',
title:'111-2'
}]
}]
let newArr=JSON.parse(JSON.stringify(arr))
for(let i of newArr){var arr2 = i.children.filter((item2) => {return item2.name === '111-1'})
i.children=arr2
}
console.log('arr',arr)
console.log('newArr',newArr)
这样 arr 就不会受影响了。