资讯专栏INFORMATION COLUMN

Js之浅拷贝深拷贝与对象数组的遍历

liangzai_cool / 1119人阅读

摘要:判断是深拷贝对象还是数组如果要拷贝的对象的属性依然是个复合类型,递归运用递归,当要拷贝的对象或者数组的属性依然是个对象或者数组时,递归调用。遍历对象聊完了深拷贝和浅拷贝,接下来说一下遍历。

在js这门语言中,数据存放在堆中,而数据的引用的存放在栈中。

浅拷贝

我们说的浅拷贝,指的是,引用地址的拷贝,栈中两块不同的引用地址都指向了堆中同样一块区域。所以,我们通过一个地址修改了堆中的数据,另外一个引用的地址同样会改变。

浅拷贝的常见写法有直接复制赋值,使用Object.assign()也是浅拷贝。

let obj = {
    "a":1,
    "b":2,
    "c":{
        "c1":3,
        "c2":4
    }
}
obj.b = 22

let newObj = obj
let newObj2 = Object.assign({},obj)

console.log(newObj)    // newObj.b为22
console.log(newObj2)   // newObj.b也为22
深拷贝

和浅拷贝不同的是,深拷贝是多带带开辟一段堆内存空间,把之前堆内存中的对象复制,这样在栈内存的新的引用会指向新的堆内存空间,新老两块空间彼此并没有直接的联系,这样的话,我们修改了之前的对象,新拷贝的对象并不会随之改变。

常见的深拷贝方法有两种,一种是递归,另外一种是JSON序列化。

function deepCopy(obj){
    let newObj = obj.constructor === Array ? []: {}   //判断是深拷贝对象还是数组
    
    for(let i in obj){
        if(typeof obj[i] === "object") {
            newObj[i] = deepCopy(obj[i])    //  如果要拷贝的对象的属性依然是个复合类型,递归
        } else {
            newObj[i] = obj[i]
        }
    }
    
    return newObj
}

let obj = {
    "a":1,
    "b":2,
    "c":{
        "c1":3,
        "c2":4
    }
}
let arr = [1,2,3,[4,5,6],7]

let newObj = deepCopy(obj)
let newArr = deepCopy(arr)

obj.b = 22
arr[3][1] = 55

console.log(obj.b,newObj.b)     // 22 2
console.log(arr[3][1],newArr[3][1])   //55 5

运用递归,当要拷贝的对象或者数组的属性依然是个对象或者数组时,递归调用。

除了递归的方式,使用JSON序列化可以很方便的解决深拷贝问题。

// 依然使用上面的例子
let newObj = JSON.parse(JSON.stringify(obj))

这种方法很巧妙很简单,但是,局限性在于不能拷贝继承的属性,原型中的属性。只有在一些简单的场合才推荐使用。

遍历对象

聊完了深拷贝和浅拷贝,接下来说一下遍历。因为我们发现,上面深拷贝的时候执行递归的时候,采用的是for ...in的遍历方式。

除了for...in,在js中的遍历方式还有很多,比如Object.keys(),for...of等等,那么这些遍历方式有什么不同呢。

Object.keys()

这个方法用于遍历,能够遍历出来的东西是对象中所有的可枚举的属性,但是不包括继承过来了。

for...in

for...in一般用于遍历对象,能够返回对象包括继承过来的可枚举属性。

Object.getOwnPropertyNames(obj)

返回对象所有的属性,也包括不可枚举的属性。但是不包括继承过来的。
这个函数会返回一个数组。

这三个遍历对象的方法,都不会返回对象中的symbol属性。

遍历数组

和遍历对象不同,遍历数组也有一些方法。

for...in

for...in除了可以遍历对象,也可以遍历数组,所以上面的例子我们可以用for...in分别遍历对象和数组。

forEach()

这是ES5新提供的一个方法,接收一个函数作为参数,回调函数。

for...of

ES6提供的遍历器,除了可以遍历数组,还支持类数组对象,甚至是字符串,其实就是继承了Iterator接口的数据结构都可以用for...of来遍历。

for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。

我认为,遍历数组,使用for...of效果最佳。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93053.html

相关文章

  • 小tips:JS之浅拷贝拷贝

    摘要:浅拷贝深拷贝浅拷贝的问题如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。 浅拷贝: function extendCopy(p) {  var c = {};  for (var i in p) {    c[i] = p[i];  }  return c; } 深拷贝: function deepCopy(p...

    Soarkey 评论0 收藏0
  • JavaScript之浅拷贝

    摘要:前言里面浅拷贝和深拷贝是非常关键的知识点,今天就来通过本文清楚的了解深浅拷贝以及该如何实现这两种拷贝方式。对象的拷贝又分为浅拷贝和深拷贝。印证了上述所说的对于所有的基本类型,简单的赋值已经是实现了深拷贝。 前言 JavaScript里面浅拷贝和深拷贝是非常关键的知识点,今天就来通过本文清楚的了解深浅拷贝以及该如何实现这两种拷贝方式。 深浅拷贝的区别 拷贝:其实就是一个对象复制给另外...

    leanxi 评论0 收藏0
  • 拷贝拷贝

    摘要:二浅拷贝与深拷贝深拷贝和浅拷贝是只针对和这样的引用数据类型的。浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。对于字符串数字及布尔值来说不是或者对象,会拷贝这些值到新的数组里。 一、数据类型 数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。 基本数据类型的特点:直...

    hzc 评论0 收藏0
  • 拷贝拷贝

    摘要:二浅拷贝与深拷贝深拷贝和浅拷贝是只针对和这样的引用数据类型的。浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。对于字符串数字及布尔值来说不是或者对象,会拷贝这些值到新的数组里。 一、数据类型 数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。 基本数据类型的特点:直...

    史占广 评论0 收藏0
  • JS专题之拷贝

    摘要:在之前的文章专题之数据类型和类型检测中我有讲过,中的数据类型分为两种,基本数据类型和引用数据类型,基本数据类型是保存在栈的数据结构中的是按值访问,所以不存在深浅拷贝问题。 前言 在开发过程中,偶尔会遇到这种场景,拿到一个数据后,你打算对它进行处理,但是你又希望拷贝一份副本出来,方便数据对比和以后恢复数据。 那么这就涉及到了 JS 中对数据的深浅拷贝问题,所谓深浅拷贝,浅拷贝的意思就是,...

    ASCH 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<