对象的深浅拷贝

标题对象的深浅拷贝

在进行实例讲解之前,我们先下个给深浅拷贝下个定义,什么是深拷贝?什么是浅拷贝?

个人理解:

  • 浅拷贝:针对指针的引用
  • 深拷贝: 对值的引用

浅拷贝

先看🌰:

var obj = {
  a: 1,
  b: 2,
};
var newObj = obj
obj.a = 3
console.log(obj.a)  // 3
console.log(newObj.a) // 3

深拷贝

var obj = {
  a: 1,
  b: 2,
};
var newObj = {};
Object.keys(obj).map(item => {
  newObj[item] = obj[item];
});
obj.a = 666
console.log(obj.a) // 666
console.log(newObj.a) // 1

比较🌰1 和 例子2 的不同,这里将 1 (针对地址的引用) 称之为浅拷贝,2 (针对属性的拷贝) 称之为深拷贝,
区别也是显而易见的

案列:实现对象深拷贝的

var obj = {
  a: 1,
  b: 2,
  c: { sex: "man", options: { age: 22 } }
};
var newObj = {};
function objDeep(newObj, obj) {
  Object.keys(obj).map(item => {
    if (obj[item] && !(obj[item] instanceof Object)) {
      newObj[item] = obj[item];
    } else {
      newObj[item] = {};
      arguments.callee(newObj[item], obj[item]);
    }
  });
}
objDeep(newObj, obj);
newObj.a = 999
console.log(obj.a) // 1
console.log(newObj.a) // 999

Object.assign()

既然提到对象的浅拷贝,就不得不提到 Object.assign()

MDN中的解释为:Object.assign() 方法用于将 所有可枚举属性的值 从一个或多个源对象复制到目标对象。它将返回目标对象。
举例:

Object.assign(target, source)
var obj = { a: 1, b: 2 };
var copy = Object.assign({a: 3}, obj);
console.log(copy); // { a: 1, b: 2 }

这里注意:源对象中的属性会代替目标对象的同名属性,这也就导致目标对象中的 {a: 3} 最终被替换为 {a: 1} 的结果
既然谈到了是可枚举属性,那我们再来看看不可枚举属性
对象的 数据属性访问器属性 请自行查看 高层三, pdf 下载地址

// 通过 Object.create() 创建的对象,默认都是不可枚举的,需要手动设置
var obj = Object.create({foo: 1}, { // foo 是个继承属性。
    a: {
        name: 'lilie'  // a 是个不可枚举属性。
    },
    b: {
        name: 'lili',
        enumerable: true  // b 是个自身可枚举属性。
    }
});

var copy = Object.assign({}, obj);
console.log(copy); // { b: 'lili' }

为啥Object.assign() 是浅拷贝,我们再来看一个🌰:

var obj = { a: 1, b: [1,3],c: {name: 'name', age: 30} };
var copy = Object.assign({a: 3}, obj);
obj.a = 999
console.log(obj.a) // 999
console.log(copy.a); // 1

写到这里,根据控制台打印结果,我反问自己,这不就是深拷贝么,事实上,你可以简单粗暴的这么理解,因为MDN解释很清楚了, Object.assign() 是对值的引用

  • 到次为此,我们已经知道了两种关于对象深拷贝的方法

我们不妨再来一个骚操作:

var obj = { a: 1, b: [1,3],c: {name: 'name', age: 30} };
var copy = JSON.parse(JSON.stringify(obj)) // 先转化为字符串,在转化为json对象,相当于完完全全拷贝了一个副本
obj.a = 999
console.log(obj.a) // 999
console.log(copy.a); // 1

到这里,应该基本上差不多了
但是笔者我不忍心,Object.assign() 感觉很像对象的去重复,各位看官有木有,既然如此,我们顺便把 数组的去重扁平化处理 的面试常遇到的代码顺便分享一下

一下关于 es6 的相关知识,如果不太了解,请移步至 es6 教程

数组的去重

let arr = [1, 5, 46, 79, 46, 78, 941, 1111, 1, 1, 1, 1, 1, 1, 1]
let arr0 = [...new Set(arr)] // 通过 es6 的 set 结合 数组的扩展语法
console.log(arr0)
let arr1 = Array.from(new Set(arr))  // 通过 es6 的 set 结合 数组的Array.from
console.log(arr1)
[1,3,4,5,1,2,3,3,4,8,90,3,0,5,4,0].filter(function(elem,index,Array){
   return index === Array.indexOf(elem);
})
console.log(r)

let arr2 = [] // 土鳖的循环
for (let i = 0; i < arr.length; i++) {
    if (arr2.indexOf(arr[i]) === -1) arr2.push(arr[i])
}
console.log(arr2)
//自定义添加方法去重复方法  可以是各种类型
   var arr3= [0, 1, '1', true, 5, true, false, undefined, undefined, null, null];
   if (!Array.prototype.unique) {
    Array.prototype.unique = function () {
    var hash = {}, result = [], type = '', item;
       for (var i = 0; i < this.length; i++) {
       item = this[i];
       type = Object.prototype.toString.call(item);// 专门用来判断字符串的类型的
          if ( !hash[item + type] ) {
             hash[item + type] = true;
             result.push(item);
          }
       }
      return result;
    };
   }
   console.log(arr3.unique());
//对象的方法来找出先次数最多的数字
   var adv={
      init:function(){
         var arr=[1,2,5,2,5,5,4,1,1,1,2,2,2];
         function findNum(arr){
            for(var i=0,hash=[];i<arr.length;i++){
               hash[arr[i]]=0;
               for(var r=0;r<arr.length;r++){
                  if(arr[i]==arr[r]){
                     hash[arr[i]]++;
                  }
               }
            }
            get(hash);
            //[4, 5, 1, 3]  
            // 1  2  4  5
         }
         function get(hash){
            var arr=[];
            for(var key in hash){
               arr.push(hash[key]);
            }
            arr.sort(function(a,b){return b-a});
            for(var key in hash){
               if(hash[key]==arr[0])
               console.log(key);
            }
            
         }
         findNum(arr);
      }
   }

扁平化处理

/** 数组相关的常用方法 */
const aboutArrayFun = {
  /** 扁平化处理 */
  // 递归
  flattenOne: arr => {
    var res = [];
    for (var i = 0; i < arr.length; i++) {
      if (Array.isArray(arr[i])) {
        res = res.concat(flattenOne(arr[i]));
      } else {
        res.push(arr[i]);
      }
    }
    return res;
  },
  // reduce
  flattenTwo: arr => {
    return arr.reduce(function(prev, item) {
      return prev.concat(Array.isArray(item) ? flattenTwo(item) : item);
    }, []);
  },
  // 扩展运算符
  flattenThree: arr => {
    while (arr.some(item => Array.isArray(item))) {
      arr = [].concat(...arr);
    }
    return arr;
  },
}

关于对象的深浅拷贝就到这里,以上是个人的理解,其实并不难,只要抓住了重点

更多的干货请点击这里
react-native 实战项目学习
欢迎各位看官的批评和指正,共同学习和成长
希望该文章对您有帮助,也希望得到您的鼓励和支持

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章