Maison > interface Web > js tutoriel > Sujet JavaScript 5 : Copie approfondie et superficielle

Sujet JavaScript 5 : Copie approfondie et superficielle

coldplay.xixi
Libérer: 2021-03-08 09:36:14
avant
2025 Les gens l'ont consulté

Sujet JavaScript 5 : Copie approfondie et superficielle

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

  • 1. Exemple de copie
  • 2. Copie superficielle
  • 3.
  • 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 :

  1. Un ensemble de données sera modifié fréquemment, mais les données d'origine peuvent être utilisées
  2. J'ai besoin de deux ensembles de données identiques, mais je ne veux pas en modifier un et l'autre changera en conséquence
  3. Moi Il est nécessaire de comparer les données avant et après l'opération

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 ?

1.1 Exemple de copie de type de base
var str = 'How are you';var newStr = str;newStr = 10console.log(str); // How are youconsole.log(newStr); // 10
Copier après la connexion

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.

1.2 Exemple de copie de type référence
var data = [1, 2, 3, 4, 5];var newData = data;newData[0] = 100;console.log(data[0]); // 100console.log(newData[0]); // 100
Copier après la connexion

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"

Sujet JavaScript 5 : Copie approfondie et superficielle

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]
Copier après la connexion

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 引用类型 :

  • La valeur stockée dans la variable est un pointeur (point), pointant vers l'adresse mémoire de l'objet stocké. Attribuer une valeur à une nouvelle variable équivaut à attribuer une nouvelle clé, et la pièce n'a pas été modifiée.

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]
Copier après la connexion

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] ]
Copier après la connexion

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 深拷贝.

Sujet JavaScript 5 : Copie approfondie et superficielle

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.

3.1 JSON

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}]
Copier après la connexion

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 :

  1. Définir un tableau contenant tous les typesarr
  2. .
  3. JSON.stringify(arr), convertit un objet ou une valeur JavaScript en JSON 字符串
  4. JSON.parse(xxx), la méthode est utilisée pour analyser les chaînes JSON, construites à partir de chaînes La description de 值或对象

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、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。
  • 函数、undefined 被单独转换时,会返回 undefined,
    • 如JSON.stringify(function(){})
    • JSON.stringify(undefined)
  • 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
  • NaN 和 Infinity 格式的数值及 null 都会被当做 null。
  • 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。

所以当我们拷贝函数、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]
Copier après la connexion

注意,此时仅能对包含纯数字的数组进行深拷贝,因为:

  1. toString无法正确的处理对象和函数
  2. Number无法处理 false、undefined等数据类型

但我愿称它为纯数字数组深拷贝

Sujet JavaScript 5 : Copie approfondie et superficielle

3.2 Object.assign()

有的人会认为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 } }
Copier après la connexion

神奇,第一层属性没有改变,但第二层却同步改变了,这是为什么呢?

因为 Object.assign()拷贝的是(可枚举)属性值。

假如源值是一个对象的引用,它仅仅会复制其引用值。MDN传送门

四、自己实现深浅拷贝

既然现有的方法无法实现深拷贝,不妨我们自己来实现一个吧~

4.1 浅拷贝

我们只需要将所有属性即其嵌套属性原封不动的复制给新变量一份即可,抛开现有的方法,我们应该怎么做呢?

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;}
Copier après la connexion

我们只需要将所有属性的引用拷贝一份即可~

4.2 深拷贝

相信大家在实现深拷贝的时候都会想到递归,同样是判断属性值,但如果当前类型为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;}
Copier après la connexion

我们用白话来解释一下deepCopy都做了什么

const obj = [1, { a: 1, b: { name: '余光'} } ];const resObj = deepCopy(obj);
Copier après la connexion
  • 读取 obj,创建 第一个newObj
    • 判断类型为 []
    • key为 0 (for in 以任意顺序遍历,我们假定按正常循序遍历)
    • 判断不是引用类型,直接复制
    • key为 1
    • 判断是引用类型
    • 进入递归,重新走了一遍刚才的流程,只不过读取的是obj[1]

另外请注意递归的方式虽然可以深拷贝,但是在性能上肯定不如浅拷贝,大家还是需要结合实际情况来选择。

写在最后

Sujet JavaScript 5 : Copie approfondie et superficielle

前端专项进阶系列的第五篇文章,希望它能对大家有所帮助,如果大家有什么建议,可以在评论区留言,能帮到自己和大家就是我最大的动力!

相关免费学习推荐: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!

Étiquettes associées:
source:csdn.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal