Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript实现浅拷贝和深拷贝 #17

Open
GGXXMM opened this issue Aug 10, 2019 · 0 comments
Open

JavaScript实现浅拷贝和深拷贝 #17

GGXXMM opened this issue Aug 10, 2019 · 0 comments
Labels
⭐️ js js knowledge

Comments

@GGXXMM
Copy link
Owner

GGXXMM commented Aug 10, 2019

什么是浅拷贝?

浅拷贝,又称浅复制,针对Object、Array、Function复杂对象只复制了引用,拷贝后的对象和原对象指向同一个堆内存地址。

实现浅拷贝

  • 数组浅拷贝(API)
// slice
var arr1 = [{'a': {'b':1} }, 2, 3];
var newArr1 = arr1.slice();
console.log(arr1[0].a === newArr1[0].a);// true

// concat
var arr2 = [{'a': {'b':1} }, 2, 3];
var newArr2 = arr2.concat();
console.log(arr2[0].a === newArr2[0].a);// true
  • 对象浅拷贝
var obj = { a: {a: "kobe", b: 39} };
var newObj = Object.assign({}, obj);
console.log(newObj.a === obj.a);// true
  • 手写实现浅拷贝

浅拷贝:仅拷贝第一级,第二级及其以后和原始对象共用堆地址

var shallowCopy = function (obj) {
  if(typeof obj !== 'object') return;

  let newObj = obj instanceof Array ? [] : {};
  for(let key in obj) {
    if(obj.hasOwnProperty(key)) {
      newObj[key] = obj[key]
    }
  }
  return newObj;
}

什么是深拷贝?

深拷贝,又称深复制,完全拷贝一个新的对象,将对象的所有属性进行拷贝,拷贝后的对象和原对象是2个不同的对象,指向不同的堆内存。

实现深拷贝

一、 JSON.stringify简单粗暴法(不能处理function函数)

function Obj() { 
  this.func = function () { alert(1) }; 
  this.obj = {a:1};
  this.arr = [1,2,3];
  this.und = undefined; 
  this.reg = /123/; 
  this.date = new Date(0); 
  this.NaN = NaN;
  this.infinity = Infinity;
  this.sym = Symbol(1);
} 

let obj1 = new Obj();
Object.defineProperty(obj1,'innumerable',{ 
  enumerable:false,
  value:'innumerable'
});
console.log('obj1',obj1);

let obj2 = JSON.parse(JSON.stringify(obj1));
console.log('obj2',obj2);

image
缺点:

  1. 拷贝对象的值有 undefinedsymbol函数 几种数据类型,经过转换后,这些键值对会消失
  2. 拷贝对象的值有 NaNInfinity-Infinity,经过转换后,这些值都会变成 null
  3. 拷贝Date引用类型,会变成时间字符串
  4. 拷贝RegExp引用类型,会变成空对象
  5. 无法拷贝不可枚举的属性

二、 递归逐一拷贝各个属性(基础版)

var deepCopy = function (obj) {
    if (typeof obj !== 'object') {
        return
    }
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
        }
    }
    return newObj
}

缺点:

  1. 拷贝对象值为functionDateRegExpError不能正常拷贝,拷贝后均为空对象{}
  2. 不能拷贝不可枚举属性

三、改进版

/**
 * 较为完善的深拷贝
 * @param {Object/Array/Date/RegExp/Function/String/Number/Boolean/Undefined/Null/Symbol} data
 * @return cloneData 拷贝后的对象
 */
function deepCopy(data) {
  let type = checkDataType(data);
  let cloneData = (type === 'array' ? [] : {});

  if(typeof data === 'object') {// 引用数据类型
    switch (type) {
      case 'object':
        for(let key in data) {
          cloneData[key] = deepCopy(data[key])
        }
        return cloneData;
      case 'array':
        data.forEach(item => {
          cloneData.push(deepCopy(item))
        })
        return cloneData;
      default:
        // 其他引用类型,包括Date/RegExp/Function
        return data;
    }
  }else {// 基础数据类型
    return data;
  }
}

function checkDataType(data) {
  let typeObj = {
    // 7种原始数据类型
    "[object String]": 'string',
    "[object Number]": 'number',
    "[object Boolean]": 'boolean',
    "[object Undefined]": 'undefined',
    "[object Null]": 'null',
    "[object Object]": 'object',
    "[object Symbol]": 'symbol',
    // 引用类型
    "[object Function]": 'function',
    "[object Array]": 'array',
    "[object Date]": 'date',
    "[object RegExp]": 'regexp',
  }

  let typeKey = Object.prototype.toString.call(data);
  return typeObj[typeKey];
}
@GGXXMM GGXXMM changed the title 手写js浅拷贝和深拷贝 JavaScript实现浅拷贝和深拷贝 Jan 19, 2021
@GGXXMM GGXXMM added the ⭐️ js js knowledge label Dec 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⭐️ js js knowledge
Projects
None yet
Development

No branches or pull requests

1 participant