Wie klonen Sie ein Array von Objekten mit Unterstrich?

Lesezeit: 6 Minuten
#!/usr/bin/env node
var _ = require('underscore');
var a = [{f: 1}, {f:5}, {f:10}];
var b = _.clone(a);
b[1].f = 55;
console.log(JSON.stringify(a));

Das führt zu:

[{"f":1},{"f":55},{"f":10}]

Clone scheint nicht zu funktionieren! Also habe ich RTFM und sehe das:

http://underscorejs.org/#clone

Erstellen Sie einen flach kopierten Klon des Objekts. Alle verschachtelten Objekte oder Arrays werden als Referenz kopiert, nicht dupliziert.

So _.clone ist ziemlich nutzlos. Gibt es eine Möglichkeit, das Array von Objekten tatsächlich zu kopieren?

  • Es gab eine Pull-Anforderung für Deep Copy, die abgelehnt wurde: github.com/jashkenas/underscore/pull/595 Lo-Dash hat CloneDeep

    – escarello

    8. Januar 2014 um 18:03 Uhr

  • lol Mir ist gerade das Wortspiel mit dem Unterstrich aufgefallen. Niedriger Strich.

    – Jess

    8. Januar 2014 um 19:09 Uhr

  • Unterstrich vs. Lodash: stackoverflow.com/questions/13789618/…

    – Jess

    8. Januar 2014 um 19:20 Uhr

Benutzer-Avatar
Jess

Nun, es gibt einen Trick! Wenn Klon verschachtelte Objekte nicht “klont”, können Sie dies erzwingen, indem Sie jedes Objekt innerhalb eines Map-Aufrufs explizit klonen! So was:

#!/usr/bin/env node
var _ = require('underscore');
var a = [{f: 1}, {f:5}, {f:10}];
var b = _.map(a, _.clone);       // <----
b[1].f = 55;
console.log(JSON.stringify(a));

Drucke:

[{"f":1},{"f":5},{"f":10}]

Yay! a ist unverändert! Ich kann jetzt bearbeiten b nach meinem Geschmack!

  • Seien Sie jedoch vorsichtig. Das funktioniert natürlich nur zwei Ebenen tief. nicht für Arrays oder Objekte, die noch mehr verschachtelt sind als dieses Beispiel.

    – Simon Zyx

    12. Februar 2015 um 20:31 Uhr

  • Außerdem klont Underscore konstruktionsbedingt RegExp- oder Date-Werte nicht richtig

    – Mark K. Cowan

    13. Mai 2015 um 8:22 Uhr

  • Jeder, der hier nachschaut, sollte meine Antwort unten sehen.

    – gdibble

    31. Januar 2017 um 6:27 Uhr

Eine andere Lösung extrahiert aus der Ausgabe auf Github das funktioniert mit jeder Ebene verschachtelter Daten und erfordert keinen Unterstrich:

JSON.parse(JSON.stringify(obj))

  • Dies funktioniert, es sei denn, das Objekt hat einen Zyklus, in diesem Fall JSON.stringify wirft einen Fehler. Was im Original nicht der Fall ist, aber dennoch ein interessanter Sachverhalt ist. a = {simple: 'thing'}; a.cycle = a ; JSON.stringify(a).

    – Mcdave

    15. Oktober 2015 um 7:07 Uhr


  • Beachten Sie auch, dass diese Lösung nur für Objekte mit einfachen Typen funktioniert. Zum Beispiel, wenn Sie Objekt haben Date oder Regex Instanzen werden sie zu Strings serialisiert. Nicht das Ende der Welt, aber Sie müssen damit umgehen, wenn Sie dies verwenden und erwarten Date Instanzen.

    – cayleyh

    24. Dezember 2015 um 19:33 Uhr


  • Und wenn Sie denken, dass jemand versuchen könnte, zu füttern undefined dazu wirst du wollen JSON.parse(JSON.stringify(obj) || null) andernfalls wird ein Fehler ausgegeben.

    – Ian Mackinnon

    29. Juni 2016 um 16:19 Uhr

  • Zusammen mit dem, was @cayleyh erwähnt hat, wird dies fallen functions insgesamt.

    – Marko Gresak

    2. August 2016 um 15:10 Uhr

