JavaScript deep copy is developed by beginners and even experienced, and they often encounter problems and cannot understand JavaScript deep copy very well.
DeepClone?
The opposite of deep copy is shallow copy. Many beginners are confused when they come into contact with this feeling.
Why use deep copy?
In many cases, we need to assign values to variables and assign a value to the memory address. However, when assigning a reference value type, we only share a memory area, which results in maintaining consistency with the previous value when assigning.
See a specific example
// Assign an object to test var test = { a: 'a', b: 'b'};// Assign test to test2// At this time, test and test2 share the same memory object, which is the shallow copy of var test2 = test;test2.a = 'a2';test.a === 'a2'// is trueIllustration:
This is a good idea to understand why reference value types data affect each other.
accomplish
To implement a deep copy function, we have to talk about the numerical type of javascript.
Determine javascript type
There are the following basic types in javascript
Type Description
undefinedundefined type has only one value undefined, which is the value when the variable is not assigned.
nullnull type also has only one value null, it is an empty object reference
BooleanBoolean has two values: true and false
String It represents text information
Number It represents digital information
Object It is an unordered collection of a series of properties, including function Function and array Array
It is impossible to judge function and array using typeof. Here we use the Object.prototype.toString method.
[By default, each object will inherit from the Object to the toString() method. If this method is not overwritten (blocked) by the same name method on the object itself or a closer upper prototype, the toString() method of the object will be called and the string type here represents an object type][1]
function type(obj) { var toString = Object.prototype.toString; var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; return map[toString.call(obj)];}Implement deepClone
For numeric values of non-referenced value types, the value is assigned directly, and for the referenced value types (object) you need to traverse again and assign recursively.
function deepClone(data) { var t = type(data), o, i, ni; if(t === 'array') { o = []; }else if( t === 'object') { o = {}; }else { return data; } if(t === 'array') { for (i = 0, ni = data.length; i < ni; i++) { o.push(deepClone(data[i])); } return o; }else if( t === 'object') { for( i in data) { o[i] = deepClone(data[i]); } return o; }}There is a point here that everyone should pay attention to. For function types, does the blogger directly assign values or share a memory value. This is because functions are more about completing certain functions, with an input value and a return value, and for upper-level services, they are more about completing business functions, and there is no need to really copy the function deeply.
But how to copy the function type?
In fact, the blogger only thought of using new to operate it, but the function will be executed once, and I dare not imagine what the execution result will be! o(□)o! I don’t have any good ideas yet, please give me guidance!
At this point, the deep copy has been almost completed, but some people think that why didn’t the shallow copy be implemented?
A shallow copy?
For shallow copies, it can be understood as operating only one common memory area! There will be danger here! (..*)
If you operate this shared data directly without controlling it, data exceptions will often occur and are changed by other parts. Therefore, you should not operate the data source directly, encapsulate some methods to perform CURD operations on the data.
It is probably almost the same here, but as a front-end, it not only considers JavaScript itself, but also the dom, browser, etc.
Element type
Let’s look at the following code, what will be returned in the result?
Object.prototype.toString.call(document.getElementsByTagName('div')[0])
The answer is [object HTMLDivElement]
Sometimes when the dom element is saved and if you accidentally copy it deep, the deep copy function above lacks judgment on the Element element. To judge the Element element, use instanceof to judge. Because for different tags, tostring will return the constructor corresponding to different tags.
function type(obj) { var toString = Object.prototype.toString; var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; if(obj instanceof Element) { return 'element'; } return map[toString.call(obj)];}Other ways?
Implementation of jquery
For details, please see https://github.com/jquery/jqu...
Underscore implementation
For details, please see https://github.com/jashkenas/...
Lodash implementation
For details, please see https://github.com/lodash/lod...
JSON implementation
You can realize deep copy by first passing JSON.stringify, and then JSON.parse. However, the data type only supports basic numeric types.
var obj = { a: 'a', b: function(){console.log('b')}}// When JSON.stringify, the function will be filtered. JSON.stringify(obj)// "{"a":"a"}"summary
Here we roughly summarize the deep copy and how to implement a deep copy. In different scenarios, it is necessary to determine whether deep copy is needed based on the business scenario.