object js - Quel est le moyen le plus efficace de cloner en profondeur un objet en JavaScript?




element copier (25)

Quel est le moyen le plus efficace de cloner un objet JavaScript? J'ai vu obj = eval(uneval(o)); en cours d'utilisation, mais ce n'est pas standard et n'est supporté que par Firefox .

J'ai fait des choses comme obj = JSON.parse(JSON.stringify(o)); mais questionne l'efficacité.

J'ai également vu des fonctions de copie récursives présentant divers défauts.
Je suis surpris qu'aucune solution canonique n'existe.


Answers

Si vous l'utilisez, la bibliothèque Underscore.js a une méthode de clone .

var newObject = _.clone(oldObject);

Commander cette référence: http://jsben.ch/#/bWfk9

Dans mes tests précédents où la vitesse était une préoccupation majeure, j'ai trouvé

JSON.parse(JSON.stringify(obj))

être le moyen le plus rapide de cloner en profondeur un objet (il bat jQuery.extend avec un indicateur deep défini sur 10-20%).

jQuery.extend est assez rapide lorsque l'indicateur deep est défini sur false (clone superficiel). C'est une bonne option, car elle inclut une logique supplémentaire pour la validation de type et ne copie pas les propriétés indéfinies, etc., mais cela vous ralentira également un peu.

Si vous connaissez la structure des objets que vous essayez de cloner ou pouvez éviter les tableaux imbriqués profonds, vous pouvez écrire une boucle simple for (var i in obj) pour cloner votre objet tout en vérifiant hasOwnProperty. Elle sera beaucoup plus rapide que jQuery.

Enfin, si vous essayez de cloner une structure d'objet connue dans une boucle dynamique, vous pouvez obtenir BEAUCOUP PLUS DE PERFORMANCES en insérant simplement la procédure de clonage et en construisant manuellement l'objet.

Les moteurs de trace JavaScript sont particulièrement for..in à optimiser.La vérification de hasOwnProperty vous ralentira également. Clone manuel lorsque la vitesse est un impératif absolu.

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

Faites attention en utilisant la JSON.parse(JSON.stringify(obj)) sur les objets Date - JSON.stringify(new Date()) renvoie une représentation sous forme de chaîne de la date au format ISO, que JSON.parse() ne reconvertit pas. à un objet Date . Voir cette réponse pour plus de détails .

De plus, veuillez noter que, dans Chrome 65 au moins, le clonage natif n’est pas la solution. Selon JSPerf , effectuer un clonage natif en créant une nouvelle fonction est près de 800 fois plus lent que l’utilisation de JSON.stringify, qui est incroyablement rapide dans tous les domaines.


S'il n'y en avait pas, vous pourriez essayer:

function clone(obj) {
    if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
        return obj;

    if (obj instanceof Date)
        var temp = new obj.constructor(); //or new Date(obj);
    else
        var temp = obj.constructor();

    for (var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            obj['isActiveClone'] = null;
            temp[key] = clone(obj[key]);
            delete obj['isActiveClone'];
        }
    }
    return temp;
}

Pour les personnes qui souhaitent utiliser la JSON.parse(JSON.stringify(obj))version, mais sans perdre les objets Date, vous pouvez utiliser le deuxième argument de parsemethod pour convertir les chaînes en Date:

function clone(obj) {
  var regExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
  return JSON.parse(JSON.stringify(x), function(k, v) {
    if (typeof v === 'string' && regExp.test(v))
      return new Date(v);
    return v;
  });
}

Copie peu profonde sur un support ( ECMAScript 5ème édition ):

var origin = { foo : {} };
var copy = Object.keys(origin).reduce(function(c,k){c[k]=origin[k];return c;},{});

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

Et copie superficielle one-liner ( ECMAScript 6ème édition , 2015):

var origin = { foo : {} };
var copy = Object.assign({}, origin);

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

En supposant que vous n’ayez que des variables et pas de fonctions dans votre objet, vous pouvez simplement utiliser:

var newObject = JSON.parse(JSON.stringify(oldObject));