FWIW, Lodash hat a KlonDeep Funktion:

Diese Methode ist wie _.clone, außer dass sie den Wert rekursiv klont.

  • Bei Schlüsseln mit undefinierten Werten verhält es sich jedoch anders. Also etwas, dessen man sich bewusst sein sollte. Klonen {a: 1, b: undefined} with lodash behält die undefinierten, aber die parse/stringify-Version entfernt sie.

    – Daniel

    29. Januar 2021 um 21:01 Uhr

Benutzer-Avatar
gdibble

API-Referenz unterstreichen:

_.toArray(list) Erstellt ein echtes Array aus der Liste (alles, über das iteriert werden kann). Nützlich zum Transmutieren des arguments-Objekts.

… oder in diesem Fall Klonen eine Anordnung. Versuche dies:

var _ = require('underscore');
var array1 =  [{a:{b:{c:1}}},{b:{c:{a:2}}},{c:{a:{b:3}}}];
var array2 = _.toArray(array1);
console.log(array1 === array2); --> false
console.log(array1[0] === array2[0]); --> true

Das Folgende ist ein Nachtrag, den ich nach Steves Kommentar unter -thx erstellt habe

Ein Vanilla JS (oder mit _.clone wenn gewünscht) Rekursiver Helfer für Deep Cloning:

