Maison > Article > interface Web > Une compréhension approfondie de la copie superficielle et de la copie profonde en JavaScript
Le contenu de cet article porte sur une compréhension approfondie de la copie superficielle et de la copie profonde en JavaScript. Il a une certaine valeur de référence. Maintenant, je le partage avec vous. Les amis dans le besoin peuvent s'y référer<.>
Il existe des types de base en JS comme, Number
, String
et les objets sont comme ceci { nom : 'Larry', compétence : 'Node.js' }, les objets et les types de base sont le plus grand La différence réside dans la manière dont ils transmettent les valeurs. Le type de base de Boolean,
, il ne sera pas changé en a
b
var a = 25; var b = a; b = 18; console.log(a);//25 console.log(b);//18Mais l'objet est différent. l'objet est passé par valeur. Passer par valeur :
var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = obj1; obj2.b = 100; console.log(obj1); // { a: 10, b: 100, c: 30 } <-- b 被改到了 console.log(obj2); // { a: 10, b: 100, c: 30 }Copiez une copie de
et appelez-la obj1
, puis remplacez obj2,
par obj2.b
mais remplacez-la accidentellement par 100,
. car il s’agit fondamentalement du même objet. C’est ce qu’on appelle une copie superficielle. obj1.b,
var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c }; obj2.b = 100; console.log(obj1); // { a: 10, b: 20, c: 30 } <-- b 沒被改到 console.log(obj2); // { a: 10, b: 100, c: 30 }
obj1。
1 Copiez simplement la déclaration
<script type="text/javascript"> function simpleClone(initalObj) { var obj = {}; for ( var i in initalObj) { obj[i] = initalObj[i]; } return obj; } var obj = { a: "hello", b:{ a: "world", b: 21 }, c:["Bob", "Tom", "Jenny"], d:function() { alert("hello world"); } } var cloneObj = simpleClone(obj); console.log(cloneObj.b); console.log(cloneObj.c); console.log(cloneObj.d); cloneObj.b.a = "changed"; cloneObj.c = [1, 2, 3]; cloneObj.d = function() { alert("changed"); }; console.log(obj.b); console.log(obj.c); console.log(obj.d); </script>
.
2. Object.assign()
Oui Nouvelles fonctions. en ES6. La méthode Object.assign()<code>Object.assign
peut copier n'importe quel nombre de propriétés énumérables de l'objet source vers l'objet cible, puis renvoyer l'objet cible. Mais <code>Object.assign() effectue une copie superficielle. Ce qui est copié est la référence aux attributs de l'objet, pas l'objet lui-même. <code>Object.assign()
Object.assign(target, ...sources)Paramètres : target : objet cible.
sources : n'importe quel nombre d'objets sources.
Valeur de retour :
L'objet cible sera renvoyé.
var obj = { a: {a: "hello", b: 21} }; var initalObj = Object.assign({}, obj); initalObj.a.a = "changed"; console.log(obj.a.a); // "changed"Compatibilité : Remarque :
Object.assign()可以处理一层的深度拷贝,如下:
var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = Object.assign({}, obj1); obj2.b = 100; console.log(obj1); // { a: 10, b: 20, c: 30 } <-- 沒被改到 console.log(obj2); // { a: 10, b: 100, c: 30 }
1. Copie manuelle
Copier les propriétés d'un objet dans les propriétés d'un autre objetvar obj1 = { a: 10, b: 20, c: 30 }; var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c }; obj2.b = 100; console.log(obj1); // { a: 10, b: 20, c: 30 } <-- 沒被改到 console.log(obj2); // { a: 10, b: 100, c: 30 }Mais c'est très gênant, vous besoin d'un One se copie ; et cette nature ne peut pas être considérée comme Deep Copy, car il peut aussi y avoir des objets à l'intérieur de l'objet, comme dans la situation suivante :
var obj1 = { body: { a: 10 } }; var obj2 = { body: obj1.body }; obj2.body.a = 20; console.log(obj1); // { body: { a: 20 } } <-- 被改到了 console.log(obj2); // { body: { a: 20 } } console.log(obj1 === obj2); // false console.log(obj1.body === obj2.body); // trueBien que
et obj2 <code>obj1
sont des objets différents, mais ils partageront le même obj1.body<code>obj2
, <code>obj1.body
donc lorsque vous modifierez obj2.body.a<code>,
, l'ancien sera également être modifié. obj2.body.a
2. Si l'objet n'a qu'un seul calque, vous pouvez utiliser ce qui précède : Objet<strong>.<span class="token function">attribuer () function<code class=" language-js">Object<span class="token punctuation">.<span class="token function">assign()函数</span></span>
<code>Object.assign({}, obj1)obj1
<code>Object.assign({}, obj1)<code>obj2 signifie d'abord créer un objet vide {}, et puis attribuez obj1
Copiez tous les attributs dans obj2.b
, donc obj2<code>obj1。
aura la même apparence que
La modification de
à ce moment n'affectera pas <code>Object.assign
Object .assign<p> a le même effet que notre copie manuelle, il ne peut donc gérer que des objets avec une seule couche de profondeur, et il n'y a aucun moyen d'obtenir une véritable copie profonde. Cependant, vous pouvez envisager de l'utiliser s'il n'y a qu'un seul calque d'objets à copier. <strong><span class="token punctuation"></span></strong></p>3. Convertissez <p> en JSON, puis inversez <span class="token punctuation"><code>JSON.stringify
JSON.parse
Utilisez JSON.stringify
pour convertir l'objet Convertissez-le en chaîne, puis utilisez JSON.parse<pre class="brush:php;toolbar:false;">var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1);
// { body: { a: 10 } } <-- 沒被改到
console.log(obj2);
// { body: { a: 20 } }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
// false</pre> pour convertir la chaîne en un nouvel objet. <p><span style="line-height: 1.5;"></span><br>C'est du vrai Deep Copy, </p>Cette méthode est simple et facile à utiliser. <p></p>
<p><code>Number, String, Boolean, Array, 扁平对象
Mais cette méthode présente également de nombreux inconvénients, par exemple, elle supprimera le constructeur de l'objet. C'est-à-dire qu'après une copie profonde, quel que soit le constructeur d'origine de l'objet, il deviendra Objet après une copie profonde.
Les seuls objets que cette méthode peut gérer correctement sont les Number, String, Boolean, Array et les objets plats<code>JSON
, c'est-à-dire les structures de données qui peuvent être directement représentées par json. Les objets RegExp ne peuvent pas être copiés en profondeur de cette manière. function
JSON。
En d'autres termes, seuls les objets pouvant être convertis au format JSON
function ne peut pas être converti en <code>JSON. . <pre class="brush:php;toolbar:false;">var obj1 = { fun: function(){ console.log(123) } };
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(typeof obj1.fun);
// &#39;function&#39;
console.log(typeof obj2.fun);
// &#39;undefined&#39; <-- 没复制</pre><p>要复制的<code>function
会直接消失,所以这个方法只能用在单纯只有数据的对象。
4、递归拷贝
function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { if (typeof initalObj[i] === 'object') { obj[i] = (initalObj[i].constructor === Array) ? [] : {}; arguments.callee(initalObj[i], obj[i]); } else { obj[i] = initalObj[i]; } } return obj; }var str = {};var obj = { a: {a: "hello", b: 21} }; deepClone(obj, str); console.log(str.a);
上述代码确实可以实现深拷贝。但是当遇到两个互相引用的对象,会出现死循环的情况。
为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。
改进版代码如下:
function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况 if(prop === obj) { continue; } if (typeof prop === 'object') { obj[i] = (prop.constructor === Array) ? [] : {}; arguments.callee(prop, obj[i]); } else { obj[i] = prop; } } return obj; }var str = {};var obj = { a: {a: "hello", b: 21} }; deepClone(obj, str); console.log(str.a);
5、使用Object.create()方法
直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。
function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况 if(prop === obj) { continue; } if (typeof prop === 'object') { obj[i] = (prop.constructor === Array) ? [] : Object.create(prop); } else { obj[i] = prop; } } return obj; }
6、jquery
jquery 有提供一个$.extend
可以用来做 Deep Copy。
var $ = require('jquery');var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] };var obj2 = $.extend(true, {}, obj1); console.log(obj1.b.f === obj2.b.f);// false
7、lodash
另外一个很热门的函数库lodash,也有提供_.cloneDeep
用来做 Deep Copy。
var _ = require('lodash');var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] };var obj2 = _.cloneDeep(obj1); console.log(obj1.b.f === obj2.b.f);// false
这个性能还不错,使用起来也很简单。
参考:
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!