Maison  >  Article  >  interface Web  >  Introduction détaillée à la copie profonde d'objets en JavaScript

Introduction détaillée à la copie profonde d'objets en JavaScript

黄舟
黄舟original
2017-03-03 15:07:071407parcourir

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 : la méthode Object.assign()

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

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

la plus simple, la méthode de copie récursive couramment utilisée et le Méthode. JSON.parse()Object.create()2.1 Méthode 1 : utilisez la méthode

JSON.parse() Il existe de nombreuses façons de mettre en œuvre la copie approfondie. Par exemple, la méthode la plus simple est d'utiliser

 :

JSON.parse().

/* ================ 深拷贝 ================ */
function deepClone(initalObj) {
    var obj = {};
    try {
        obj = JSON.parse(JSON.stringify(initalObj));
    }
    return obj;
}
Cette méthode est simple et facile à utiliser.
/* ================ 客户端调用 ================ */
var obj = {
    a: {
        a: "world",
        b: 21
    }
}
var cloneObj = deepClone(obj);
cloneObj.a.a = "changed";

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

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

, 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.

Number, String, Boolean, Array, 扁平对象2.2 Méthode 2 : Copie récursive

Le code est le suivant :

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

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 :

2.3 Méthode 3 : Utilisez la méthode Object.create()
/* ================ 深拷贝 ================ */
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;
}

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

3. Référence : Implémentation de la méthode jQuery.extend()
/* ================ 深拷贝 ================ */
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;
}

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 : https://github.com/jquery/jquery/blob/master/src/core.js.

Ce qui précède est une introduction détaillée à la copie profonde d'objets en JavaScript. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (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;
};


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