Lodash a une belle lodash.com/docs#cloneDeep :

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

Code:

// extends 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned
function extend(from, to)
{
    if (from == null || typeof from != "object") return from;
    if (from.constructor != Object && from.constructor != Array) return from;
    if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||
        from.constructor == String || from.constructor == Number || from.constructor == Boolean)
        return new from.constructor(from);

    to = to || new from.constructor();

    for (var name in from)
    {
        to[name] = typeof to[name] == "undefined" ? extend(from[name], null) : to[name];
    }

    return to;
}

Tester:

var obj =
{
    date: new Date(),
    func: function(q) { return 1 + q; },
    num: 123,
    text: "asdasd",
    array: [1, "asd"],
    regex: new RegExp(/aaa/i),
    subobj:
    {
        num: 234,
        text: "asdsaD"
    }
}

var clone = extend(obj);

Ce n'est généralement pas la solution la plus efficace, mais c'est ce dont j'ai besoin. Cas de test simples ci-dessous ...

function clone(obj, clones) {
    // Makes a deep copy of 'obj'. Handles cyclic structures by
    // tracking cloned obj's in the 'clones' parameter. Functions 
    // are included, but not cloned. Functions members are cloned.
    var new_obj,
        already_cloned,
        t = typeof obj,
        i = 0,
        l,
        pair; 

    clones = clones || [];

    if (obj === null) {
        return obj;
    }

    if (t === "object" || t === "function") {

        // check to see if we've already cloned obj
        for (i = 0, l = clones.length; i < l; i++) {
            pair = clones[i];
            if (pair[0] === obj) {
                already_cloned = pair[1];
                break;
            }
        }

        if (already_cloned) {
            return already_cloned; 
        } else {
            if (t === "object") { // create new object
                new_obj = new obj.constructor();
            } else { // Just use functions as is
                new_obj = obj;
            }

            clones.push([obj, new_obj]); // keep track of objects we've cloned

            for (key in obj) { // clone object members
                if (obj.hasOwnProperty(key)) {
                    new_obj[key] = clone(obj[key], clones);
                }
            }
        }
    }
    return new_obj || obj;
}

Test de matrice cyclique ...

a = []
a.push("b", "c", a)
aa = clone(a)
aa === a //=> false
aa[2] === a //=> false
aa[2] === a[2] //=> false
aa[2] === aa //=> true

Test de fonctionnalité...

f = new Function
f.a = a
ff = clone(f)
ff === f //=> true
ff.a === a //=> false

function clone(obj)
 { var clone = {};
   clone.prototype = obj.prototype;
   for (property in obj) clone[property] = obj[property];
   return clone;
 }

Je sais que c’est un vieux billet, mais j’ai pensé que cela pourrait être utile à la prochaine personne qui trébuche.

Tant que vous n'attribuez rien à un objet, il ne conserve aucune référence en mémoire. Donc, pour créer un objet que vous souhaitez partager avec d'autres objets, vous devez créer une fabrique de la manière suivante:

var a = function(){
    return {
        father:'zacharias'
    };
},
b = a(),
c = a();
c.father = 'johndoe';
alert(b.father);

var clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (var i in this) {
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        }
        else
        {
            newObj[i] = this[i];
        }
    }
    return newObj;
}; 

Object.defineProperty( Object.prototype, "clone", {value: clone, enumerable: false});

C'est ce que j'utilise:

function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(typeof(obj[i])=="object" && obj[i] != null)
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}

Copier en profondeur des objets en JavaScript (je pense le meilleur et le plus simple)

1. Utilisation de JSON.parse (JSON.stringify (objet));

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = JSON.parse(JSON.stringify(obj));
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

2.Utilisation de la méthode créée

function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(obj[i] != null &&  typeof(obj[i])=="object")
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = cloneObject(obj);
obj.b.c = 20;

console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

3. Utilisation du lien lodash de _.cloneDeep de Lo-Dashlodash

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

4. Utilisation de la méthode Object.assign ()

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

