深浅拷贝与for...of/in

本文详细介绍了ES6中的for...of和for...in遍历方式,强调了它们在遍历Array、Map、Set等数据结构的区别,并指出Object无法直接使用for...of。同时,文章深入探讨了深拷贝和浅拷贝的概念,通过实例展示了如何在JavaScript中实现对象和数组的深浅拷贝,特别是对于包含复杂数据类型的情况。最后,提供了深拷贝的实现函数`deepClone`。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

📝 个人简介

⭐ 个人主页:我是段段🙋‍
🍊 博客领域:编程基础、前端💻
🍅 写作风格:干货!干货!都是干货!
🍑 精选专栏:数组
🛸 支持段段:点赞👍、收藏⭐、留言💬

深浅拷贝与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
}

深浅拷贝

数据类型分为 基本数据类型引用数据类型

  1. 基本数据类型
  • 主要包括:String、Number、Boolean、Null、Undefined、Symbol(ES 6)

  • 其特点为:直接存储在中的数据

  1. 引用数据类型
  • 主要包括: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方法同上

有问题欢迎评论指出,博主会及时改正的🙇‍

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是段段

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值