浅拷贝:仅仅是指向被拷贝的内存地址,如果原地址中对象被改变了,那么浅拷贝出来的对象也会相应改变。
深拷贝:在计算机中开辟了一块新的内存地址用于存放复制的对象。
var sourceObj = {
name: 'tt',
age: 18,
job: 'web',
friends: ['t1', 't2']
}
const shallowClone = (target) => {
if (typeof target === 'object' && target !== null) {
const cloneTarget = Array.isArray(target) ? [] : {};
for (let prop in target) {
if (target.hasOwnProperty(prop)) {
cloneTarget[prop] = target[prop];
}
}
return cloneTarget;
} else {
return target;
}
}
let target = {};
let source = { a: { b: 1 } };
Object.assign(target, source);
console.log(target);
let obj1 = { a: { b: 1 }, sym: Symbol(1) };
Object.defineProperty(obj1, 'innumerable', {
value: '不可枚举属性',
enumerable: false
});
let obj2 = {};
Object.assign(obj2, obj1)
obj1.a.b = 2;
console.log('obj1', obj1);
console.log('obj2', obj2);
let obj = { a: 1, b: { c: 1 } };
let obj2 = { ...obj };
obj.a = 2;
console.log(obj);
obj.b.c = 2;
console.log(obj);
let arr = [1, 2, 3];
let newArr = [...arr];
let arr = [1, 2, 3];
let newArr = arr.concat();
newArr[1] = 100;
console.log(arr);
console.log(newArr);
let arr = [1, 2, { val: 4 }];
let newArr = arr.slice();
newArr[2].val = 1000;
console.log(arr);
var _ = require("lodash");
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3],
};
var obj2 = _.clone(obj1);
console.log(obj1.b.f === obj2.b.f);
var a = {name:1, sya:function(){ console.log("打印")},age:undefined};
var b = JSON.parse(JSON.stringify(a));
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 str = JSON.stringify(obj1);
let obj2 = JSON.parse(str);
console.log('obj2', obj2);
var sourceObj = {
name: 'tt',
age: 18,
job: 'web',
friends: ['t1', 't2']
}
var util = (function() {
var class2Type = {}
var objTypes = ["Null","Undefined","Number","Boolean","String","Object","Function","Array","RegExp","Date”]
objTypes.forEach(function(item) {
class2Type['[object ' + item + ']'] = item.toLowerCase()
})
function isType(obj, type) {
return getType(obj) === type
}
function getType(obj) {
return class2type[Object.prototype.toString.call(obj)] || 'object'
}
return {
isType: isType,
getType: getType
}
})()
function copy(obj, deep){
if(obj == null || typeof obj !== 'object'){
return obj
}
var i,
target = util.isType(obj,"array") ? [] : {},
value,
valueType
for(i in obj){
value = obj[i]
valueType = util.getType(value)
if(deep && (valueType === "array" || valueType === "object")){
target[i] = copy(value)
}else{
target[i] = value
}
}
return target
}
var targetObj = copy(sourceObj, true);
targetObj.friends.push ('t3');
console.log(sourceObj)
Object.prototype.clone = function() {
var Constructor = this.constructor
var obj = new Constructor()
for (var attr in this) {
if (this.hasOwnProperty(attr)) {
if (typeof this[attr] !== 'function') {
if (this[attr] === null) {
obj[attr] = null
} else {
obj[attr] = this[attr].clone()
}
}
}
}
return obj
}
Array.prototype.clone = function() {
var thisArr = this.valueOf()
var newArr = []
for (var i = 0; i < thisArr.length; i++) {
newArr.push(thisArr[i].clone())
}
return newArr
}
Boolean.prototype.clone = function() {
return this.valueOf()
}
Number.prototype.clone = function() {
return this.valueOf()
}
String.prototype.clone = function() {
return this.valueOf()
}
Date.prototype.clone = function() {
return new Date(this.valueOf())
}
RegExp.prototype.clone = function() {
var pattern = this.valueOf()
var flags = ''
flags += pattern.global ? 'g' : ''
flags += pattern.ignoreCase ? 'i' : ''
flags += pattern.multiline ? 'm' : ''
return new RegExp(pattern.source, flags)
}
function deepClone(source){
const targetObj = source.constructor === Array ? [] : {};
for(let keys in source){
if(source.hasOwnProperty(keys)){
if(source[keys] && typeof source[keys] === 'object'){
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
}else{
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
var a = {name:1, sya:function(){ console.log("打印")},age:undefined};
var b = deepClone(a);
b.name=2;
console.log(a)
console.log(b)
1. 针对能够遍历对象的不可枚举属性以及 Symbol 类型,我们可以使用 Reflect.ownKeys 方法;
2. 当参数为 Date、RegExp 类型,则直接生成一个新的实例返回;
3. 利用 Object 的 getOwnPropertyDescriptors 方法可以获得对象的所有属性,以及对应的特性,顺便结合 Object 的 create 方法创建一个新对象,并继承传入原对象的原型链;
4. 利用 WeakMap 类型作为 Hash 表,因为 WeakMap 是弱引用类型,可以有效防止内存泄漏,作为检测循环引用很有帮助,如果存在循环,则引用直接返回 WeakMap 存储的值。
const isComplexDataType = obj => (typeof obj === 'object' || typeof obj === 'function') && (obj !== null);
const deepClone = function (obj, hash = new WeakMap()) {
if (obj.constructor === Date) return new Date(obj)
if (obj.constructor === RegExp) return new RegExp(obj)
if (hash.has(obj)) return hash.get(obj)
let allDesc = Object.getOwnPropertyDescriptors(obj);
let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc);
hash.set(obj, cloneObj);
for (let key of Reflect.ownKeys(obj)) {
cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key], hash) : obj[key]
}
return cloneObj
}
let obj = {
num: 0,
str: '',
boolean: true,
unf: undefined,
nul: null,
obj: {
name: '我是一个对象',
id: 1
},
arr: [0, 1, 2],
func: function () {
console.log('我是一个函数')
},
date: new Date(0),
reg: new RegExp('/我是一个正则/ig'),
[Symbol('1')]: 1,
};
Object.defineProperty(obj, 'innumerable', {
enumerable: false,
value: '不可枚举属性'
});
obj = Object.create(obj, Object.getOwnPropertyDescriptors(obj))
obj.loop = obj
let cloneObj = deepClone(obj)
cloneObj.arr.push(4)
console.log('obj', obj)
console.log('cloneObj', cloneObj)
var a = {n: 1}
var b = a;
a.x = a = {n: 2}
console.log(a.x);
console.log(b.x);
var a = {n: 1}
var b = a;
b.n = a.f = {n: 2};
console.log(a);
console.log(b);