📝 个人简介
⭐ 个人主页:我是段段🙋
🍊 博客领域:编程基础、前端💻
🍅 写作风格:干货!干货!都是干货!
🍑 精选专栏:数组
🛸 支持段段:点赞👍、收藏⭐、留言💬
深浅拷贝与for…of/in
for…of与for…in
for…of是ES6新增的遍历方式,允许遍历一个含有Iterator接口的数据结构并且返回各项的值
具有原生Iterator接口的数据结构
Array
Map
Set
TypeArray
类数组对象(函数的arguments对象、NodeList对象)...
可见Object没有部署原生的Iterator接口,所以不能使用for…of进行循环
遍历Object
let obj = {
a: 1,
b: 2,
c: 3
}
// for...in
for(let key in obj){
console.log(key) // a b c
}
// for...of
for(let key of obj){
console.log(key) // obj is not iterable
}
遍历Array
let arr = [4, 5, 6]
// for...in
for(let prop in arr){
console.log(prop) // 0 1 2
}
// for...of
for(let prop of arr){
console.log(prop) // 4 5 6
}
深浅拷贝
数据类型分为 基本数据类型 和 引用数据类型
- 基本数据类型
-
主要包括:String、Number、Boolean、Null、Undefined、Symbol(ES 6)
-
其特点为:直接存储在栈中的数据
- 引用数据类型
-
主要包括:Object 、Array 、Date 、Function,统称为Object类型
-
其特点为:存储的是该对象在栈中引用,真实的数据存放在堆内存中
拷贝分为浅拷贝和深拷贝,其二者都是针对Object和Array类型的
浅拷贝只复制指向某个对象的指针而不复制对象本身,新旧对象还是共享同一块内存,修改新对象也会修改到原对象
而深拷贝则会另外创建一个新的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象
对象深/浅拷贝
当对象中包含复杂数据类型时
// 对象中包含复杂数据类型
let obj = {
username: '猪八戒',
sex: '雄性',
age: 800,
hobby: ['翠兰', '高老庄']
}
// 浅拷贝
let newObj = {}
for(let prop in obj){
newObj[prop] = obj[prop]
}
newObj.hobby.push('吃')
console.log(newObj, 'newObj')
console.log(obj, 'obj')
// { username: '猪八戒', sex: '雄性', age: 800, hobby: [ '翠兰', '高老庄', '吃' ] } newObj
// { username: '猪八戒', sex: '雄性', age: 800, hobby: [ '翠兰', '高老庄', '吃' ] } obj
let newObj = {}
newObj = { ...obj }
newObj.hobby.push('吃')
console.log(newObj, 'newObj')
console.log(obj, 'obj')
// { username: '猪八戒', sex: '雄性', age: 800, hobby: [ '翠兰', '高老庄', '吃' ] } newObj
// { username: '猪八戒', sex: '雄性', age: 800, hobby: [ '翠兰', '高老庄', '吃' ] } obj
// 可以看出浅拷贝时,新对象和原对象中的数据都发生了变化
当对象中不包含复杂数据类型时
// 深拷贝(单层)
// 不包含复杂数据类型
let obj1 = {
name: '张三',
age: 24
}
// 使用Object.assign()方法
let obj2 = Object.assign({}, obj1)
obj2.age = 22
console.log(obj1)
console.log(obj2)
// { name: '张三', age: 24 }
// { name: '张三', age: 22 }
// ..扩展运算符
let obj2 = { ...obj1 }
obj2.age = 22
console.log(obj1)
console.log(obj2)
// { name: '张三', age: 24 }
// { name: '张三', age: 22 }
// 循环遍历对象
let obj2 = {}
for(let key in obj1){
obj2[key] = obj1[key]
}
obj2.age = 22
console.log(obj1)
console.log(obj2)
// { name: '张三', age: 24 }
// { name: '张三', age: 22 }
当对象中包含复杂数据类型的多层深拷贝
let obj = {
username: '猪八戒',
sex: '雄性',
age: 800,
hobby: ['翠兰', '高老庄'],
monster: {
name: ['白骨精', '豹子精']
}
}
let newObj = {}
for(let prop in obj){
newObj[prop] = obj[prop]
}
newObj.monster.name.push('蛇精')
console.log(newObj, 'newObj')
console.log(obj, 'obj')
// {
// username: '猪八戒',
// sex: '雄性',
// age: 800,
// hobby: [ '翠兰', '高老庄' ],
// monster: { name: [ '白骨精', '豹子精', '蛇精' ] }
// } newObj
// {
// username: '猪八戒',
// sex: '雄性',
// age: 800,
// hobby: [ '翠兰', '高老庄' ],
// monster: { name: [ '白骨精', '豹子精', '蛇精' ] }
// } obj
// 深拷贝(多层)
let newObj = deepClone(obj)
newObj.hobby.push('吃')
console.log(newObj, 'newObj')
console.log(obj, 'obj')
// { username: '猪八戒', sex: '雄性', age: 800, hobby: [ '翠兰', '高老庄', '吃' ] } newObj
// { username: '猪八戒', sex: '雄性', age: 800, hobby: [ '翠兰', '高老庄' ] } obj
// 深拷贝时,只有新的对象中添加了数据,没有改变原始对象中的数据
// 封装一个函数,用来实现Object类型的深拷贝
function deepClone(o){
if(o instanceof Array){
let _arr = []
for (var i = 0, len = o.length; i < len; i++) {
_arr[i] = typeof o[i] === 'object' ? deepClone(o[i]) : o[i]
}
return _arr
} else if(o instanceof Object){
let _o = {}
for(let key in o){
_o[key] = typeof o[key] === 'object' ? deepClone(o[key]) : o[key]
}
return _o
}
return o
}
数组深/浅拷贝
let arr = [1, 2, 3]
// 浅拷贝
let newArr = arr
newArr.push(4)
console.log(arr)
console.log(newArr)
// [ 1, 2, 3, 4 ] arr
// [ 1, 2, 3, 4 ] newArr
// 和浅拷贝对象时一样,新数组和原数组都发生了变化
// 深拷贝(单层)
// 循环遍历的方法
let newArr = []
arr.forEach( item => {
newArr.push(item)
})
newArr.push(4)
console.log(arr, 'arr')
console.log(newArr, 'newArr')
// [ 1, 2, 3 ] arr
// [ 1, 2, 3, 4 ] newArr
// 扩展运算符(...)
let newArr = [...arr]
newArr.push(4)
console.log(arr, 'arr')
console.log(newArr, 'newArr')
// [ 1, 2, 3 ] arr
// [ 1, 2, 3, 4 ] newArr
// concat()方法
let newArr = [].concat(arr)
newArr.push(4)
console.log(arr, 'arr')
console.log(newArr, 'newArr')
// [ 1, 2, 3 ] arr
// [ 1, 2, 3, 4 ] newArr
// slice()方法
let arr1 = [1, 2, 3]
let arr2 = arr1.concat()
arr2.push(4)
console.log( arr1, 'arr1' )
console.log( arr2, 'arr2' )
// [ 1, 2, 3 ] arr1
// [ 1, 2, 3, 4 ] arr2
// Array.from()方法
let arr1 = [1, 2, 3]
let arr2 = Array.from(arr1)
arr2.push(4)
console.log( arr1, 'arr1' )
console.log( arr2, 'arr2' )
// [ 1, 2, 3 ] arr1
// [ 1, 2, 3, 4 ] arr2
当数组变成多层时,以上的方法就不再适用了
let arr = [1, 2, 3, [4, 5]]
let newArr = []
arr.forEach( item => {
newArr.push(item)
})
newArr[3].push(6)
console.log(arr, 'arr')
console.log(newArr, 'newArr')
// [ 1, 2, 3, [ 4, 5, 6 ] ] arr
// [ 1, 2, 3, [ 4, 5, 6 ] ] newArr
// 发现结果中,不管原数据和新数据都push进去了新数据
所以还是使用封装的deepClone方法,判断每一项的具体类型,进而实现数据的拷贝
// 深拷贝(多层)
let newArr = deepClone(arr)
newArr.push(4)
console.log(arr, 'arr')
console.log(newArr, 'newArr')
// [ 1, 2, 3 ] arr
// [ 1, 2, 3, 4 ] newArr
// deepClone方法同上
有问题欢迎评论指出,博主会及时改正的🙇