MAIS FAUX QUAND

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = Object.assign({}, obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// Note: Properties on the prototype chain and non-enumerable properties cannot be copied.

5.Utilisation du lien Underscore.js _.clone Underscore.js

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

MAIS FAUX QUAND

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// (Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated.)

Référence medium.com

JSBEN.CH Analyse comparative des performances Playground 1 ~ 3 http://jsben.ch/KVQLd


Il ne semble pas encore exister d'opérateur de clonage profond idéal pour les objets de type tableau. Comme l'illustre le code ci-dessous, le cloneur jQuery de John Resig transforme des tableaux de propriétés non numériques en objets qui ne sont pas des tableaux et le cloneur JSON de RegDwight supprime les propriétés non numériques. Les tests suivants illustrent ces points sur plusieurs navigateurs:

function jQueryClone(obj) {
   return jQuery.extend(true, {}, obj)
}

function JSONClone(obj) {
   return JSON.parse(JSON.stringify(obj))
}

var arrayLikeObj = [[1, "a", "b"], [2, "b", "a"]];
arrayLikeObj.names = ["m", "n", "o"];
var JSONCopy = JSONClone(arrayLikeObj);
var jQueryCopy = jQueryClone(arrayLikeObj);

alert("Is arrayLikeObj an array instance?" + (arrayLikeObj instanceof Array) +
      "\nIs the jQueryClone an array instance? " + (jQueryCopy instanceof Array) +
      "\nWhat are the arrayLikeObj names? " + arrayLikeObj.names +
      "\nAnd what are the JSONClone names? " + JSONCopy.names)

Le moyen efficace de cloner (et non de cloner en profondeur) un objet dans une ligne de code

Une méthode Object.assign fait partie de la norme ECMAScript 2015 (ES6) et fait exactement ce dont vous avez besoin.

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

La méthode Object.assign () est utilisée pour copier les valeurs de toutes les propriétés énumérables d'un ou de plusieurs objets source vers un objet cible.

Object.assign

Le polyfill pour supporter les navigateurs plus anciens:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

// obj target object, vals source object
var setVals = function (obj, vals) {
    if (obj && vals) {
        for (var x in vals) {
            if (vals.hasOwnProperty(x)) {
                if (obj[x] && typeof vals[x] === 'object') {
                    obj[x] = setVals(obj[x], vals[x]);
                } else {
                    obj[x] = vals[x];
                }
            }
        }
    }
    return obj;
};

Crockford suggère (et je préfère) d'utiliser cette fonction:

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

var newObject = object(oldObject);

C'est laconique, ça fonctionne comme prévu et vous n'avez pas besoin d'une bibliothèque.

MODIFIER:

Ceci est un polyfill pour Object.create, vous pouvez donc également l'utiliser.

var newObject = Object.create(oldObject);

Remarque: Si vous utilisez une partie de cela, vous pouvez avoir des problèmes avec certaines itérations qui utilisent hasOwnProperty. Parce que createcréer un nouvel objet vide qui hérite oldObject. Mais cela reste utile et pratique pour cloner des objets.

Par exemple si oldObject.a = 5;

newObject.a; // is 5

mais:

oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false

Clonage structuré

HTML5 définit un algorithme de clonage "structuré" interne pouvant créer des clones d'objets profonds. Il est toujours limité à certains types intégrés, mais en plus des quelques types pris en charge par JSON, il prend également en charge les dates, les régressions, les cartes, les ensembles, les blobs, les listes de fichiers, les images, les tableaux fragmentés, les tableaux typés, et probablement davantage à l'avenir. . Il préserve également les références dans les données clonées, ce qui lui permet de prendre en charge des structures cycliques et récursives susceptibles de générer des erreurs pour JSON.

Prise en charge directe dans les navigateurs: bientôt disponible? 🙂

Les navigateurs ne fournissent pas actuellement d’interface directe pour l’algorithme de clonage structuré, mais une fonction globale structuredClone() est en cours de discussion dans whatwg / html # 793 sur GitHub et pourrait être disponible sous peu! Tel que proposé actuellement, son utilisation dans la plupart des cas sera aussi simple que:

const clone = structuredClone(original);

Jusqu'à ce que cela soit livré, les implémentations de clones structurés des navigateurs ne sont exposées qu'indirectement.

Solution de contournement asynchrone: utilisable. 😕

La méthode la moins coûteuse pour créer un clone structuré avec des API existantes consiste à publier les données via un port d'un MessageChannels . L'autre port émettra un événement de message avec un clone structuré du .data attaché. Malheureusement, l’écoute de ces événements est nécessairement asynchrone et les alternatives synchrones sont moins pratiques.

class StructuredCloner {
  constructor() {
    this.pendingClones_ = new Map();
    this.nextKey_ = 0;

    const channel = new MessageChannel();
    this.inPort_ = channel.port1;
    this.outPort_ = channel.port2;

    this.outPort_.onmessage = ({data: {key, value}}) => {
      const resolve = this.pendingClones_.get(key);
      resolve(value);
      this.pendingClones_.delete(key);
    };
    this.outPort_.start();
  }

  cloneAsync(value) {
    return new Promise(resolve => {
      const key = this.nextKey_++;
      this.pendingClones_.set(key, resolve);
      this.inPort_.postMessage({key, value});
    });
  }
}

const structuredCloneAsync = window.structuredCloneAsync =
    StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);

