Heim  >  Artikel  >  Web-Frontend  >  Tiefe Kopie von Objekten in JavaScript

Tiefe Kopie von Objekten in JavaScript

黄舟
黄舟Original
2016-12-14 09:59:411107Durchsuche

Der Unterschied zwischen tiefer Kopie und flacher Kopie eines Objekts ist wie folgt:

Flache Kopie: kopiert nur die Referenz des Objekts, nicht das Objekt selbst.
Tiefe Kopie: kopiert alle Objekte vom kopierten Objekt referenziert wird. Kopieren Sie es erneut.

1. Implementierung einer flachen Kopie

Die Implementierungsmethode einer flachen Kopie ist relativ einfach, solange eine einfache Kopieranweisung verwendet wird.

1.1 Methode 1: Einfache Kopiererklärung

/* ================ 浅拷贝 ================ */
function simpleClone(initalObj) {
    var obj = {};
    for ( var i in initalObj) {
        obj[i] = initalObj[i];
    }
    return obj;
}

Kundenanruf

/* ================ 客户端调用 ================ */
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 Methode 2: Object.assign()

Die Methode Object.assign() kann eine beliebige Anzahl der eigenen aufzählbaren Eigenschaften des Quellobjekts in das Zielobjekt kopieren und dann das Zielobjekt zurückgeben. Aber Object.assign() Es wird eine flache Kopie durchgeführt, und was kopiert wird, ist der Verweis auf die Eigenschaften des Objekts, nicht das Objekt selbst.

 
var obj = { a: {a: "hello", b: 21} }; 
var initalObj = Object.assign({}, obj); 
initalObj.a.a = "changed"; 
console.log(obj.a.a); // "changed"

2. Implementierung von Deep Copy

Es gibt viele Möglichkeiten, Deep Copy zu implementieren, einschließlich der einfachsten JSON.parse()-Methode und der häufig verwendeten rekursiven Kopiermethode ES5 Object.create()-Methode.

2.1 Methode 1: Verwenden Sie die JSON.parse()-Methode

Es gibt viele Möglichkeiten, Deep Copy zu implementieren. Die einfachste Möglichkeit ist beispielsweise die Verwendung von 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"

Diese Methode ist einfach und leicht anzuwenden.

Aber diese Methode hat auch viele Nachteile, zum Beispiel wird der Konstruktor des Objekts verworfen. Das heißt, nach dem tiefen Kopieren wird das Objekt unabhängig vom ursprünglichen Konstruktor des Objekts nach dem tiefen Kopieren zum Objekt.

Die einzigen Objekte, die diese Methode korrekt verarbeiten kann, sind Number-, String-, Boolean-, Array- und flache Objekte, also solche, die von JSON verarbeitet werden können Eine direkt dargestellte Datenstruktur. RegExp-Objekte können auf diese Weise nicht tief kopiert werden.

2.2 Methode 2: Rekursives Kopieren

Der Code lautet wie folgt:

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

Der obige Code kann tatsächlich eine tiefe Kopie erreichen. Wenn man jedoch auf zwei Objekte stößt, die aufeinander verweisen, entsteht eine Endlosschleife.

Um eine Endlosschleife zu vermeiden, die dadurch verursacht wird, dass Objekte aufeinander verweisen, sollten Sie beim Durchlaufen feststellen, ob Objekte aufeinander verweisen, und wenn ja, die Schleife verlassen.

Der verbesserte Code lautet wie folgt:

/* ================ 深拷贝 ================ */
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 Methode 3: Verwenden Sie die Object.create()-Methode

Verwenden Sie var newObj direkt = Object.create(oldObj) kann den Effekt einer tiefen Kopie erzielen.

/* ================ 深拷贝 ================ */
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. Referenz: Implementierung der jQuery.extend()-Methode

jQuery.extend() von jQuery.js implementiert auch eine tiefe Kopie von Objekten. Der offizielle Code wird unten als Referenz veröffentlicht.

Offizielle Linkadresse: https://github.com/jquery/jquery/blob/master/src/core.js.

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;
};

Dieser Artikel stellt hauptsächlich den Inhalt von js zum Thema Deep Copy vor. Weitere Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn). ) Artikel!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn