J'ai un gros objet avec beaucoup de données. Et je veux cloner ceci dans une autre variable. Quand je définis un paramètre de l'instance B a le même résultat dans l'objet d'origine:
var obj = {a: 25, b: 50, c: 75};
var A = obj;
var B = obj;
A.a = 30;
B.a = 40;
alert(obj.a + " " + A.a + " " + B.a); // 40 40 40
Ma sortie devrait être 25 30 40. Des idées?
EDIT
Merci tout le monde. Je change le code de dystroy et voici mon résultat:
Object.prototype.clone = Array.prototype.clone = function()
{
if (Object.prototype.toString.call(this) === '[object Array]')
{
var clone = [];
for (var i=0; i<this.length; i++)
clone[i] = this[i].clone();
return clone;
}
else if (typeof(this)=="object")
{
var clone = {};
for (var prop in this)
if (this.hasOwnProperty(prop))
clone[prop] = this[prop].clone();
return clone;
}
else
return this;
}
var obj = {a: 25, b: 50, c: 75};
var A = obj.clone();
var B = obj.clone();
A.a = 30;
B.a = 40;
alert(obj.a + " " + A.a + " " + B.a);
var arr = [25, 50, 75];
var C = arr.clone();
var D = arr.clone();
C[0] = 30;
D[0] = 40;
alert(arr[0] + " " + C[0] + " " + D[0]);
Si vous utilisez une instruction =
pour attribuer une valeur à un var
avec un objet du côté droit, javascript ne copie pas, mais référence l'objet.
Vous pouvez utiliser la méthode clone
de lodash
var obj = {a: 25, b: 50, c: 75};
var A = _.clone(obj);
Ou la méthode cloneDeep
de lodash si votre objet a plusieurs niveaux d'objet
var obj = {a: 25, b: {a: 1, b: 2}, c: 75};
var A = _.cloneDeep(obj);
Ou la méthode merge
de lodash si vous voulez étendre l'objet source
var obj = {a: 25, b: {a: 1, b: 2}, c: 75};
var A = _.merge({}, obj, {newkey: "newvalue"});
Ou vous pouvez utiliser la méthode jQuerys extend
:
var obj = {a: 25, b: 50, c: 75};
var A = $.extend(true,{},obj);
Voici le code source de la méthode extend de jQuery 1.11:
jQuery.extend = jQuery.fn.extend = function() {
var src, copyIsArray, copy, name, options, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
Bien que cela ne soit pas un clonage, un moyen simple d'obtenir votre résultat consiste à utiliser l'objet d'origine comme prototype d'un nouvel objet.
Vous pouvez le faire en utilisant Object.create
:
var obj = {a: 25, b: 50, c: 75};
var A = Object.create(obj);
var B = Object.create(obj);
A.a = 30;
B.a = 40;
alert(obj.a + " " + A.a + " " + B.a); // 25 30 40
Cela crée un nouvel objet dans A
et B
qui hérite de obj
. Cela signifie que vous pouvez ajouter des propriétés sans affecter l'original.
Pour prendre en charge les implémentations traditionnelles, vous pouvez créer un shim (partiel) qui fonctionnera pour cette tâche simple.
if (!Object.create)
Object.create = function(proto) {
function F(){}
F.prototype = proto;
return new F;
}
Il n'émule pas toutes les fonctionnalités de Object.create
, mais il convient à vos besoins ici.
Vous pouvez définir une fonction de clonage.
J'utilise celui-ci:
function goclone(source) {
if (Object.prototype.toString.call(source) === '[object Array]') {
var clone = [];
for (var i=0; i<source.length; i++) {
clone[i] = goclone(source[i]);
}
return clone;
} else if (typeof(source)=="object") {
var clone = {};
for (var prop in source) {
if (source.hasOwnProperty(prop)) {
clone[prop] = goclone(source[prop]);
}
}
return clone;
} else {
return source;
}
}
var B = goclone(A);
Il ne copie pas le prototype, les fonctions, etc. Mais vous devriez l'adapter (et peut-être le simplifier) à vos propres besoins.
A
et B
référencent le même objet. A.a
et B.a
référencent donc la même propriété du même objet.
Voici une fonction "copie" qui peut faire le travail, il peut faire des clones superficiels et profonds. Notez les mises en garde. Il copie toutes les propriétés énumérables d'un objet (propriétés non héritées), y compris celles avec des valeurs de Falsey (je ne comprends pas pourquoi les autres approches les ignorent), il ne copie pas non plus les propriétés inexistantes des tableaux épars.
Il n’existe pas de fonction générale de copie ou de clonage car il existe de nombreuses idées différentes sur ce que doit faire une copie ou un clone dans tous les cas. La plupart excluent les objets Host, ou autre chose que Objects ou Arrays. Celui-ci copie également les primitives. Que devrait-il arriver avec les fonctions?
Regardez donc ce qui suit, c'est une approche légèrement différente des autres.
/* Only works for native objects, Host objects are not
** included. Copies Objects, Arrays, Functions and primitives.
** Any other type of object (Number, String, etc.) will likely give
** unexpected results, e.g. copy(new Number(5)) ==> 0 since the value
** is stored in a non-enumerable property.
**
** Expects that objects have a properly set *constructor* property.
*/
function copy(source, deep) {
var o, prop, type;
if (typeof source != 'object' || source === null) {
// What do to with functions, throw an error?
o = source;
return o;
}
o = new source.constructor();
for (prop in source) {
if (source.hasOwnProperty(prop)) {
type = typeof source[prop];
if (deep && type == 'object' && source[prop] !== null) {
o[prop] = copy(source[prop]);
} else {
o[prop] = source[prop];
}
}
}
return o;
}