Exemple d'utilisation:

const main = async () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = await structuredCloneAsync(original);

  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));

  console.log("Assertions complete.");
};

main();

Solutions de contournement synchrones: horrible! 🤢

Il n'y a pas de bonne option pour créer des clones structurés de manière synchrone. Voici quelques astuces peu pratiques à la place.

history.pushState() et history.replaceState() créent un clone structuré de leur premier argument et attribuent cette valeur à history.state . Vous pouvez l'utiliser pour créer un clone structuré de tout objet comme celui-ci:

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

Exemple d'utilisation:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

main();

Bien que synchrone, cela peut être extrêmement lent. Il entraîne tous les frais généraux associés à la manipulation de l'historique du navigateur. Si vous appelez cette méthode à plusieurs reprises, Chrome risque de ne plus répondre temporairement.

Le constructeur Notification crée un clone structuré de ses données associées. Il tente également d'afficher une notification du navigateur à l'utilisateur, mais cela échouera silencieusement sauf si vous avez demandé l'autorisation de notification. Si vous avez l'autorisation à d'autres fins, nous fermerons immédiatement la notification que nous avons créée.

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.onshow = n.close.bind(n);
  return n.data;
};

Exemple d'utilisation:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.close();
  return n.data;
};

main();


Juste parce que je n'ai pas vu AngularJS mentionné et pensé que les gens pourraient vouloir savoir ...

angular.copy fournit également une méthode de copie en profondeur des objets et des tableaux.


