Comprenez le processus derrière la copie et évitez les erreurs inutiles. Js série spéciale de copie profonde et superficielle, travaillons ensemble ~
Contenu
4. Implémentez vous-même une copie profonde et superficielle
Recommandation d'apprentissage gratuite : javascript tutoriel vidéo
1. Exemple de copie
Lorsque nous exploitons des données, nous pouvons rencontrer la situation suivante :
Lorsque nous rencontrons un scénario de besoin similaire, la première chose qui nous vient à l'esprit est de le copier, mais nous ne savons pas que la copie est également très compétente ~
L'exemple simple ci-dessous vous semble-t-il familier ?
var str = 'How are you';var newStr = str;newStr = 10console.log(str); // How are youconsole.log(newStr); // 10
Comme tout le monde peut l'imaginer, la chaîne est un type de base et sa valeur est stockée dans la pile, elle ouvre en fait de nouvelles variables. nouvel espace. str
et newStr
sont comme deux pièces identiques, avec la même disposition mais sans connexion.
var data = [1, 2, 3, 4, 5];var newData = data;newData[0] = 100;console.log(data[0]); // 100console.log(newData[0]); // 100
Segment de code similaire, mais cette fois nous utilisons le type de référence du tableau comme exemple. Vous constaterez qu'après avoir modifié les données attribuées, les données d'origine ont. a également changé. Cela ne répond évidemment pas à nos besoins. Cet article parlera de la connaissance de la copie des données citées.
Si vous avez des questions sur les types de données Js, vous pouvez aussi bien consulter "Types de données de base en JavaScript"
2. Copie superficielle
La division de la copie est discutée en fonction des types de référence. Comme son nom l'indique, la copie superficielle est une « copie superficielle ». travail superficiel :
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]
Heureusement, rien ne se passe (opération). Une fois le nouveau tableau opéré, les données stockées dans les deux variables changeront.
La raison pour laquelle ce genre de situation se produit est également due aux caractéristiques de base de 引用类型
:
Slice et concat dans le tableau renverront un nouveau tableau Essayons-le ensemble :
var arr = [1,2,3,4];var res = arr.slice();// 或者res = arr.concat()res[0] = 100;console.log(arr); // [1,2,3,4]
Ce problème est-il résolu si rapidement ? Bien que cette couche de données soit traitée de cette manière, le problème est bel et bien résolu, mais !
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] ]
Effectivement, les choses ne sont pas si simples, et cela est aussi dû aux différents types de données.
S ne nous permet pas d'opérer directement l'adresse dans la mémoire, ce qui signifie que nous ne pouvons pas opérer l'espace mémoire de l'objet. Nos opérations sur l'objet n'opèrent donc que sur sa référence.
Étant donné que 浅拷贝
ne peut pas répondre à nos exigences, basées sur le principe d'efficacité, nous recherchons des moyens de nous aider à atteindre 深拷贝
.
3. Comment copier en profondeur ?
La méthode des données a échoué, existe-t-il un autre moyen ? Nous devons obtenir une copie fidèle des données indépendantes.
Ici, nous utilisons deux méthodes de JSON, JSON.stringify()
, JSON.parse()
pour obtenir la copie profonde la plus simple
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}]
Cette méthode doit être utilisée pour obtenir une copie profonde copier La copie est la méthode la plus simple, mais elle pose encore des problèmes Jetons un coup d'œil à ce que nous venons de faire :
arr
JSON 字符串
值或对象
est compris :
Nous pouvons comprendre que les données d'origine sont converties en 新字符串
, puis restaurées en une seule via 新字符串
新对象
, la méthode de modification du type de données contourne indirectement le processus de copie de la référence de l'objet et n'affecte pas les données d'origine.
Limitations :
L'objectif fondamental de cette méthode est de garantir l'intégrité des données lors du "transfert", et JSON.stringify()
convertir la valeur dans le Il y a aussi des défauts :JSON格式
所以当我们拷贝函数、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(视频)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!