Understand the process behind copying and avoid unnecessary mistakes. Let’s work together on the deep and shallow copying of Js special series~
Contents
4. Implement deep and shallow copy by yourself
Free learning recommendation: javascript video tutorial
1. Copy example
When we operate the data, we may encounter the following situation:
When we encounter similar need scenarios, the first thing that comes to mind is to copy it, but we don’t know that copying also has a lot of knowledge~
Does the following simple example sound familiar to you?
var str = 'How are you';var newStr = str;newStr = 10console.log(str); // How are youconsole.log(newStr); // 10
As everyone can imagine, string is a basic type, and its value is stored in the stack. When copying it, it is actually opening up new variables. new space. str
and newStr
are like two identical rooms, with the same layout but no connection.
var data = [1, 2, 3, 4, 5];var newData = data;newData[0] = 100;console.log(data[0]); // 100console.log(newData[0]); // 100
Similar code segment, but this time we use the reference type of array as an example. You will find that after modifying the assigned data, the original data has also changed. This obviously doesn't meet our needs. This article will talk about the knowledge of quoting data copy.
If you have questions about the data types of Js, you might as well take a look at "Basic Data Types in JavaScript"
2. Shallow copy
The division of copies is discussed based on reference types. Shallow copy - as the name suggests, shallow copy is a "shallow copy". In fact, it only does superficial work:
var arr = [1, 2, 3, 4];var newArr = arr;console.log(arr, newArr); // [1,2,3,4] [1,2,3,4]newArr[0] = 100;console.log(arr, newArr) // [100,2,3,4] [100,2,3,4]
Fortunately, nothing happens (operation). Once the new array is operated on, the data stored in both variables will change.
The reason why this kind of situation occurs is also because of the basic characteristics of reference type
:
Both slice and concat in the array will return a new array. Let’s try it together:
var arr = [1,2,3,4];var res = arr.slice();// 或者res = arr.concat()res[0] = 100;console.log(arr); // [1,2,3,4]
Is this problem solved so quickly? Although this layer of data is processed in this way, the problem is indeed solved, but!
var arr = [ { age: 23 }, [1,2,3,4] ];var newArr = arr.concat();arr[0].age = 18;arr[1][0] = 100;console.log(arr) // [ {age: 18}, [100,2,3,4] ]console.log(newArr) // [ {age: 18}, [100,2,3,4] ]
Sure enough, things are not that simple, this is also because of the different data types.
S We are not allowed to directly operate the address in the memory, which means that we cannot operate the memory space of the object. Therefore, our operations on the object are only operating on its reference.
Since shallow copy
cannot meet our requirements, based on the principle of efficiency, we are looking to see if there is anyone who can help us achieve deep copy
Methods.
#3. How to deep copy?
The data method failed, is there any other way? We need to achieve a true copy of independent data.
Here we use two methods of JSON, JSON.stringify()
, JSON.parse()
to achieve the most concise Deep copy
var arr = ['str', 1, true, [1, 2], {age: 23}]var newArr = JSON.parse( JSON.stringify(arr) );newArr[3][0] = 100;console.log(arr); // ['str', 1, true, [1, 2], {age: 23}]console.log(newArr); // ['str', 1, true, [100, 2], {age: 23}]
This method should be the simplest way to implement deep copy, but it still has problems, let’s take a look at what we just did:
arr
JSON string
values or objects described by strings
Understand :
We can understand that the original data is converted into new string
, and then restored to a new object# through
new string ##, the method of changing the data type indirectly bypasses the process of copying the object reference, and does not affect the original data.
Restrictions:
The fundamental purpose of this method is to ensure the integrity of the data during "transfer", andJSON.stringify() There are also flaws in converting values to the corresponding
JSON format:
所以当我们拷贝函数、undefined等stringify
转换有问题的数据时,就会出错,我们在实际开发中也要结合实际情况使用。
举一反三:
既然是通过改变数据类型来绕过拷贝引用这一过程,那么单纯的数组深拷贝是不是可以通过现有的几个API来实现呢?
var arr = [1,2,3];var newArr = arr.toString().split(',').map(item => Number(item))newArr[0] = 100;console.log(arr); // [1,2,3]console.log(newArr); // [100,2,3]
注意,此时仅能对包含纯数字的数组进行深拷贝,因为:
但我愿称它为纯数字数组深拷贝!
有的人会认为Object.assign()
,可以做到深拷贝,我们来看一下
var obj = {a: 1, b: { c: 2 } }var newObj = Object.assign({}, obj)newObj.a = 100;newObj.b.c = 200;console.log(obj); // {a: 1, b: { c: 200 } }console.log(newObj) // {a: 100, b: { c: 200 } }
神奇,第一层属性没有改变,但第二层却同步改变了,这是为什么呢?
因为 Object.assign()拷贝的是(可枚举)属性值。
假如源值是一个对象的引用,它仅仅会复制其引用值。MDN传送门
四、自己实现深浅拷贝
既然现有的方法无法实现深拷贝,不妨我们自己来实现一个吧~
我们只需要将所有属性即其嵌套属性原封不动的复制给新变量一份即可,抛开现有的方法,我们应该怎么做呢?
var shallowCopy = function(obj) { if (typeof obj !== 'object') return; // 根据obj的类型判断是新建一个数组还是对象 var newObj = obj instanceof Array ? [] : {}; // 遍历obj,并且判断是obj的属性才拷贝 for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj;}
我们只需要将所有属性的引用拷贝一份即可~
相信大家在实现深拷贝的时候都会想到递归,同样是判断属性值,但如果当前类型为object
则证明需要继续递归,直到最后
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;}
我们用白话来解释一下deepCopy
都做了什么
const obj = [1, { a: 1, b: { name: '余光'} } ];const resObj = deepCopy(obj);
obj
,创建 第一个newObj[]
0
(for in
以任意顺序遍历,我们假定按正常循序遍历)1
obj[1]
另外请注意递归的方式虽然可以深拷贝,但是在性能上肯定不如浅拷贝,大家还是需要结合实际情况来选择。
写在最后
前端专项进阶系列的第五篇文章
,希望它能对大家有所帮助,如果大家有什么建议,可以在评论区留言,能帮到自己和大家就是我最大的动力!
相关免费学习推荐:javascript(视频)
The above is the detailed content of JavaScript Topic 5: Deep and Shallow Copy. For more information, please follow other related articles on the PHP Chinese website!