function clone(thing, opts) {
    var newObject = {};
    if (thing instanceof Array) {
        return thing.map(function (i) { return clone(i, opts); });
    } else if (thing instanceof Date) {
        return new Date(thing);
    } else if (thing instanceof RegExp) {
        return new RegExp(thing);
    } else if (thing instanceof Function) {
        return opts && opts.newFns ?
                   new Function('return ' + thing.toString())() :
                   thing;
    } else if (thing instanceof Object) {
        Object.keys(thing).forEach(function (key) {
            newObject[key] = clone(thing[key], opts);
        });
        return newObject;
    } else if ([ undefined, null ].indexOf(thing) > -1) {
        return thing;
    } else {
        if (thing.constructor.name === 'Symbol') {
            return Symbol(thing.toString()
                       .replace(/^Symbol\(/, '')
                       .slice(0, -1));
        }
        // return _.clone(thing);  // If you must use _ ;)
        return thing.__proto__.constructor(thing);
    }
}

var a = {
    a: undefined,
    b: null,
    c: 'a',
    d: 0,
    e: Symbol('a'),
    f: {},
    g: { a:1 },
    h: [],
    i: [ { a:2 }, { a:3 } ],
    j: [ 1, 2 ],
    k: function (a) { return a; },
    l: /[a-z]/g,
    z: [ {
        a: undefined,
        b: null,
        c: 'b',
        d: 1,
        e: Symbol(1),
        f: {},
        g: { b:2 },
        h: { c:{ c:3 } },
        i: { a:Symbol('b') },
        j: { a:undefined, b:null },
        k: [],
        l: [ 1, [ 1, 2 ], [ [ 1, 2, 3 ] ] ],
        m: function (a) { return !a; },
        n: { a:function (a) { return !!a; } },
        o: /(a|b)/i
       } ]
};
var b = clone(a);
var c = clone(a, { newFns:true });


/* Results - value beneath each for reference:

a.a === b.a --> true
undefined

a.b === b.b --> true
null

a.c === b.c --> true
'a'

a.d === b.d --> true
0

a.e === b.e --> false
Symbol(a)

a.f === b.f --> false
{}

a.g === b.g --> false
{ a:1 }

a.h === b.h --> false
[]

a.i === b.i --> false
[ { a:2 }, { a:3 } ]

a.i[0] === b.i[0] --> false
{ a:2 }

a.i[0].a === b.i[0].a --> true
2

a.j === b.j --> false
[ 1, 2 ]

a.k === b.k --> true
a.k === c.k --> false
function (a) { return a; }

a.l === b.l --> false
/[a-z]/g

a.z === b.z --> false
[Object]

a.z[0].a === b.z[0].a --> true
undefined

a.z[0].b === b.z[0].b --> true
null

a.z[0].c === b.z[0].c --> true
'b'

a.z[0].d === b.z[0].d --> true
1

a.z[0].e === b.z[0].e --> 
false
Symbol(1)

a.z[0].f === b.z[0].f --> false
{}

a.z[0].g === b.z[0].g -- > false
{ b:2 }

a.z[0].g.b === b.z[0].g.b --> true
2

a.z[0].h === b.z[0].h --> false
{ c:{ c:3 } }

a.z[0].h.c === b.z[0].h.c --> false
{ c:3 }

a.z[0].h.c.c === b.z[0].h.c.c --> true
3

a.z[0].i === b.z[0].i --> false
{ a:Symbol(b) }

a.z[0].i.a === b.z[0].i.a --> false
Symbol(b)

a.z[0].j === b.z[0].j --> false
{ a:undefined, b:null }

a.z[0].j.a === b.z[0].j.a --> true
undefined

a.z[0].k === b.z[0].k --> false
[]

a.z[0].l === b.z[0].l --> false
[ 1, [ 1, 2 ], [ [ 1, 2, 3 ] ] ]

a.z[0].l[1] === b.z[0].l[1] --> false
[ 1, 2 ]

a.z[0].l[1][1] === b.z[0].l[1][1] --> true
2

a.z[0].m === b.z[0].m --> true
a.z[0].m === c.z[0].m --> false
function (a) { return !a; }

a.z[0].n === b.z[0].n --> false
{ a:function (a) { return !!a; } }

a.z[0].n.a === b.z[0].n.a --> true
a.z[0].n.a === c.z[0].n.a --> false
function (a) { return !!a; }

a.z[0].o === b.z[0].o --> false
/(a|b)/i

*/

1145580cookie-checkWie klonen Sie ein Array von Objekten mit Unterstrich?

Wie klonen Sie ein Array von Objekten mit Unterstrich?

Lesezeit: 6 Minuten
#!/usr/bin/env node
var _ = require('underscore');
var a = [{f: 1}, {f:5}, {f:10}];
var b = _.clone(a);
b[1].f = 55;
console.log(JSON.stringify(a));

Das führt zu:

[{"f":1},{"f":55},{"f":10}]

Clone scheint nicht zu funktionieren! Also habe ich RTFM und sehe das:

http://underscorejs.org/#clone

Erstellen Sie einen flach kopierten Klon des Objekts. Alle verschachtelten Objekte oder Arrays werden als Referenz kopiert, nicht dupliziert.

So _.clone ist ziemlich nutzlos. Gibt es eine Möglichkeit, das Array von Objekten tatsächlich zu kopieren?

  • Es gab eine Pull-Anforderung für Deep Copy, die abgelehnt wurde: github.com/jashkenas/underscore/pull/595 Lo-Dash hat CloneDeep

    – escarello

    8. Januar 2014 um 18:03 Uhr

  • lol Mir ist gerade das Wortspiel mit dem Unterstrich aufgefallen. Niedriger Strich.

    – Jess

    8. Januar 2014 um 19:09 Uhr

  • Unterstrich vs. Lodash: stackoverflow.com/questions/13789618/…

    – Jess

    8. Januar 2014 um 19:20 Uhr

Benutzer-Avatar
Jess

Nun, es gibt einen Trick! Wenn Klon verschachtelte Objekte nicht “klont”, können Sie dies erzwingen, indem Sie jedes Objekt innerhalb eines Map-Aufrufs explizit klonen! So was:

#!/usr/bin/env node
var _ = require('underscore');
var a = [{f: 1}, {f:5}, {f:10}];
var b = _.map(a, _.clone);       // <----
b[1].f = 55;
console.log(JSON.stringify(a));

Drucke:

[{"f":1},{"f":5},{"f":10}]

Yay! a ist unverändert! Ich kann jetzt bearbeiten b nach meinem Geschmack!

  • Seien Sie jedoch vorsichtig. Das funktioniert natürlich nur zwei Ebenen tief. nicht für Arrays oder Objekte, die noch mehr verschachtelt sind als dieses Beispiel.

    – Simon Zyx

    12. Februar 2015 um 20:31 Uhr

  • Außerdem klont Underscore konstruktionsbedingt RegExp- oder Date-Werte nicht richtig

    – Mark K. Cowan

    13. Mai 2015 um 8:22 Uhr

  • Jeder, der hier nachschaut, sollte meine Antwort unten sehen.

    – gdibble

    31. Januar 2017 um 6:27 Uhr

Eine andere Lösung extrahiert aus der Ausgabe auf Github das funktioniert mit jeder Ebene verschachtelter Daten und erfordert keinen Unterstrich:

JSON.parse(JSON.stringify(obj))

  • Dies funktioniert, es sei denn, das Objekt hat einen Zyklus, in diesem Fall JSON.stringify wirft einen Fehler. Was im Original nicht der Fall ist, aber dennoch ein interessanter Sachverhalt ist. a = {simple: 'thing'}; a.cycle = a ; JSON.stringify(a).

    – Mcdave

    15. Oktober 2015 um 7:07 Uhr


  • Beachten Sie auch, dass diese Lösung nur für Objekte mit einfachen Typen funktioniert. Zum Beispiel, wenn Sie Objekt haben Date oder Regex Instanzen werden sie zu Strings serialisiert. Nicht das Ende der Welt, aber Sie müssen damit umgehen, wenn Sie dies verwenden und erwarten Date Instanzen.

    – cayleyh

    24. Dezember 2015 um 19:33 Uhr


  • Und wenn Sie denken, dass jemand versuchen könnte, zu füttern undefined dazu wirst du wollen JSON.parse(JSON.stringify(obj) || null) andernfalls wird ein Fehler ausgegeben.

    – Ian Mackinnon

    29. Juni 2016 um 16:19 Uhr

  • Zusammen mit dem, was @cayleyh erwähnt hat, wird dies fallen functions insgesamt.

    – Marko Gresak

    2. August 2016 um 15:10 Uhr

FWIW, Lodash hat a KlonDeep Funktion:

Diese Methode ist wie _.clone, außer dass sie den Wert rekursiv klont.

  • Bei Schlüsseln mit undefinierten Werten verhält es sich jedoch anders. Also etwas, dessen man sich bewusst sein sollte. Klonen {a: 1, b: undefined} with lodash behält die undefinierten, aber die parse/stringify-Version entfernt sie.

    – Daniel

    29. Januar 2021 um 21:01 Uhr

Benutzer-Avatar
gdibble

API-Referenz unterstreichen:

_.toArray(list) Erstellt ein echtes Array aus der Liste (alles, über das iteriert werden kann). Nützlich zum Transmutieren des arguments-Objekts.

… oder in diesem Fall Klonen eine Anordnung. Versuche dies:

var _ = require('underscore');
var array1 =  [{a:{b:{c:1}}},{b:{c:{a:2}}},{c:{a:{b:3}}}];
var array2 = _.toArray(array1);
console.log(array1 === array2); --> false
console.log(array1[0] === array2[0]); --> true

Das Folgende ist ein Nachtrag, den ich nach Steves Kommentar unter -thx erstellt habe

Ein Vanilla JS (oder mit _.clone wenn gewünscht) Rekursiver Helfer für Deep Cloning:

function clone(thing, opts) {
    var newObject = {};
    if (thing instanceof Array) {
        return thing.map(function (i) { return clone(i, opts); });
    } else if (thing instanceof Date) {
        return new Date(thing);
    } else if (thing instanceof RegExp) {
        return new RegExp(thing);
    } else if (thing instanceof Function) {
        return opts && opts.newFns ?
                   new Function('return ' + thing.toString())() :
                   thing;
    } else if (thing instanceof Object) {
        Object.keys(thing).forEach(function (key) {
            newObject[key] = clone(thing[key], opts);
        });
        return newObject;
    } else if ([ undefined, null ].indexOf(thing) > -1) {
        return thing;
    } else {
        if (thing.constructor.name === 'Symbol') {
            return Symbol(thing.toString()
                       .replace(/^Symbol\(/, '')
                       .slice(0, -1));
        }
        // return _.clone(thing);  // If you must use _ ;)
        return thing.__proto__.constructor(thing);
    }
}

var a = {
    a: undefined,
    b: null,
    c: 'a',
    d: 0,
    e: Symbol('a'),
    f: {},
    g: { a:1 },
    h: [],
    i: [ { a:2 }, { a:3 } ],
    j: [ 1, 2 ],
    k: function (a) { return a; },
    l: /[a-z]/g,
    z: [ {
        a: undefined,
        b: null,
        c: 'b',
        d: 1,
        e: Symbol(1),
        f: {},
        g: { b:2 },
        h: { c:{ c:3 } },
        i: { a:Symbol('b') },
        j: { a:undefined, b:null },
        k: [],
        l: [ 1, [ 1, 2 ], [ [ 1, 2, 3 ] ] ],
        m: function (a) { return !a; },
        n: { a:function (a) { return !!a; } },
        o: /(a|b)/i
       } ]
};
var b = clone(a);
var c = clone(a, { newFns:true });


/* Results - value beneath each for reference:

a.a === b.a --> true
undefined

a.b === b.b --> true
null

a.c === b.c --> true
'a'

a.d === b.d --> true
0

a.e === b.e --> false
Symbol(a)

a.f === b.f --> false
{}

a.g === b.g --> false
{ a:1 }

a.h === b.h --> false
[]

a.i === b.i --> false
[ { a:2 }, { a:3 } ]

a.i[0] === b.i[0] --> false
{ a:2 }

a.i[0].a === b.i[0].a --> true
2

a.j === b.j --> false
[ 1, 2 ]

a.k === b.k --> true
a.k === c.k --> false
function (a) { return a; }

a.l === b.l --> false
/[a-z]/g

a.z === b.z --> false
[Object]

a.z[0].a === b.z[0].a --> true
undefined

a.z[0].b === b.z[0].b --> true
null

a.z[0].c === b.z[0].c --> true
'b'

a.z[0].d === b.z[0].d --> true
1

a.z[0].e === b.z[0].e --> 
false
Symbol(1)

a.z[0].f === b.z[0].f --> false
{}

a.z[0].g === b.z[0].g -- > false
{ b:2 }

a.z[0].g.b === b.z[0].g.b --> true
2

a.z[0].h === b.z[0].h --> false
{ c:{ c:3 } }

a.z[0].h.c === b.z[0].h.c --> false
{ c:3 }

a.z[0].h.c.c === b.z[0].h.c.c --> true
3

a.z[0].i === b.z[0].i --> false
{ a:Symbol(b) }

a.z[0].i.a === b.z[0].i.a --> false
Symbol(b)

a.z[0].j === b.z[0].j --> false
{ a:undefined, b:null }

a.z[0].j.a === b.z[0].j.a --> true
undefined

a.z[0].k === b.z[0].k --> false
[]

a.z[0].l === b.z[0].l --> false
[ 1, [ 1, 2 ], [ [ 1, 2, 3 ] ] ]

a.z[0].l[1] === b.z[0].l[1] --> false
[ 1, 2 ]

a.z[0].l[1][1] === b.z[0].l[1][1] --> true
2

a.z[0].m === b.z[0].m --> true
a.z[0].m === c.z[0].m --> false
function (a) { return !a; }

a.z[0].n === b.z[0].n --> false
{ a:function (a) { return !!a; } }

a.z[0].n.a === b.z[0].n.a --> true
a.z[0].n.a === c.z[0].n.a --> false
function (a) { return !!a; }

a.z[0].o === b.z[0].o --> false
/(a|b)/i

*/

1145590cookie-checkWie klonen Sie ein Array von Objekten mit Unterstrich?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy