Maison >interface Web >js tutoriel >Copie profonde d'objets en JavaScript

Copie profonde d'objets en JavaScript

黄舟
黄舟original
2017-02-21 12:00:331144parcourir



En JavaScript, il est courant de copier des objets. Mais une simple instruction copy ne peut faire qu'une copie superficielle d'un objet, c'est-à-dire qu'une référence est copiée, et non l'objet auquel elle fait référence. Le plus souvent, nous souhaitons faire une copie complète de l'objet pour éviter que l'objet d'origine ne soit modifié involontairement.

La différence entre la copie profonde et la copie superficielle d'un objet est la suivante :

  • Copie superficielle : copie uniquement la référence de l'objet, pas l'objet lui-même ;

  • Copie approfondie : copiez tous les objets référencés par l'objet copié.

1. Implémentation de la copie superficielle

La méthode d'implémentation de la copie superficielle est relativement simple, à condition d'utiliser une simple instruction de copie.

1.1 Méthode 1 : Instruction de copie simple

/* ================ 浅拷贝 ================ */
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); // {a: "world", b: 21}
console.log(cloneObj.c); // ["Bob", "Tom", "Jenny"]
console.log(cloneObj.d); // function() { alert("hello world"); }

// 修改拷贝后的对象
cloneObj.b.a = "changed";
cloneObj.c = [1, 2, 3];
cloneObj.d = function() { alert("changed"); };

console.log(obj.b); // {a: "changed", b: 21} // // 原对象所引用的对象被修改了

console.log(obj.c); // ["Bob", "Tom", "Jenny"] // 原对象所引用的对象未被修改
console.log(obj.d); // function() { alert("hello world"); } // 原对象所引用的函数未被修改

1.2 Méthode 2 : Object.assign()

La méthode Object.assign() peut attribuer n'importe quel Plusieurs propriétés énumérables de l'objet source sont copiées dans l'objet cible, puis l'objet cible est renvoyé. Cependant, Object.assign() effectue une copie superficielle, en copiant les références aux propriétés de l'objet, et non à l'objet lui-même.

var obj = { a: {a: "hello", b: 21} };

var initalObj = Object.assign({}, obj);

initalObj.a.a = "changed";

console.log(obj.a.a); // "changed"

2. Implémentation de la copie profonde

Il existe de nombreuses façons d'implémenter la copie profonde, y compris la méthode JSON.parse() la plus simple et la méthode de copie récursive couramment utilisée, et dans Méthode ES5 Object.create().

2.1 Méthode 1 : Utilisez la méthode JSON.parse()

Il existe de nombreuses façons d'implémenter la copie approfondie. Par exemple, la méthode la plus simple consiste à utiliser JSON.parse() :

.
/* ================ 深拷贝 ================ */
function deepClone(initalObj) {
    var obj = {};
    try {
        obj = JSON.parse(JSON.stringify(initalObj));
    }
    return obj;
}
/* ================ 客户端调用 ================ */
var obj = {
    a: {
        a: "world",
        b: 21
    }
}
var cloneObj = deepClone(obj);
cloneObj.a.a = "changed";

console.log(obj.a.a); // "world"

Cette méthode est simple et facile à utiliser.

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 objets Number, String, Boolean, Array et plats, 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.

2.2 Méthode 2 : Copie récursive

Le code est le suivant :

/* ================ 深拷贝 ================ */
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;
}

Le code ci-dessus peut en effet réaliser une copie profonde. Mais lorsque vous rencontrez deux objets qui se référencent l’un à l’autre, une boucle infinie se produit.

Afin d'éviter une boucle infinie provoquée par des objets se référençant les uns aux autres, vous devez déterminer si les objets se font référence les uns aux autres pendant le parcours, et si c'est le cas, quitter la boucle.

Le code amélioré est le suivant :

/* ================ 深拷贝 ================ */
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;
}

2.3 Méthode 3 : Utilisez la méthode Object.create()

Utilisez var newObj = Object.create(oldObj) directement, vous pouvez obtenir l'effet de copie complète.

/* ================ 深拷贝 ================ */
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;
}

3. Référence : Implémentation de la méthode jQuery.extend()

jQuery.extend() de jQuery.js implémente également la copie approfondie des objets. Le code officiel est affiché ci-dessous pour référence.

Adresse du lien officiel : http://www.php.cn/.

jQuery.extend = jQuery.fn.extend = function() {
    var options, name, src, copy, copyIsArray, 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&#39;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&#39;t bring in undefined values
                } else if ( copy !== undefined ) {
                    target[ name ] = copy;
                }
            }
        }
    }

    // Return the modified object
    return target;
};


Ce qui précède est le contenu de la copie profonde d'objets en JavaScript. Pour plus de contenu connexe, veuillez faire attention au contenu. Site Web chinois PHP (www.php.cn) !






Déclaration:
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