आप अंडरस्कोर का उपयोग करके वस्तुओं की एक सरणी कैसे क्लोन करते हैं?


82
#!/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));

इसका परिणाम यह होगा:

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

क्लोन काम करता दिखाई नहीं देता! इसलिए मैं RTFM, और इसे देखता हूं:

http://underscorejs.org/#clone

ऑब्जेक्ट के उथले-कॉपी किए गए क्लोन बनाएँ। किसी भी नेस्टेड ऑब्जेक्ट या सरणियों को संदर्भ द्वारा कॉपी किया जाएगा, डुप्लिकेट नहीं।

तो _.cloneबहुत बेकार है। क्या वास्तव में वस्तुओं के सरणी की नकल करने का एक तरीका है?


4
गहरी प्रति के लिए एक पुल अनुरोध था जिसे अस्वीकार कर दिया गया था: github.com/jashkenas/underscore/pull/595 लो-डैश ने क्लोन किया है
epascarello

5
योग्य मुझे सिर्फ अंडरस्कोर पर सजा का एहसास हुआ। कम पानी का छींटा।
जेस

1
अंडरस्कोर बनाम लॉश: stackoverflow.com/questions/13789618/…
जेस

जवाबों:


122

खैर, एक चाल है! यदि क्लोन नेस्टेड ऑब्जेक्ट्स को "क्लोन" नहीं करता है, तो आप इसे मैप कॉल के अंदर प्रत्येक ऑब्जेक्ट को स्पष्ट रूप से क्लोन करके बाध्य कर सकते हैं! ऐशे ही:

#!/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));

प्रिंटों:

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

वाह! aअपरिवर्तित है! मैं अब bअपनी पसंद के अनुसार संपादन कर सकता हूं!


48
हालांकि सावधान रहें। यह निश्चित रूप से केवल दो स्तरों में काम करता है। उन सरणियों या वस्तुओं के लिए नहीं, जो इस उदाहरण से भी अधिक नेस्टेड हैं।
साइमन ज़ीक्स

1
डिजाइन से, अंडरस्कोर भी RegExp या दिनांक मानों को ठीक से क्लोन नहीं करेगा
मार्क के कोवान

1
यहाँ किसी को भी मेरा जवाब नीचे देखना चाहिए।
gdibble

65

गितुब पर समस्या से निकाले गए एक अन्य समाधान जो किसी भी स्तर पर नेस्टेड डेटा के साथ काम करता है, और अंडरस्कोर की आवश्यकता नहीं है:

JSON.parse(JSON.stringify(obj))

13
यह तब तक काम करता है जब तक कि ऑब्जेक्ट में एक चक्र न हो, जिस स्थिति में JSON.stringifyकोई त्रुटि होती है। जो मूल में मामला नहीं है, लेकिन अभी भी मामलों की एक दिलचस्प स्थिति है। a = {simple: 'thing'}; a.cycle = a ; JSON.stringify(a)
एमकेवी

10
इस समाधान को ध्यान देने योग्य भी केवल सरल प्रकार के साथ वस्तुओं के लिए काम करता है। उदाहरण के लिए, यदि आप ऑब्जेक्ट हैं Dateया Regexउदाहरण हैं, तो उन्हें स्ट्रिंग्स के लिए क्रमांकित किया जाएगा। दुनिया का अंत नहीं है, लेकिन अगर आप इस का उपयोग कर रहे हैं और Dateउदाहरणों की अपेक्षा करते हैं, तो आपको इसे संभालने की आवश्यकता है ।
cayleyh

1
और अगर आपको लगता है कि कोई व्यक्ति undefinedआपको इसे खिलाने की कोशिश कर सकता है, तो आप JSON.parse(JSON.stringify(obj) || null)इसे अन्यथा फेंक देंगे।
इयान मैकिनॉन

1
@Cayleyh ने जो उल्लेख किया है उसके साथ, यह functionपूरी तरह से गिर जाएगा ।
Marko Grešak


9

अंडरस्कोर एपीआई संदर्भ :

_.toArray(list)सूची से एक वास्तविक ऐरे बनाता है (कुछ भी जो इसे खत्म किया जा सकता है)। तर्क वस्तु को प्रसारित करने के लिए उपयोगी है।

... या इस मामले में, एक सरणी का क्लोनिंग । इसे इस्तेमाल करे:

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

निम्नलिखित एक परिशिष्ट है जिसे मैंने स्टीव के नीचे -thx की टिप्पणी के बाद बनाया है

एक वेनिला जेएस (या _.cloneयदि वांछित है) का उपयोग करके गहरी क्लोनिंग पुनरावर्ती सहायक :

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

*/

यह सबसे अच्छा जवाब है।
पियरे

_.toArray(list)एक सरणी में वस्तुओं को क्लोन नहीं करता है। var array1 = [{a: 1}, {a: 2}, {a: 3}]; var array2 = _.toArray(array1); array2[0].a = 999; console.log(array1[0]); --> {a: 999}
स्टीव लैंग

@SteveLang कि बाहर इशारा करने के लिए धन्यवाद। उफ़। इसलिए मुझे वनीला JS fn को उपर लाने में कुछ समय लगा, जो कि अगर उपयोगकर्ता को वास्तव _.cloneमें elseकंडीशन में उपयोग करना है ;)
gdibble
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.