The introduction
In each community to find the use of native JS to achieve deep cloning methods, opinions vary, most of the implementation effect is not ideal, here will be summed up each of the words, come to a perfect solution.
This article refers to the following articles, if you are interested, please go to the original link.
- JS type judgment, object cloning, array cloning
- How to make deep copy of objects in JS
- Parse (json.stringify (obj)) to implement deep copy
Shallow clone and deep clone
Shallow clone
- The primitive type is passed by value and the object type is still passed by reference.
- Primitive types get the right result even with normal cloning because primitive types store the actual data of the object.
A deep clone
- All elements or attributes are copied exactly, completely separated from the original object.
- Instead of assigning a reference to the original object to a new object, a clone creates a new object with a different reference address and copies the attributes of the original object to the new object.
Exploration of shallow clone implementation
Implementation of numerical cloning –> OK
const a = 1;
letb = a; console.log(b); //1 b = 2; console.log(a); // 1 console.log(b); / / 2Copy the code
Implementation of string cloning –> OK
const c="1"; let d=c; console.log(d); //"1" d="2"; console.log(c); // "1" console.log(d); / / "2"Copy the code
Implementation of Boolean clone –> OK
const x = true; let y = x; console.log(y); //true y = false; console.log(x); // true console.log(y); //falseCopy the code
Implementation of Symbol value cloning –> OK
const s1 = Symbol('foo'); let s2 = s1; console.log(s2); //Symbol(foo) console.log(s2 === s1); //true s2 = Symbol('bar'); console.log(s1, s2); //Symbol(foo) Symbol(bar) console.log(s2 === s1); //falseCopy the code
Implementation of function cloning –> OK
const m = function () {alert(1); }; let n = m; n(); //1 n = function () {alert(2); }; m(); //1 n(); / / 2Copy the code
Implementation of object cloning –> not OK
let obj = { a: 1, b: 2 } let obj2 = obj; console.log(obj); //{a: 1,b: 2} console.log(obj2); //{a: 1,b: 2} obj.a = 8; console.log(obj); //{a: 8,b: 2} console.log(obj2); //{a: 8,b: 2} //obj2 = obj is a reference to the same address value, changes in one of the values affect the otherCopy the code
Array clone implementation –> not ok
Because objects can be nested in arrays, objects cannot be deep-cloned, nor can arrays.
Exploration of implementation of proclonation
The classic JSON approach to deep cloning -> imperfect solution
function Person(name) { this.name = name; } const Jack = new Person('Jack'); Const obj = {a: 1, b: function (arg) {console.log(' I'm unique, JSON can't copy me '); }, c: { d: 3, e: { f: [1,[2,[3,[4,[5]]]]], g: { h: 5 } } }, date: [new Date(1536627600000), new Date(1540047600000)], reg: new RegExp('\\w+'), num: [NaN, Infinity, -Infinity], person: Jack, }; Parse (json.stringify (obj)); // let obj2 = json.parse (json.stringify (obj)); console.log(obj); console.log(obj2); obj.c.e.f = 1000; // Change the value of the source object obj2.c.e.g.h = 2000; // Change the value of the cloned object console.log(obj.c.e.f, obj2.c.e.f); console.log( obj.c.e.g.h, obj2.c.e.g.h);Copy the code
Running results:
It can be seen that the JSON cloning method has the following disadvantages:
- If obj has a time object in it (date), then json.stringify is followed by json.parse, and the time will be just a string. Not a time object
- If there are RegExp, Error objects (reg) in obj, then serialization results in empty objects
- If obj has a function (case B) with undefined, the serialization results in losing either function or undefined
- If obj has NaN, Infinity, and -infinity, the serialized result becomes null
- Parse (json.stringify (obj)) can only serialize the enumerable property of the object, for example, if the object in obj (case person) is generated by a constructor, then using json.parse (json.stringify (obj)) deep copy, Object constructor is discarded and all constructors point to Object
- Deep copy cannot be implemented correctly if there are circular references in the object. Therefore, we can conclude that json cloning is only suitable for clones of simple data types or reference data types that only carry simple data.
The common way to implement proclonation in network is not perfect solution
Function Person(name) {this.name = name; } const Jack = new Person('Jack'); Const obj = {a: 1, b: function (arg) {console.log(' copy me, you are cool '); }, c: { d: 3, e: { f: [1,[2,[3,[4,[5]]]]], g: { h: 5 } } }, date: [new Date(1536627600000), new Date(1540047600000)], reg: new RegExp('\\w+'), num: [NaN, Infinity, -Infinity], person: Jack, }; / / deep cloning method to realize the function deepClone (origin, target) {const tar = target | | {}; for (let item in origin) { if (origin.hasOwnProperty(item)) { if (typeof origin[item] === 'object') { tar[item] = Object.prototype.toString.call(origin[item]) === '[object Array]' ? [] : {}; deepClone(origin[item], tar[item]); } else { tar[item] = origin[item]; } } } return tar; } let obj2 = deepClone(obj, {}); console.log(obj); console.log(obj2); obj.c.e.f = 1000; obj2.c.e.g.h = 2000; console.log(obj.c.e.f, obj2.c.e.f); console.log( obj.c.e.g.h, obj2.c.e.g.h);Copy the code
Running results:
- If obj has a time object in it (in the case of Date), then the result is that the time is just an empty object
- If there are RegExp, Error objects (reg) in obj, then serialization results in empty objects
- If the object (person) in obj is generated with a constructor, the object’s constructor is discarded after using the deep copy.
Therefore, this function is not perfect for all types of deep cloning, but it is sufficient for routine development, which requires only cloning of objects or arrays, such as time objects, RegExp, Error objects, and objects generated by constructors.
Implementation of native JS deep clone -> perfect solution 1
Function Person(name) {this.name = name; } const Jack = new Person('Jack'); Const obj = {a: 1, b: function (arg) {console.log(' copy me, you are cool '); }, c: { d: 3, e: { f: [1,[2,[3,[4,[5]]]]], g: { h: 5 } } }, date: [new Date(1536627600000), new Date(1540047600000)], reg: new RegExp('\\w+'), num: [NaN, Infinity, -Infinity], person: Jack, }; Function deepClone(data) {const type = this.judgeType(data); let obj; if (type === 'Array') { obj = []; for (let i = 0, len = data.length; i < len; i++ ) { obj.push(this.deepClone(data[i])); } } else if (type === 'Object') { obj = new data.constructor (); If an object in obj is generated by a constructor, the object's constructor is discarded after using a deep copy; for (let key in data) { obj[key] = this.deepClone(data[key]); }} else {return data; } return obj; Function judgeType(obj) {if (obj instanceof Element) {return 'Element '; } return Object.prototype.toString.call(obj).slice(8,-1); } let obj2 = deepClone(obj); console.log(obj); console.log(obj2); obj.c.e.f = 1000; obj2.c.e.g.h = 2000; console.log(obj.c.e.f, obj2.c.e.f); console.log( obj.c.e.g.h, obj2.c.e.g.h);Copy the code
Running results:
Implementation of native JS deep clone –> perfect solution 2
Function Person(name) {this.name = name; } const Jack = new Person('Jack'); Const obj = {a: 1, b: function (arg) {console.log(' copy me, you are cool '); }, c: { d: 3, e: { f: [1,[2,[3,[4,[5]]]]], g: { h: 5 } } }, date: [new Date(1536627600000), new Date(1540047600000)], reg: new RegExp('\\w+'), num: [NaN, Infinity, -Infinity], person: Jack, }; Function deepClone(obj) {if (obj === null) return null; if (typeof obj ! == 'object') return obj; if (obj.constructor === Date) return new Date(obj); if (obj.constructor === RegExp) return new RegExp(obj); const newObj = new obj.constructor (); For (let key in obj) {if (obj.hasownProperty (key)) {const val = obj[key]; newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; // Use arguments.callee to uncouple function names. } } return newObj; } const obj2 = deepClone(obj); console.log(obj); console.log(obj2); obj.c.e.f = 1000; obj2.c.e.g.h = 2000; console.log(obj.c.e.f, obj2.c.e.f); console.log( obj.c.e.g.h, obj2.c.e.g.h);Copy the code
Running results:
Compared with the last perfect solution, the implementation of this method is commendable, the amount of code is less, the same is to achieve a variety of data types of deep clone implementation, choose which method is no problem, see personal preference.
The above is the deep cloning method after the summary of personal reference, if there is incorrect place, please give directions to all parties, thank you!