Copie profonde par performance: classé du meilleur au pire

  • Réaffectation "=" (tableaux de chaînes, tableaux de nombres - uniquement)
  • Slice (tableaux de chaînes, tableaux de nombres uniquement)
  • Concaténation (tableaux de chaînes, tableaux de nombres uniquement)
  • Fonction personnalisée: copie en boucle ou récursive
  • jQuery's $ .extend
  • JSON.parse (tableaux de chaînes, tableaux de nombres, tableaux d'objets - uniquement)
  • _.Clone de Underscore.js (tableaux de chaînes, tableaux de nombres uniquement)
  • _.CloneDeep de Lo-Dash

Copier en profondeur un tableau de chaînes ou de nombres (un niveau - pas de pointeurs de référence):

Lorsqu'un tableau contient des nombres et des chaînes, des fonctions telles que .slice (), .concat (), .splice (), l'opérateur d'attribution "=" et la fonction clone de Underscore.js; fera une copie profonde des éléments du tableau.

Où la réaffectation a la performance la plus rapide:

var arr1 = ['a', 'b', 'c'];
var arr2 = arr1;
arr1 = ['a', 'b', 'c'];

Et .slice () a de meilleures performances que .concat (), http://jsperf.com/duplicate-array-slice-vs-concat/3

var arr1 = ['a', 'b', 'c'];  // Becomes arr1 = ['a', 'b', 'c']
var arr2a = arr1.slice(0);   // Becomes arr2a = ['a', 'b', 'c'] - deep copy
var arr2b = arr1.concat();   // Becomes arr2b = ['a', 'b', 'c'] - deep copy

Copier en profondeur un tableau d’objets (deux niveaux ou plus - pointeurs de référence):

var arr1 = [{object:'a'}, {object:'b'}];

Ecrivez une fonction personnalisée (avec des performances plus rapides que $ .extend () ou JSON.parse):

function copy(o) {
   var out, v, key;
   out = Array.isArray(o) ? [] : {};
   for (key in o) {
       v = o[key];
       out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
   }
   return out;
}

copy(arr1);

Utilisez des fonctions utilitaires tierces:

$.extend(true, [], arr1); // Jquery Extend
JSON.parse(arr1);
_.cloneDeep(arr1); // Lo-dash

Où $ .extend de jQuery a de meilleures performances:


Remarque: Ceci est une réponse à une autre réponse, pas une réponse appropriée à cette question. Si vous souhaitez un clonage rapide d’objets, suivez les conseils de Corban dans sa réponse à cette question.

Je tiens à noter que la méthode .clone() dans jQuery ne clone que des éléments DOM. Pour cloner des objets JavaScript, vous feriez:

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

Plus d'informations peuvent être trouvées dans la documentation de jQuery .

Je tiens également à noter que la copie profonde est en réalité beaucoup plus intelligente que ce qui est présenté ci-dessus - elle permet d'éviter de nombreux pièges (en essayant d'étendre en profondeur un élément DOM, par exemple). Il est fréquemment utilisé dans jQuery core et dans les plug-ins pour un effet optimal.


Voici une méthode complète clone () permettant de cloner n'importe quel objet JavaScript. Il gère presque tous les cas:

function clone(src, deep) {

    var toString = Object.prototype.toString;
    if (!src && typeof src != "object") {
        // Any non-object (Boolean, String, Number), null, undefined, NaN
        return src;
    }

    // Honor native/custom clone methods
    if (src.clone && toString.call(src.clone) == "[object Function]") {
        return src.clone(deep);
    }

    // DOM elements
    if (src.nodeType && toString.call(src.cloneNode) == "[object Function]") {
        return src.cloneNode(deep);
    }

    // Date
    if (toString.call(src) == "[object Date]") {
        return new Date(src.getTime());
    }

    // RegExp
    if (toString.call(src) == "[object RegExp]") {
        return new RegExp(src);
    }

    // Function
    if (toString.call(src) == "[object Function]") {

        //Wrap in another method to make sure == is not true;
        //Note: Huge performance issue due to closures, comment this :)
        return (function(){
            src.apply(this, arguments);
        });
    }

    var ret, index;
    //Array
    if (toString.call(src) == "[object Array]") {
        //[].slice(0) would soft clone
        ret = src.slice();
        if (deep) {
            index = ret.length;
            while (index--) {
                ret[index] = clone(ret[index], true);
            }
        }
    }
    //Object
    else {
        ret = src.constructor ? new src.constructor() : {};
        for (var prop in src) {
            ret[prop] = deep
                ? clone(src[prop], true)
                : src[prop];
        }
    }
    return ret;
};

AngularJS

Eh bien, si vous utilisez angular, vous pouvez le faire aussi

var newObject = angular.copy(oldObject);

My understanding is that there are 3 scopes: global scope, available globally; local scope, available to an entire function regardless of blocks; and block scope, only available to the block, statement, or expression on which it was used. Global and local scope are indicated with the keyword 'var', either within a function or outside, and block scope is indicated with the keyword 'let'.

For those that believe there is only global and local scope, please explain why Mozilla would have an entire page describing the nuances of block scope in JS.

let





javascript object clone