ජාවාස්ක්‍රිප්ට් වස්තුවක් නිවැරදිව ක්ලෝන කරන්නේ කෙසේද?


3090

මට වස්තුවක් xතිබේ. yවෙනස් කිරීමට yනොහැකි වන පරිදි එය වස්තුවක් ලෙස පිටපත් කිරීමට මම කැමතියි x. ජාවාස්ක්‍රිප්ට් වස්තු වලින් සාදන ලද වස්තූන් පිටපත් කිරීමෙන් අමතර අනවශ්‍ය ගුණාංග ඇති වන බව මම තේරුම් ගතිමි. මෙය මගේම වචනාර්ථයෙන් සාදන ලද වස්තුවක් පිටපත් කරන බැවින් මෙය ගැටළුවක් නොවේ.

ජාවාස්ක්‍රිප්ට් වස්තුවක් නිවැරදිව ක්ලෝන කරන්නේ කෙසේද?


31
මෙම ප්‍රශ්නය බලන්න: stackoverflow.com/questions/122102/…
නියාස්

258
JSON සඳහා, මම භාවිතා කරමිmObj=JSON.parse(JSON.stringify(jsonObject));
ලෝ ලෝ.

68
කිසිවෙකු යෝජනා නොකරන්නේ මන්දැයි මට තේරෙන්නේ නැත Object.create(o), එය කතුවරයා අසන සෑම දෙයක්ම කරයිද?
froginvasion

45
var x = { deep: { key: 1 } }; var y = Object.create(x); x.deep.key = 2; මෙය සිදු කිරීමෙන් පසු y.deep.key2 ක් ද වනු ඇත, එබැවින් Object.create ක්ලෝනකරණය සඳහා භාවිතා කළ නොහැක ...
රූබන් ස්ටොක්

18
work r3wt එය ක්‍රියා නොකරනු ඇත ... කරුණාකර විසඳුම පිළිබඳ මූලික පරීක්‍ෂණයක් කිරීමෙන් පසුව පමණක් පළ කරන්න ..
අක්ෂේ

Answers:


1564

ජාවාස්ක්‍රිප්ට් හි ඕනෑම වස්තුවක් සඳහා මෙය කිරීම සරල හෝ සරල නොවේ. මූලාකෘතියේ ඉතිරිව තිබිය යුතු සහ නව අවස්ථාවට පිටපත් නොකළ යුතු වස්තුවක මූලාකෘතියෙන් වැරදි ලෙස ගුණාංග ලබා ගැනීමේ ගැටලුවට ඔබ මුහුණ දෙනු ඇත. නිදසුනක් ලෙස, ඔබ යම් පිළිතුරක් නිරූපණය කරන පරිදි cloneක්‍රමයක් එකතු කරන්නේ නම්, ඔබට Object.prototypeඑම ගුණාංගය පැහැදිලිවම මඟ හැරිය යුතුය. නමුත් Object.prototypeඔබ නොදන්නා වෙනත් අතිරේක ක්‍රම හෝ වෙනත් අතරමැදි මූලාකෘති තිබේ නම් කුමක් කළ යුතුද? එවැනි අවස්ථාවකදී, ඔබ නොකළ යුතු ගුණාංග ඔබ පිටපත් කරනු ඇත, එබැවින් ඔබ hasOwnPropertyක්‍රමවේදය සමඟ අනපේක්ෂිත, දේශීය නොවන ගුණාංග හඳුනාගත යුතුය .

ගණන් කළ නොහැකි ගුණාංග වලට අමතරව, සැඟවුණු ගුණාංග ඇති වස්තු පිටපත් කිරීමට ඔබ උත්සාහ කරන විට ඔබට දැඩි ගැටළුවක් ඇති වේ. උදාහරණයක් ලෙස, prototypeශ්‍රිතයක සැඟවුණු දේපලකි. එසේම, වස්තුවක මූලාකෘතිය ගුණාංගය සමඟ යොමු කර ඇති __proto__අතර එය ද සැඟවී ඇති අතර ප්‍රභව වස්තුවේ ගුණාංගවලට වඩා නැවත / ලූපයක් මඟින් එය පිටපත් නොකෙරේ. මම හිතන්නේ __proto__ෆයර්ෆොක්ස් හි ජාවාස්ක්‍රිප්ට් පරිවර්තකයට විශේෂිත විය හැකි අතර එය වෙනත් බ්‍රව්සර්වල වෙනස් දෙයක් විය හැකි නමුත් ඔබට පින්තූරය ලැබේ. සෑම දෙයක්ම ගණන් කළ නොහැකි ය. ඔබ එහි නම දන්නේ නම් ඔබට සැඟවුණු ගුණාංගයක් පිටපත් කළ හැකිය, නමුත් එය ස්වයංක්‍රීයව සොයාගත හැකි ක්‍රමයක් මම නොදනිමි.

අලංකාර විසඳුමක් සෙවීමේ තවත් උමතුවක් වන්නේ මූලාකෘති උරුමය නිවැරදිව සැකසීමේ ගැටලුවයි. ඔබේ ප්‍රභව වස්තුවේ මූලාකෘතිය නම් Object, සරලවම නව පොදු වස්තුවක් නිර්මාණය කිරීම {}ක්‍රියා කරයි, නමුත් ප්‍රභවයේ මූලාකෘතිය යම්කිසි පරම්පරාවක් නම් Object, එවිට ඔබ hasOwnPropertyපෙරණය භාවිතයෙන් මඟ හැරුණු එම මූලාකෘතියේ අතිරේක සාමාජිකයින් ඔබට අහිමි වනු ඇත . මූලාකෘතියේ තිබුනද ඒවා මුලින් ගණන් කළ නොහැකි විය. එක් විසඳුමක් විය හැක්කේ constructorආරම්භක පිටපත් වස්තුව ලබා ගැනීම සඳහා ප්‍රභව වස්තුවේ දේපල අමතා පසුව ගුණාංග පිටපත් කිරීමයි, නමුත් ඔබට තවමත් ගණන් කළ නොහැකි ගුණාංග නොලැබෙනු ඇත. උදාහරණයක් ලෙස, Dateවස්තුවක් එහි දත්ත සැඟවුණු සාමාජිකයෙකු ලෙස ගබඩා කරයි:

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}

var d1 = new Date();

/* Executes function after 5 seconds. */
setTimeout(function(){
    var d2 = clone(d1);
    alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString());
}, 5000);

දිනය සඳහා d1තත්පර 5 ක් පසු වේ d2. එකක් Dateඅනෙකට සමාන කළ හැකි setTimeක්‍රමයක් වන්නේ ක්‍රමවේදය ඇමතීමයි, නමුත් එය Dateපන්තියට විශේෂිත වේ . මෙම ගැටලුවට වෙඩි නොවදින පොදු විසඳුමක් ඇතැයි මම නොසිතමි.

මම පිටපත් සාමාන්ය ගැඹුරු ක්රියාත්මක කිරීමට ගිය විට මට පමණක් සරල පිටපත් කිරීමට අවශ්ය වනු ඇත යන උපකල්පනය මත සම්මුති අවසන් Object, Array, Date, String, Number, හෝ Boolean. අන්තිම වර්ග 3 වෙනස් කළ නොහැකි නිසා මට නොගැඹුරු පිටපතක් කළ හැකි අතර එය වෙනස් වීම ගැන කරදර නොවන්න. එම ලැයිස්තුවේ ඇති සරල වර්ග 6 න් එකක් Objectහෝ අඩංගු ඕනෑම මූලද්‍රව්‍යයක් Arrayවනු ඇතැයි මම තවදුරටත් උපකල්පනය කළෙමි . පහත සඳහන් කේත සමඟ මෙය කළ හැකිය:

function clone(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

ඉහත සඳහන් ශ්‍රිතය මා සඳහන් කළ සරල වර්ග 6 සඳහා ප්‍රමාණවත් ලෙස ක්‍රියා කරනු ඇත, වස්තූන් හා අරා වල දත්ත ගස් ව්‍යුහයක් සාදන තාක් කල්. එනම්, වස්තුවේ එකම දත්ත ගැන එකකට වඩා සඳහන් නොවේ. උදාහරණයක් වශයෙන්:

// This would be cloneable:
var tree = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "right" : null,
    "data"  : 8
};

// This would kind-of work, but you would get 2 copies of the 
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];

// Cloning this would cause a stack overflow due to infinite recursion:
var cyclicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
cyclicGraph["right"] = cyclicGraph;

එයට කිසිදු ජාවාස්ක්‍රිප්ට් වස්තුවක් හැසිරවීමට නොහැකි වනු ඇත, නමුත් ඔබ එය විසි කරන ඕනෑම දෙයකට එය ක්‍රියා කරනු ඇතැයි ඔබ නොසිතන තාක් කල් එය බොහෝ අරමුණු සඳහා ප්‍රමාණවත් වේ.


5
පාහේ මම <obj.length; {සඳහා (var i = 0; පමණක් (;; i <ලෙන් ++ i var i = 0, var කාචය = obj.length) සඳහා වන රේඛාව වෙනස් වුණා - A nodejs කදිම වැඩ ++ i) {
ට්‍රින්ඩාස්

5
අනාගත ගූගල්කරුවන් සඳහා: එකම ගැඹුරු පිටපතක්, gist.github.com/2234277
ට්‍රින්ඩාස්

8
වර්තමානයේ JSON.parse(JSON.stringify([some object]),[some revirer function])විසඳුමක් වේවිද?
KooiInc

5
පළමු ස්නිපටයේ, එය එසේ නොවිය යුතු යැයි ඔබට විශ්වාසද var cpy = new obj.constructor()?
සයන්

8
වස්තු පැවරුම Chrome හි සත්‍ය පිටපතක් සාදන බවක් නොපෙනේ, මුල් වස්තුව පිළිබඳ සඳහනක් පවත්වා ගෙන යයි - JSON.stringify සහ JSON.parse භාවිතා කර ක්ලෝන කිරීමට - පරිපූර්ණව ක්‍රියාත්මක විය
1owk3y

975

ඔබ Dateඔබේ වස්තුව තුළ s, කාර්යයන්, නිර්වචනය නොකළ, regExp හෝ Infinity භාවිතා නොකරන්නේ නම් , ඉතා සරල එක් ලයිනර් එකක් JSON.parse(JSON.stringify(object)):

const a = {
  string: 'string',
  number: 123,
  bool: false,
  nul: null,
  date: new Date(),  // stringified
  undef: undefined,  // lost
  inf: Infinity,  // forced to 'null'
}
console.log(a);
console.log(typeof a.date);  // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date);  // result of .toISOString()

වස්තූන්, අරා, නූල්, බූලියන් සහ සංඛ්‍යා අඩංගු සියලු වර්ගවල වස්තු සඳහා මෙය ක්‍රියා කරයි.

සේවකයෙකුට සහ ඉන් පණිවිඩ යැවීමේදී භාවිතා කරන බ්‍රව්සර්වල ව්‍යුහාත්මක ක්ලෝන ඇල්ගොරිතම පිළිබඳ මෙම ලිපිය ද බලන්න . ගැඹුරු ක්ලෝනකරණය සඳහා ශ්‍රිතයක් ද එහි අඩංගු වේ.


43
මෙය භාවිතා කළ හැක්කේ පරීක්ෂා කිරීම සඳහා පමණක් බව සලකන්න. පළමුවෙන්ම, කාලය හා මතක පරිභෝජනය අනුව එය ප්‍රශස්ත නොවේ. දෙවනුව, සෑම බ්‍රව්සරයකම මෙම ක්‍රම නොමැත.
Nux

2
ඔබට සැමවිටම JSON2.js හෝ JSON3.js ඇතුළත් කළ හැකිය. කෙසේ හෝ ඔබගේ යෙදුම සඳහා ඔබට ඒවා අවශ්‍ය වේ. JSON.stringify හි උරුම වූ ගුණාංග ඇතුළත් නොවන බැවින් මෙය හොඳම විසඳුම නොවන බව මම එකඟ වෙමි.
ටිම් හොං

79
UxNux, කාලය සහ මතකය අනුව ප්‍රශස්ත නොවන්නේ ඇයි? මයිජින් මෙසේ පවසයි: "මෙම ක්‍රමය නොගැඹුරු පිටපත් කිරීමට වඩා (ගැඹුරු වස්තුවක් මත) මන්දගාමී වීමට හේතුව මෙම ක්‍රමය අර්ථ දැක්වීම අනුව ගැඹුරු පිටපත් වීමයි. නමුත් JSON ස්වදේශීය කේතයෙන් (බොහෝ බ්‍රව්සර් වල) ක්‍රියාත්මක වන බැවින් මෙය සැලකිය යුතු වේගයකින් සිදුවනු ඇත. වෙනත් ජාවාස්ක්‍රිප්ට් මත පදනම් වූ ගැඹුරු පිටපත් කිරීමේ විසඳුමක් භාවිතා කිරීමට වඩා, සමහර විට එය ජාවාස්ක්‍රිප්ට් මත පදනම් වූ නොගැඹුරු පිටපත් කිරීමේ ක්‍රමයකට වඩා වේගවත් විය හැකිය (බලන්න: jsperf.com/cloning-an-object/79). stackoverflow.com/questions/122102/…
BeauCielBleu

17
මට අවශ්‍ය වන්නේ 2014 ඔක්තෝම්බර් සඳහා මේ සඳහා යාවත්කාලීනයක් එක් කිරීමට ය. ක්‍රෝම් 37+ JSON.parse (JSON.stringify (oldObject)) සමඟ වේගවත් වේ; මෙය භාවිතා කිරීමේ වාසිය නම්, ජාවාස්ක්‍රිප්ට් එන්ජිමකට අවශ්‍ය නම් වඩා හොඳ දෙයක් දැක බලා එය ප්‍රශස්ත කිරීම ඉතා පහසු වීමයි.
mirhagk

17
2016 යාවත්කාලීනය: මෙය දැන් බහුලව භාවිතා වන සෑම බ්‍රව්සරයකම වැඩ කළ යුතුය. ( මට භාවිතා කළ හැකිද ... බලන්න ) දැන් ඇති ප්‍රධාන ප්‍රශ්නය වනුයේ එය ප්‍රමාණවත් තරම් ක්‍රියාකාරීද යන්නයි.
ජේම්ස්

784

JQuery සමඟ, ඔබට හැකි නොගැඹුරු පිටපතක් සමග දීර්ඝ :

var copiedObject = jQuery.extend({}, originalObject)

පසුකාලීන වෙනස්වීම් වලට copiedObjectබලපාන්නේ නැත originalObject, සහ අනෙක් අතට.

නැතහොත් ගැඹුරු පිටපතක් සෑදීමට :

var copiedObject = jQuery.extend(true, {}, originalObject)

164
හෝ පවා:var copiedObject = jQuery.extend({},originalObject);
ග්‍රාන්ට් මැක්ලීන්

82
ගැඹුරු පිටපතක් සඳහා පළමු පරාමිතිය ලෙස සත්‍යය සඳහන් කිරීමට ද ප්‍රයෝජනවත් වේ:jQuery.extend(true, {}, originalObject);
විල් ෂේවර්

6
ඔව්, මෙම සබැඳිය මට ප්‍රයෝජනවත් විය (පැස්කල්ට සමාන විසඳුමක්) stackoverflow.com/questions/122102/…
ගැරී ඉංග්‍රීසි

3
සටහනක් පමණක්, මෙය මුල් වස්තුවේ ප්‍රොටෝකෝලය සාදන්නේ නැත
සෑම් ජෝන්ස්

1
අනුව stackoverflow.com/questions/184710/... , එය, originalObject සමුද්දේශ පිටපත් ඉතින් ඇයි මෙතන බව "නොගැඹුරු පිටපතක්" බව පෙනේ පවසයි ...subsequent changes to the copiedObject will not affect the originalObject, and vice versa.... මට ඇත්තටම ව්‍යාකූල වීම ගැන කණගාටුයි.
කාර්

689

ECMAScript 6 හි Object.assign ක්‍රමයක් ඇත, එය එක් එක් වස්තුවක සිට තවත් වස්තුවකට ගණනය කළ හැකි සියළුම දේපලවල අගයන් පිටපත් කරයි. උදාහරණයක් වශයෙන්:

var x = {myProp: "value"};
var y = Object.assign({}, x); 

නමුත් කැදැලි වස්තූන් තවමත් යොමු ලෙස පිටපත් කර ඇති බව මතක තබා ගන්න.


ඔව්, මම විශ්වාස කරන්නේ Object.assignඑය යා යුතු මාර්ගය බවයි. එයද බහු පිරවීම පහසුය: gist.github.com/rafaelrinaldi/43813e707970bd2d77fa

22
එසේම මෙම (මෙම සිට වස්තුව literals හරහා අර්ථ "මෙතෝදිස්තයන්" කට පිටපත් කරනු බව දැනුවත් විය වේ ගණ්ය) නමුත් නොවන ක්රම "පන්තිය" යාන්ත්රණයක් (මෙම සිට හරහා විරෝධය පා නැති ගණ්ය).
මාකස් ජූනියස් බ

16
මා සිතන්නේ මෙය එඩ්ජ් හැර IE විසින් අනුමත නොකරන බවයි. සමහර අය තවමත් මෙය භාවිතා කරයි.
සාවලියස්

1
මෙය @ ඉයුජින් ටියුරින්ගේ පිළිතුරට සමානය.
විල්ට්

5
අත්දැකීම් වලින් කථා කිරීම ... මෙය භාවිතා නොකරන්න. වස්තූන් ධූරාවලිගත වන පරිදි නිර්මාණය කර ඇති අතර ඔබ පළමු මට්ටම පමණක් පිටපත් කරනු ඇත, එමඟින් සම්පූර්ණ වස්තුවම පිටපත් කර ඇත. මාව විශ්වාස කරන්න, එය ඔබේ හිස සීරීමට දින ගණනක් ඉතිරි කරයි.
ow3n

235

එක් එම්ඩීඑන් සඳහා :

  • ඔබට නොගැඹුරු පිටපතක් අවශ්‍ය නම් භාවිතා කරන්න Object.assign({}, a)
  • "ගැඹුරු" පිටපතක් සඳහා, භාවිතා කරන්න JSON.parse(JSON.stringify(a))

බාහිර පුස්තකාල අවශ්‍ය නොවන නමුත් ඔබ පළමුව බ්‍රව්සරයේ අනුකූලතාව පරීක්ෂා කළ යුතුය .


8
JSON.parse (JSON.stringify (a)) ලස්සනයි, නමුත් එය භාවිතා කිරීමට පෙර ඔබ අපේක්ෂිත එකතුව සඳහා ගතවන කාලය මිණුම් සලකුණු කිරීම නිර්දේශ කරමි. වස්තු ප්‍රමාණය මත පදනම්ව, මෙය කිසිසේත්ම ඉක්මන්ම විකල්පය නොවනු ඇත.
එඩ්සා

3
JSON ක්‍රමය මම දැක්කා දින වස්තූන් නූල් බවට පරිවර්තනය කරන නමුත් නැවත දිනට නොවේ. ජාවාස්ක්‍රිප්ට් හි කාල කලාපවල විනෝදය සමඟ කටයුතු කළ යුතු අතර ඕනෑම දිනයක් අතින් සකස් කරන්න. දිනයන් හැර වෙනත් වර්ග සඳහා සමාන අවස්ථා විය හැකිය
ස්ටීව් සීගර්

දිනය සඳහා, මම cloneක්‍රියාකාරීත්වය ඇති බැවින් moment.js භාවිතා කරමි . වැඩි විස්තර මෙතැනින් බලන්න momentjs.com/docs/#/parsing/moment-clone
Tareq

මෙය හොඳයි, නමුත් වස්තුව තුළ ක්‍රියාකාරිත්වය තිබේ නම්
ප්‍රවේශම් වන්න

Json විග්‍රහ කිරීමේ තවත් ගැටළුවක් වන්නේ රවුම් යොමු කිරීම් ය. වස්තුව තුළ කිසියම් චක්‍රලේඛ යොමු කිරීමක් තිබේ නම්, මෙය බිඳී යනු ඇත
philoj

134

බොහෝ පිළිතුරු ඇත, නමුත් ECMAScript 5 වෙතින් Object.create ගැන සඳහන් කරන කිසිවක් ඔබට නිශ්චිත පිටපතක් ලබා නොදෙන බව පිළිගන්නා නමුත් ප්‍රභවය නව වස්තුවේ මූලාකෘතිය ලෙස සකසයි.

මේ අනුව, මෙය ප්‍රශ්නයට නිශ්චිත පිළිතුරක් නොවේ, නමුත් එය එක්-පේළියේ විසඳුමක් වන අතර එමඟින් අලංකාර වේ. එය අවස්ථා 2 ක් සඳහා වඩාත් සුදුසු වේ:

  1. එවැනි උරුමයක් ප්‍රයෝජනවත් වන තැන (duh!)
  2. ප්‍රභව වස්තුව වෙනස් නොකරන තැන, එමඟින් වස්තු 2 අතර සම්බන්ධතාවය ගැටළුවක් නොවේ.

උදාහරණයක්:

var foo = { a : 1 };
var bar = Object.create(foo);
foo.a; // 1
bar.a; // 1
foo.a = 2;
bar.a; // 2 - prototype changed
bar.a = 3;
foo.a; // Still 2, since setting bar.a makes it an "own" property

මෙම විසඳුම වඩා උසස් යැයි මා සලකන්නේ ඇයි? එය ස්වදේශීය ය, එබැවින් ලූපයක් නැත, පුනරාවර්තනයක් නැත. කෙසේ වෙතත්, පැරණි බ්‍රව්සර් සඳහා පොලිෆිල් එකක් අවශ්‍ය වේ.


සටහන: Object.create යනු ගැඹුරු පිටපතක් නොවේ (itpastorn හි පුනරාවර්තනයක් නොමැති බව සඳහන් කර ඇත). සාධනය:var a = {b:'hello',c:{d:'world'}}, b = Object.create(a); a == b /* false */; a.c == b.c /* true */;
zamnuts

104
මෙය මූලාකෘති උරුමය මිස ක්ලෝන කිරීම නොවේ. මේවා සම්පූර්ණයෙන්ම වෙනස් දේවල්. නව වස්තුවට එහි කිසිදු ගුණාංගයක් නොමැත, එය මූලාකෘතිවල ගුණාංග වෙත යොමු කරයි. ක්ලෝන කිරීමේ කාරණය වන්නේ වෙනත් වස්තුවක කිසිදු ගුණාංගයක් සඳහන් නොකරන නැවුම් නව වස්තුවක් නිර්මාණය කිරීමයි.
d13

7
මම ඔබ සමඟ සම්පූර්ණයෙන්ම එකඟයි. මෙය 'අපේක්ෂිත' ක්ලෝනකරණය නොවන බව මම ද එකඟ වෙමි. නමුත් මිනිසුන් වෙත පැමිණ, ප්‍රමිතිගත නොවන අපැහැදිලි විසඳුම් සෙවීමට උත්සාහ කරනවා වෙනුවට ජාවාස්ක්‍රිප්ට් වල ස්වභාවය වැලඳ ගන්න. ඇත්ත වශයෙන්ම, ඔබ මූලාකෘති වලට කැමති නැති අතර ඒවා සියල්ලම ඔබට "අපහාස" වේ, නමුත් ඇත්ත වශයෙන්ම ඔබ කරන්නේ කුමක්දැයි ඔබ දන්නේ නම් ඒවා ඉතා ප්‍රයෝජනවත් වේ.
froginvasion

4
ObRobG: මෙම ලිපිය යොමු කිරීම සහ ක්ලෝනකරණය අතර වෙනස පැහැදිලි කරයි: en.wikipedia.org/wiki/Cloning_(programming) . Object.createයොමු කිරීම් හරහා දෙමව්පියන්ගේ දේපල වෙත යොමු වේ. එයින් අදහස් කරන්නේ දෙමව්පියන්ගේ දේපළ වටිනාකම් වෙනස් වුවහොත් දරුවාගේ දේද වෙනස් වන බවයි. මෙය කූඩුවල අරා සහ වස්තූන් සමඟ පුදුම සහගත අතුරු ආබාධ ඇති අතර ඒවා ඔබ නොදන්නේ නම් ඔබේ කේතයේ දෝෂ සොයා ගැනීමට අපහසු විය හැකිය: jsbin.com/EKivInO/2 . ක්ලෝන කරන ලද වස්තුවක් යනු සම්පූර්ණයෙන්ම නව ස්වාධීන වස්තුවකි, එය මවුපියන්ට සමාන ගුණාංග හා අගයන් ඇත, නමුත් එය මවුපියන්ට සම්බන්ධ නොවේ.
d13

1
මෙය මිනිසුන් නොමඟ යවයි ... Object.create () උරුමය සඳහා මාධ්‍යයක් ලෙස භාවිතා කළ හැකි නමුත් ක්ලෝනකරණය එයට කොතැනකවත් නැත.
prajnavantha

130

එක් කේත පේළියක ජාවාස්ක්‍රිප්ට් වස්තුවක් ක්ලෝන කිරීමට අලංකාර ක්‍රමයක්

Object.assignක්රමය සම්මතයන් 2015 (ES6) සම්මත කොටසක් වන අතර, ඔබට අවශ්ය දේ හරියටම කරනවා.

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

Object.assign () ක්‍රමය භාවිතා කරනුයේ සියළුම ගණනය කළ හැකි දේපලවල අගයන් ප්‍රභව වස්තු එකක් හෝ වැඩි ගණනක සිට ඉලක්කගත වස්තුවකට පිටපත් කිරීමට ය.

වැඩිදුර කියවන්න...

මෙම polyfill පැරණි බ්රව්සර සහාය:

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

ගොළු ප්‍රශ්නයට කණගාටුයි, නමුත් පොලිෆිල් හි ක්‍රියාකාරිත්වය එක් පරාමිතියක් පමණක් Object.assignගන්නා විට පරාමිති දෙකක් ගන්නේ ඇයි value?
ක්වෙර්ටි

@Qwertie ඊයේ සියලුම තර්ක නැවත නැවත එක් වස්තුවකට ඒකාබද්ධ කර අවසන් වරට සම්මත කරන ලද
තර්කයෙන්

ඔහ්, මට පෙනේ, ස්තූතියි (මට argumentsමීට පෙර වස්තුව ගැන හුරුපුරුදු නොවීය .) මට Object()ගූගල් හරහා සොයා ගැනීමට අපහසු විය ... එය යතුරු ලියනයකි, එසේ නොවේ ද?
Qwertie

47
මෙය සිදු කරනුයේ නොගැඹුරු "ක්ලෝනකරණය" පමණි
මාකස් ජූනියස් බ

1
මෙම පිළිතුර හරියටම මේ හා සමාන ය: stackoverflow.com/questions/122102/… මම දනිමි එය එකම පුද්ගලයා විසින් බව නමුත් පිළිතුර පිටපත් කිරීම වෙනුවට ඔබ යොමු කළ යුතුය.
lesolorzanov

88

අන්තර්ජාලයේ බොහෝ විසඳුම් සමඟ ගැටළු කිහිපයක් තිබේ. එබැවින් පිළිගත් පිළිතුර පිළිගත නොහැක්කේ මන්ද යන්න ඇතුළත් පසු විපරමක් කිරීමට මම තීරණය කළෙමි.

ආරම්භක තත්වය

ජාවාස්ක්‍රිප්ට් එකක් එහි සියලුම දරුවන් සහ ඔවුන්ගේ දරුවන් සමඟ ගැඹුරින් පිටපත් කිරීමට මට අවශ්‍යය Object. නමුත් මම වගේ සාමාන්ය සංවර්ධක ක නැහැ පටන් මගේ Objectඇති සාමාන්ය properties , circular structuresපවා හා nested objects.

ඒ නිසා අපි පළමුව circular structureසහ nested objectපළමු නිර්මාණය කරමු .

function Circ() {
    this.me = this;
}

function Nested(y) {
    this.y = y;
}

සෑම දෙයක්ම Objectනමින් නම් කරමු a.

var a = {
    x: 'a',
    circ: new Circ(),
    nested: new Nested('a')
};

ඊළඟට, අපට නම් කළ aහැකි විචල්‍යයකට පිටපත් කර එය bවිකෘති කිරීමට අවශ්‍යය .

var b = a;

b.x = 'b';
b.nested.y = 'b';

මෙහි සිදුවූයේ කුමක්දැයි ඔබ දන්නවා, එසේ නොවුවහොත් ඔබ මෙම ශ්‍රේෂ් question ප්‍රශ්නයට ගොඩ නොවන්නේය.

console.log(a, b);

a --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

දැන් අපි විසඳුමක් සොයා ගනිමු.

JSON

මම උත්සාහ කළ පළමු උත්සාහය වූයේ භාවිතා JSONකිරීමයි.

var b = JSON.parse( JSON.stringify( a ) );

b.x = 'b';
b.nested.y = 'b';

ඒ සඳහා වැඩි කාලයක් නාස්ති නොකරන්න, ඔබට ලැබෙනු TypeError: Converting circular structure to JSONඇත.

පුනරාවර්තන පිටපත (පිළිගත් "පිළිතුර")

පිළිගත් පිළිතුර දෙස බලමු.

function cloneSO(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

හොඳයි, හෙහ්? එය වස්තුවේ පුනරාවර්තන පිටපතක් වන අතර වෙනත් වර්ගද හසුරුවයි Date, නමුත් එය අවශ්‍යතාවයක් නොවීය.

var b = cloneSO(a);

b.x = 'b';
b.nested.y = 'b';

පුනරාවර්තනය සහ circular structuresහොඳින් ක්‍රියා නොකරයි ...RangeError: Maximum call stack size exceeded

දේශීය විසඳුම

මගේ සම-සේවකයා සමඟ වාද කිරීමෙන් පසු, මගේ ලොක්කා අපෙන් ඇසුවේ කුමක්දැයි විමසූ අතර, ඔහු ගොග්ලිං කිරීමෙන් පසු සරල විසඳුමක් සොයා ගත්තේය . එය හැඳින්වේ Object.create.

var b = Object.create(a);

b.x = 'b';
b.nested.y = 'b';

මෙම විසඳුම කලකට පෙර ජාවාස්ක්‍රිප්ට් වෙත එකතු කරන ලද අතර එය හසුරුවයි circular structure.

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

... ඔබට පෙනේ, එය ඇතුළත කැදැලි ව්‍යුහය සමඟ ක්‍රියා කළේ නැත.

දේශීය විසඳුම සඳහා පොලිෆිල්

Object.createIE 8 මෙන් පැරණි බ්‍රව්සරයේ පොලිෆිල් එකක් තිබේ. එය මොසිල්ලා විසින් නිර්දේශ කරන ලද දෙයක් වන අතර ඇත්ත වශයෙන්ම එය පරිපූර්ණ නොවන අතර දේශීය විසඳුම හා සමාන ගැටළුවක් ඇති කරයි .

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

var b = clonePF(a);

b.x = 'b';
b.nested.y = 'b';

මම Fවිෂය පථයෙන් පිටත තබා ඇති නිසා අපට instanceofපවසන දේ බැලීමට අපට හැකිය.

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> F {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> true

ස්වදේශීය විසඳුම හා සමාන ගැටළුවක් , නමුත් ටිකක් නරක ප්‍රතිදානය.

වඩා හොඳ (නමුත් පරිපූර්ණ නොවේ) විසඳුම

වටේ කැණීමේදී මට සමාන ප්‍රශ්නයක් හමු විය ( ජාවාස්ක්‍රිප්ට් හි, ගැඹුරු පිටපතක් සිදු කරන විට, දේපලක් “මෙය” වීම නිසා මම චක්‍රයක් වළක්වා ගන්නේ කෙසේද? ) නමුත් මේ සඳහා වඩා හොඳ විසඳුමක් ඇත.

function cloneDR(o) {
    const gdcc = "__getDeepCircularCopy__";
    if (o !== Object(o)) {
        return o; // primitive value
    }

    var set = gdcc in o,
        cache = o[gdcc],
        result;
    if (set && typeof cache == "function") {
        return cache();
    }
    // else
    o[gdcc] = function() { return result; }; // overwrite
    if (o instanceof Array) {
        result = [];
        for (var i=0; i<o.length; i++) {
            result[i] = cloneDR(o[i]);
        }
    } else {
        result = {};
        for (var prop in o)
            if (prop != gdcc)
                result[prop] = cloneDR(o[prop]);
            else if (set)
                result[prop] = cloneDR(cache);
    }
    if (set) {
        o[gdcc] = cache; // reset
    } else {
        delete o[gdcc]; // unset again
    }
    return result;
}

var b = cloneDR(a);

b.x = 'b';
b.nested.y = 'b';

ප්‍රතිදානය දෙස බලමු ...

console.log(a, b);

a --> Object {
    x: "a",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "a"
    }
}

b --> Object {
    x: "b",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> false

අවශ්‍යතා ගැලපේ, නමුත් වෙනස් instanceකිරීම nestedසහ වෙනස් කිරීම ඇතුළුව තවමත් කුඩා ගැටළු කිහිපයක් circතිබේ Object.

පත්‍රයක් බෙදා ගන්නා ගස්වල ව්‍යුහය පිටපත් නොකෙරේ, ඒවා ස්වාධීන කොළ දෙකක් බවට පත්වේ:

        [Object]                     [Object]
         /    \                       /    \
        /      \                     /      \
      |/_      _\|                 |/_      _\|  
  [Object]    [Object]   ===>  [Object]    [Object]
       \        /                 |           |
        \      /                  |           |
        _\|  |/_                 \|/         \|/
        [Object]               [Object]    [Object]

නිගමනය

පුනරාවර්තනය සහ හැඹිලිය භාවිතා කරන අවසාන විසඳුම හොඳම නොවිය හැකි නමුත් එය වස්තුවේ සැබෑ ගැඹුරු පිටපතකි. එය සරල හසුරුවන properties, circular structuresසහ nested objectඋත්සහය අතර, නමුත් එය අවුල් කරනු ඔවුන් උදාහරණයක් දක්වා.

jsfiddle


12
ඒ නිසා සම්මුතිය යනු එම ගැටළුව මඟහරවා ගැනීමයි :)
මිකස්

මූලික භාවිත අවස්ථා වලට වඩා වැඩි ප්‍රමාණයක් ආවරණය වන සැබෑ පිරිවිතරයක් ඇති වන තෙක් මිකස් , ඔව්.
ෆේබියෝ පොලෝනි

2
ඉහත දක්වා ඇති විසඳුම් පිළිබඳ නිවැරදි විශ්ලේෂණයක් කළ නමුත් කතුවරයා විසින් නිගමනය කරන ලද නිගමනයෙන් පෙන්නුම් කරන්නේ මෙම ප්‍රශ්නයට විසඳුමක් නොමැති බවයි.
අමීර් මොග්

2
ජේඑස් ස්වදේශීය ක්ලෝන ක්‍රියාකාරිත්වය ඇතුළත් නොකිරීම ලැජ්ජාවකි.
l00k

1
සියලුම ඉහළ පිළිතුරු අතර, මෙය නිවැරදි පිළිතුරට සමීප බව මට හැඟේ.
KTU

78

නොගැඹුරු පිටපතක් සමඟ ඔබ හොඳින් නම්, underscore.js පුස්තකාලයට ක්ලෝනයක් ඇත ක්‍රමයක් ඇත.

y = _.clone(x);

නැත්නම් ඔබට එය දිගු කළ හැකිය

copiedObject = _.extend({},originalObject);

2
ස්තූතියි. උල්කාපාත සේවාදායකයක මෙම තාක්ෂණය භාවිතා කිරීම.
ටර්බෝ

ලොඩාෂ් සමඟ ඉක්මනින් ආරම්භ කිරීම සඳහා, මම නිර්දේශ කරන්නේ npm, Browserify මෙන්ම lodash ඉගෙනීමයි. මට 'npm i --save lodash.clone' සමඟ වැඩ කිරීමට ක්ලෝන ලැබුණි, පසුව 'var clone = required (' lodash.clone ');' වැඩ කිරීමට අවශ්‍ය වීමට, ඔබට බ්‍රවුසරකරණය වැනි දෙයක් අවශ්‍ය වේ. ඔබ එය ස්ථාපනය කර එය ක්‍රියාත්මක වන ආකාරය ඉගෙන ගත් පසු, ඔබ ඔබේ කේතය ක්‍රියාත්මක කරන සෑම අවස්ථාවකම (කෙලින්ම Chrome වෙත යාම වෙනුවට) 'browserify yourfile.js> bundle.js; chrome index.html ආරම්භ කරන්න' භාවිතා කරයි. මෙය ඔබගේ ගොනුව සහ npm මොඩියුලයේ සිට ඔබට අවශ්‍ය සියලුම ගොනු bundle.js වෙත රැස් කරයි. ඔබට බොහෝ විට කාලය ඉතිරි කර ගත හැකි අතර ගුල්ප් සමඟ මෙම පියවර ස්වයංක්‍රීය කළ හැකිය.
ආරොන් බෙල්

66

හරි, ඔබට මෙම වස්තුව පහතින් ඇති බව සිතන්න, ඔබට එය ක්ලෝන කිරීමට අවශ්‍යය:

let obj = {a:1, b:2, c:3}; //ES6

හෝ

var obj = {a:1, b:2, c:3}; //ES5

පිළිතුර ප්‍රධාන වශයෙන් ඔබ භාවිතා කරන ECMAscript මත ක්ෂය වී ඇත , දී ES6+ඔබට Object.assignක්ලෝනය කිරීමට සරලව භාවිතා කළ හැකිය :

let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3};

හෝ මේ ආකාරයට පැතිරීමේ ක්‍රියාකරු භාවිතා කිරීම:

let cloned = {...obj}; //new {a:1, b:2, c:3};

නමුත් ඔබ භාවිතා කරන්නේ නම් ES5, ඔබට ක්‍රම කිහිපයක් භාවිතා කළ හැකිය, නමුත් JSON.stringify, ඔබ පිටපත් කිරීම සඳහා විශාල දත්ත ප්‍රමාණයක් භාවිතා නොකිරීමට වග බලා ගන්න, නමුත් එය බොහෝ අවස්ථාවන්හිදී එක් පේළියක් සඳහා පහසු ක්‍රමයක් විය හැකිය, මේ වගේ දෙයක්:

let cloned = JSON.parse(JSON.stringify(obj)); 
//new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over

ඔබට big chunk of dataසමාන විය හැකි දේට උදාහරණයක් දිය හැකිද ? 100kb? 100MB? ස්තූතියි!
user1063287

ඔව්, @ user1063287, මූලික වශයෙන් විශාල දත්ත, කාර්ය සාධනය වඩාත් නරකයි ... එබැවින් එය සැබවින්ම රඳා පවතින්නේ kb, mb හෝ gb නොවේ, එය ඔබට කොපමණ වාර ගණනක් අවශ්‍යද යන්න ගැන වැඩි යමක් වේ ... එසේම එය ක්‍රියා නොකරනු ඇත කාර්යයන් සහ වෙනත් දේවල් සඳහා ...
Alireza

3
Object.assignනොගැඹුරු පිටපතක් සාදයි (පැතිරීම මෙන්ම, ඇලිසෙරා)
බොග්ඩාන් ඩී

^) @Alireza: ඔබ es5 ඉඩ දෙන්න භාවිතා කළ නොහැකි
SensationSama

41

සාමාජික ක්‍රමවේදයන් නොමැති වස්තූන්ගේ ගැඹුරු පිටපත් සෑදීම සඳහා JSON කේතීකරණය භාවිතා කිරීම විශේෂයෙන් අනවශ්‍ය විසඳුමකි. ක්‍රමවේදය වන්නේ JSON ඔබේ ඉලක්කගත වස්තුව සංකේතනය කිරීමයි, පසුව එය විකේතනය කිරීමෙන් ඔබ සොයන පිටපත ලැබෙනු ඇත. ඔබට අවශ්‍ය තරම් පිටපත් සෑදීමට අවශ්‍ය වාර ගණනක් විකේතනය කළ හැකිය.

ඇත්ත වශයෙන්ම, කාර්යයන් JSON හි අයත් නොවේ, එබැවින් මෙය ක්‍රියාත්මක වන්නේ සාමාජික ක්‍රම නොමැතිව වස්තු සඳහා පමණි.

මම JSON බ්ලොබ් යතුරු අගය ගබඩාවක ගබඩා කර ඇති නිසාත්, ඒවා ජාවාස්ක්‍රිප්ට් API එකක වස්තු ලෙස නිරාවරණය වන විටත්, සෑම වස්තුවකම ඇත්ත වශයෙන්ම වස්තුවේ මුල් තත්වයේ පිටපතක් අඩංගු වන බැවින් මෙම ක්‍රමය මගේ භාවිත අවස්ථාව සඳහා පරිපූර්ණ විය. අමතන්නා විසින් නිරාවරණය වූ වස්තුව විකෘති කිරීමෙන් පසුව ඩෙල්ටාව ගණනය කළ හැකිය.

var object1 = {key:"value"};
var object2 = object1;

object2 = JSON.stringify(object1);
object2 = JSON.parse(object2);

object2.key = "a change";
console.log(object1);// returns value

කාර්යයන් JSON ට අයත් නොවන්නේ ඇයි? ඔවුන් නැවත වරක් JSON ලෙස මාරු කරනු මම දැක ඇත්තෙමි ...
the_drow

5
කාර්යයන් JSON පිරිවිතරයේ කොටසක් නොවේ, ඒවා දත්ත මාරු කිරීම සඳහා ආරක්ෂිත (හෝ බුද්ධිමත්) ක්‍රමයක් නොවන අතර, එය JSON සඳහා සාදන ලද්දකි. ෆයර්ෆොක්ස් හි ස්වදේශීය JSON එන්කෝඩරය එයට ලබා දෙන කාර්යයන් නොසලකා හරින බව මම දනිමි, නමුත් අනෙක් අයගේ හැසිරීම ගැන මට විශ්වාස නැත.
ක්‍රිස් වෝකර්

1
@mark: { 'foo': function() { return 1; } }යනු වචනානුසාරයෙන් සාදන ලද වස්තුවකි.
abarnert

ar බාර්නර්ට් කාර්යයන් දත්ත නොවේ. "ක්‍රියාකාරී වචනාර්ථයන්" යනු වැරදි නාමයකි - කාර්යයන් සඳහා පැවරුම් සහ සියලු ආකාරයේ "අනුක්‍රමික නොවන" දේවල් ඇතුළුව අත්තනෝමතික කේත අඩංගු විය හැකිය.
vemv

36

යොමු කිරීමකින් තොරව වස්තුවක් පිටපත් කිරීමට ඔබට පැතිරීමේ දේපලක් භාවිතා කළ හැකිය . නමුත් ප්‍රවේශම් වන්න (අදහස් බලන්න), 'පිටපත' ඇත්තේ අවම වස්තුව / අරාව මට්ටමින් ය. කැදැලි දේපල තවමත් යොමු කිරීම් වේ!


සම්පූර්ණ ක්ලෝන:

let x = {a: 'value1'}
let x2 = {...x}

// => mutate without references:

x2.a = 'value2'
console.log(x.a)    // => 'value1'

දෙවන මට්ටමේ යොමු කිරීම් සහිත ක්ලෝන:

const y = {a: {b: 'value3'}}
const y2 = {...y}

// => nested object is still a references:

y2.a.b = 'value4'
console.log(y.a.b)    // => 'value4'

ජාවාස්ක්‍රිප්ට් ඇත්ත වශයෙන්ම දේශීයව ගැඹුරු ක්ලෝන සඳහා සහය නොදක්වයි. උපයෝගිතා ශ්‍රිතයක් භාවිතා කරන්න. උදාහරණයක් ලෙස රාම්ඩා:

http://ramdajs.com/docs/#clone


1
මෙය ක්‍රියා නොකරයි ... x බොහෝ විට x = ['ab', 'cd', ...] සඳහා
අරාවයක් වන විට එය ක්‍රියා කරයි

3
මෙය ක්‍රියාත්මක වන නමුත් මතක තබා ගන්න මෙය ෂලෝ පිටපතක්, එබැවින් වෙනත් වස්තූන් පිළිබඳ ගැඹුරු යොමු කිරීම් යොමු ලෙස පවතී!
බග්ස් බනී

අර්ධ ක්ලෝනයක් ද මේ ආකාරයෙන් සිදුවිය හැකිය:const first = {a: 'foo', b: 'bar'}; const second = {...{a} = first}
ක්‍රිස්ටියන් ට්‍රේනා

26

AngularJS භාවිතා කරන්නන් සඳහා, මෙම පුස්තකාලයේ ඇති වස්තූන් ක්ලෝන කිරීම හෝ දිගු කිරීම සඳහා සෘජු ක්‍රමයක් ද ඇත.

var destination = angular.copy(source);

හෝ

angular.copy(source, destination);

Angular.copy ප්‍රලේඛනයේ තවත් ...


2
මෙය ගැඹුරු පිටපතක් FYI.
zamnuts

23

මෙන්න ඔබට භාවිතා කළ හැකි ශ්‍රිතයක්.

function clone(obj) {
    if(obj == null || typeof(obj) != 'object')
        return obj;    
    var temp = new obj.constructor(); 
    for(var key in obj)
        temp[key] = clone(obj[key]);    
    return temp;
}

10
මෙම පිළිතුර තරමක් සමීප නමුත් නිවැරදි නොවේ. ඔබ දිනය වස්තුවක් ක්ලෝන කිරීමට උත්සාහ කරන්නේ නම්, ඔබට එම දිනයම නොලැබෙන්නේ දිනය ඉදිකිරීම්කරුගේ ශ්‍රිතයට ඇමතුම නව දිනය වත්මන් දිනය / වේලාව සමඟ ආරම්භ කරන බැවිනි. එම අගය ගණන් කළ නොහැකි අතර for / in loop මගින් පිටපත් නොකරනු ඇත.
ඒ. ලෙවී

පරිපූර්ණ නොවේ, නමුත් එම මූලික අවස්ථා සඳහා හොඳයි. උදා: මූලික වස්තුවක්, අරාවක් හෝ නූල් විය හැකි තර්කයක් සරල ක්ලෝනකරණයට ඉඩ දීම.
james_womack

භාවිතා කරමින් ඉදිකිරීම්කරු නිවැරදිව ඇමතීම සඳහා ඉහළට new. පිළිගත් පිළිතුර නැත.
GetFree

අනෙක් සියල්ල නෝඩ් මත ක්‍රියා කරයි! තවමත් ඉතිරිව ඇති යොමු සබැඳි
user956584

පුනරාවර්තන චින්තනය විශිෂ්ටයි.නමුත් වටිනාකම අරාව නම් එය ක්‍රියාත්මක වේද?
Q10Viking

23

පිළිතුර - ලෙවීගේ පිළිතුර බොහෝ දුරට සම්පූර්ණයි, මෙන්න මගේ කුඩා දායකත්වය: පුනරාවර්තන යොමු කිරීම් හැසිරවිය හැකි ක්‍රමයක් තිබේ , මෙම පේළිය බලන්න

if(this[attr]==this) copy[attr] = copy;

වස්තුව XML DOM අංගයක් නම්, අපි ඒ වෙනුවට ක්ලෝනනෝඩ් භාවිතා කළ යුතුය

if(this.cloneNode) return this.cloneNode(true);

ඒ. ලෙවීගේ පරිපූර්ණ අධ්‍යයනය සහ කැල්වින්ගේ මූලාකෘතිකරණ ප්‍රවේශය මගින් මම මෙම විසඳුම ඉදිරිපත් කරමි.

Object.prototype.clone = function() {
  if(this.cloneNode) return this.cloneNode(true);
  var copy = this instanceof Array ? [] : {};
  for(var attr in this) {
    if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
      copy[attr] = this[attr];
    else if(this[attr]==this) copy[attr] = copy;
    else copy[attr] = this[attr].clone();
  }
  return copy;
}

Date.prototype.clone = function() {
  var copy = new Date();
  copy.setTime(this.getTime());
  return copy;
}

Number.prototype.clone = 
Boolean.prototype.clone =
String.prototype.clone = function() {
  return this;
}

පිළිතුරු වල ඇන්ඩි බර්ක්ගේ සටහනද බලන්න.


3
Date.prototype.clone = function() {return new Date(+this)};
RobG

23

මෙම ලිපියෙන්: බ්‍රයන් හුයිස්මන් විසින් ජාවාස්ක්‍රිප්ට් හි අරා සහ වස්තු පිටපත් කරන්නේ කෙසේද :

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

4
මෙය සමීප නමුත් කිසිදු වස්තුවක් සඳහා ක්‍රියා නොකරයි. මේ සමඟ දින වස්තුවක් ක්ලෝන කිරීමට උත්සාහ කරන්න. සෑම ගුණාංගයක්ම ගණන් කළ නොහැකි බැවින් ඒවා සියල්ලම for / in loop හි නොපෙන්වයි.
ඒ. ලෙවී

මේ වගේ වස්තු මූලාකෘතියට එකතු කිරීම මට jQuery බිඳ දැමුවා. මම ක්ලෝන 2 ලෙස නම් කළ විට පවා.
iPadDeveloper2011

3
@ iPadDeveloper2011 ඉහත කේතයේ දෝෂයක් ඇති අතර එය '(මෙහි var i සඳහා)' වෙනුවට 'i' (මේ සඳහා) සඳහා ගෝලීය විචල්‍යයක් නිර්මාණය කළේය. මට සංස්කරණය කිරීමට අවශ්‍ය කර්මය ඇති අතර එය නිවැරදි කර එය නිවැරදි කරමි.
mikemaccana

1
Al කැල්වින්: මෙය ගණනය කළ නොහැකි දේපලක් නිර්මාණය කළ යුතුය, එසේ නොමැතිනම් 'සඳහා' ලූප සඳහා 'ක්ලෝන' දිස්වනු ඇත.
mikemaccana

2
ඇයි var copiedObj = Object.create(obj);හොඳ ක්‍රමයක් නොවන්නේ ?
ඩෑන් පී.

20

ES-6 හි ඔබට Object.assign (...) භාවිතා කළ හැකිය. උදා:

let obj = {person: 'Thor Odinson'};
let clone = Object.assign({}, obj);

හොඳ සඳහනක් මෙහි ඇත: https://googlechrome.github.io/samples/object-assign-es6/


12
එය වස්තුව ගැඹුරු ක්ලෝන නොකරයි.
අගෝස්තු

එය පැවරුමක් මිස පිටපතක් නොවේ. clone.Title = "යන්තම් ක්ලෝනයක්" යන්නෙන් අදහස් වන්නේ obj.Title = "හුදෙක් ක්ලෝනයක්" යන්නයි.
HoldOffHunger

OldHoldOffHunger ඔබ වැරදී ඇත. ඔබගේ බ්‍රව්සරයේ JS කොන්සෝලය ( let obj = {person: 'Thor Odinson'}; let clone = Object.assign({}, obj); clone.title = "Whazzup";)
බිඳවැටීම

@ කොලප්සාර්: එය හරියටම මා විසින් පරීක්ෂා කරන ලදි, එවිට console.log (පුද්ගලයා) වනුයේ "තෝර් ඔඩින්සන්" නොව "වස්අප්" ය. අගෝස්තුගේ අදහස බලන්න.
HoldOffHunger

1
OldHoldOffHunger ක්‍රෝම් 60.0.3112.113 හෝ එජ් 14.14393 හි සිදු නොවේ; ප්‍රාථමික වර්ගවල objදේපලවල අගයන් ඇත්ත වශයෙන්ම ක්ලෝන කර ඇති බැවින් අගෝස්තු ප්‍රකාශය අදාළ නොවේ . වස්තු වන දේපල අගයන් ක්ලෝන නොකෙරේ.
බිඳවැටීම

20

ECMAScript 2018 හි

let objClone = { ...obj };

බව දැනුවත් විය පිළිතුරු පැතැලිව වස්තූන් තවමත් පිටපත් පරිශීලනය.


1
කැදැලි වස්තූන් තවමත් යොමු කිරීමක් ලෙස පිටපත් කර ඇති බවට ඉඟියට ස්තූතියි! මගේ කේතය නිදොස් කිරීමේදී මට පිස්සු හැදුනේ මම "ක්ලෝනය" මත කැදැලි ගුණාංග වෙනස් කළ නමුත් මුල් පිටපත වෙනස් වූ බැවිනි.
බෙනී නියුගුබවර්

මෙය 2018 නොව ES2016 වන අතර මෙම පිළිතුර වසර දෙකකට පෙර ලබා දී ඇත.
ඩෑන් ඩස්කල්ස්කු

ඉතින් මට කැදැලි දේපලවල පිටපතක් අවශ්‍ය නම් කුමක් කළ යුතුද
සුනිල් ගාග්

1
Un සුනිල්ගාර්ග් කැදැලි දේපල පිටපත් කිරීම සඳහා ඔබට භාවිතා කළ හැකිය const objDeepClone = JSON.parse(JSON.stringify(obj));
පවන් ගාරේ

18

ලොඩාෂ් භාවිතා කිරීම:

var y = _.clone(x, true);

5
OMG ක්ලෝනකරණය නැවත සොයා ගැනීම උමතු වනු ඇත. එකම එකම පිළිතුර මෙයයි.
ඩෑන් රොස්

5
මම කැමතියි _.cloneDeep(x)එය අත්‍යවශ්‍යයෙන්ම ඉහත ආකාරයටම වන නමුත් වඩා හොඳින් කියවයි.
garbanzio

15

සරල වස්තු ක්ලෝන කිරීමට උනන්දුවක් දක්වයි:

JSON.parse(JSON.stringify(json_original));

මූලාශ්‍රය: ජාවාස්ක්‍රිප්ට් වස්තුව නව විචල්‍ය NOT වෙත යොමු කිරීමෙන් පිටපත් කරන්නේ කෙසේද?


හරිම ලස්සනයි - සරලයි.
මැට් එච්

AttMattH: මෙම පිළිතුර දැනටමත් 2012 දී ලබා දී ඇත . ඔබ එය දුටුවාද? මොහොමඩ්, ඔබ ඒවායින් එකක් අනුපිටපත් කිරීමට පෙර පවතින පිළිතුරු පරීක්ෂා කළාද?
ඩෑන් ඩස්කල්ස්කු

හොඳයි ඒක එක ක්‍රමයක්. ty කවදාවත් ඒ ගැන හිතුවේ නැහැ
1-14x0r

14

ඔබට එක් කේත පේළියක් භාවිතා කර වස්තුවක් ක්ලෝන කර පෙර සඳහන් කළ ඕනෑම සඳහනක් ඉවත් කළ හැකිය. සරලව කරන්න:

var obj1 = { text: 'moo1' };
var obj2 = Object.create(obj1); // Creates a new clone without references

obj2.text = 'moo2'; // Only updates obj2's text property

console.log(obj1, obj2); // Outputs: obj1: {text:'moo1'}, obj2: {text:'moo2'}

Object.create සඳහා දැනට සහාය නොදක්වන බ්‍රව්සර් / එන්ජින් සඳහා ඔබට මෙම පොලිෆිල් භාවිතා කළ හැකිය:

// Polyfill Object.create if it does not exist
if (!Object.create) {
    Object.create = function (o) {
        var F = function () {};
        F.prototype = o;
        return new F();
    };
}

1
+1 Object.create(...)අනිවාර්යයෙන්ම යා යුතු මාර්ගයයි.
රෙනේ නිෆෙනෙගර්

පරිපූර්ණ පිළිතුර. සමහර විට ඔබට පැහැදිලි කිරීමක් එකතු කළ Object.hasOwnPropertyහැකිද? මූලාකෘති සබැඳිය සෙවීම වළක්වා ගන්නේ කෙසේදැයි ජනතාව දනී.
froginvasion

හොඳින් ක්‍රියා කරන නමුත් පොලිෆිල් වැඩ කරන්නේ කුමන බ්‍රව්සර් වලද?
ඉයන් ලූන්

11
මෙය මූලාකෘතියක් ලෙස obj1 සමඟ obj2 නිර්මාණය කරයි. එය ක්‍රියාත්මක වන්නේ ඔබ textobj2 හි සාමාජිකයා සෙවනැල්ල කරන බැවිනි. ඔබ පිටපතක් සාදන්නේ නැත, obj2 හි සාමාජිකයෙකු හමු නොවූ විට මූලාකෘති දාමයට කල් දමන්න.
නික් ඩෙසෝල්නියර්ස්

2
මෙය "යොමු නොමැතිව" නිර්මාණය නොකරයි, එය මූලාකෘතියට යොමු කරයි. එය තවමත් යොමු කිරීමකි. දේපලක් මුල් පිටපතෙහි වෙනස් වුවහොත් "ක්ලෝන" හි ඇති මූලාකෘති දේපල වෙනස් වේ. එය කිසිසේත් ක්ලෝනයක් නොවේ.
ජිම්බෝ ජොනී

13

පැරණි ප්‍රශ්නයකට නව පිළිතුරක්! පැතිරුණු සින්ටැක්ස් සමඟ ECMAScript 2016 (ES6) භාවිතා කිරීමෙන් ඔබට සතුටක් තිබේ නම් එය පහසුය.

keepMeTheSame = {first: "Me!", second: "You!"};
cloned = {...keepMeTheSame}

මෙය වස්තුවක නොගැඹුරු පිටපතක් සඳහා පිරිසිදු ක්‍රමයක් සපයයි. ගැඹුරු පිටපතක් සෑදීම, එනම් පුනරාවර්තන ලෙස කැදැලි කරන ලද සෑම වස්තුවකම සෑම අගයකම නව පිටපතක් සාදන්න, ඉහත බරින් වැඩි විසඳුම් අවශ්‍ය වේ.

ජාවාස්ක්‍රිප්ට් දිගටම විකාශනය වෙමින් පවතී.


2
ඔබට වස්තූන් මත අර්ථ දක්වා ඇති කාර්යයන් ඇති විට එය ක්‍රියා නොකරයි
පීටර් මාරෙක්

ඈත මම පැතිර ක්රියාකරු පමණක් iterables සමග වැඩ දකින පරිදි - developer.mozilla.org පවසයි: var obj = {'key1': 'value1'}; var array = [...obj]; // TypeError: obj is not iterable
ඔලේ

Le ඔලෙහ් [... obj] වෙනුවට `{... obj use භාවිතා කරන්න;`
මනිකන්ත් ගෞතම්

@manikantgautam මම මීට පෙර Object.assign () භාවිතා කළ නමුත් දැන් ඇත්ත වශයෙන්ම වස්තු පැතිරීමේ වාක්‍ය ඛණ්ඩය නවතම Chrome, Firefox (තවමත් එජ් සහ සෆාරි වල නොමැත) සඳහා සහය දක්වයි. එහි ECMAScript යෝජනාව ... නමුත් මට පෙනෙන තාක් දුරට බාබෙල් එයට සහාය දක්වයි, එබැවින් එය භාවිතා කිරීමට ආරක්ෂිත වේ.
ඔලේ

12
let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)

දේපල වස්තුවක් නොව පන්ති නිදසුනක් ක්ලෝන කිරීමට ඔබට අවශ්‍ය නම් ES6 විසඳුම .


මෙය වෙනස් වන්නේ කෙසේද let cloned = Object.assign({}, obj) කෙසේද?
ceztko

10

මම හිතන්නේ සරල හා වැඩ කරන පිළිතුරක් තිබේ. ගැඹුරු පිටපත් කිරීමේදී කාරණා දෙකක් තිබේ:

  1. දේපල එකිනෙකාගෙන් ස්වාධීනව තබා ගන්න.
  2. ක්ලෝන කරන ලද වස්තුව මත ක්‍රම සජීවීව තබා ගන්න.

ඒ නිසා මම හිතන්නේ එක් සරල විසඳුමක් වනුයේ පළමුව අනුක්‍රමිකකරණය කිරීම සහ ආශා කිරීම සහ පසුව කාර්යයන් පිටපත් කිරීම සඳහා එය පැවරීමයි.

let deepCloned = JSON.parse(JSON.stringify(source));
let merged = Object.assign({}, source);
Object.assign(merged, deepCloned);

මෙම ප්‍රශ්නයට බොහෝ පිළිතුරු තිබුණද, මෙයද උපකාර වනු ඇතැයි මම බලාපොරොත්තු වෙමි.


මට ලොඩාෂ් ආනයනය කිරීමට අවසර තිබුණත්, මම කැමතියි ලොඩාෂ් භාවිතා කිරීමට cloneDeep.
ConductedClever

2
මම භාවිතා කරන්නේ JSON.parse (JSON.stringify (source)). සෑම විටම වැඩ කරයි.
මිෂා

2
Is මිෂා, මේ ආකාරයෙන් ඔබට කාර්යයන් මග හැරෙනු ඇත. 'ක්‍රියා' යන වචනයට බොහෝ අර්ථයන් ඇත.
ConductedClever

මා සඳහන් කළ ආකාරයට පළමු ස්ථරයේ කාර්යයන් පමණක් පිටපත් කරනු ඇති බව මතක තබා ගන්න. එබැවින් අපට එකිනෙකා තුළ යම් වස්තූන් තිබේ නම්, එකම ක්‍රමය ක්ෂේත්‍රය අනුව ක්ෂේත්‍රය පුනරාවර්තනය කිරීමයි.
ConductedClever

9

ගැඹුරු පිටපතක් සහ ක්ලෝනයක් සඳහා, JSON.stringify ඉන්පසු JSON.parse වස්තුව:

obj = { a: 0 , b: { c: 0}};
let deepClone = JSON.parse(JSON.stringify(obj));
obj.a = 5;
obj.b.c = 5;
console.log(JSON.stringify(deepClone)); // { a: 0, b: { c: 0}}

ඉතා දක්ෂයි ... මෙම ප්‍රවේශයට යම් අවාසියක් තිබේද?
ඇලෙක්ස්

8

මෙය ශ්‍රිතවල ක්ලෝනකරණය සහ බහු / චක්‍රීය යොමු කිරීම් හැසිරවීමට A. ලෙවීගේ කේතයේ අනුවර්තනයකි - මෙයින් අදහස් කරන්නේ ක්ලෝන කරන ලද ගසෙහි ඇති ගුණාංග දෙකක් එකම වස්තුවක යොමු නම්, ක්ලෝන කරන ලද වස්තු ගස මේවා ඇති බවයි ගුණාංග යොමු කරන ලද වස්තුවෙහි එකම හා එකම ක්ලෝනයට යොමු වේ. මෙය ද චක්‍රීය පරායත්තතාවයන් නිරාකරණය කරයි. ඇල්ගොරිතමයේ සංකීර්ණත්වය O (n) වේ

function clone(obj){
    var clonedObjectsArray = [];
    var originalObjectsArray = []; //used to remove the unique ids when finished
    var next_objid = 0;

    function objectId(obj) {
        if (obj == null) return null;
        if (obj.__obj_id == undefined){
            obj.__obj_id = next_objid++;
            originalObjectsArray[obj.__obj_id] = obj;
        }
        return obj.__obj_id;
    }

    function cloneRecursive(obj) {
        if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj;

        // Handle Date
        if (obj instanceof Date) {
            var copy = new Date();
            copy.setTime(obj.getTime());
            return copy;
        }

        // Handle Array
        if (obj instanceof Array) {
            var copy = [];
            for (var i = 0; i < obj.length; ++i) {
                copy[i] = cloneRecursive(obj[i]);
            }
            return copy;
        }

        // Handle Object
        if (obj instanceof Object) {
            if (clonedObjectsArray[objectId(obj)] != undefined)
                return clonedObjectsArray[objectId(obj)];

            var copy;
            if (obj instanceof Function)//Handle Function
                copy = function(){return obj.apply(this, arguments);};
            else
                copy = {};

            clonedObjectsArray[objectId(obj)] = copy;

            for (var attr in obj)
                if (attr != "__obj_id" && obj.hasOwnProperty(attr))
                    copy[attr] = cloneRecursive(obj[attr]);                 

            return copy;
        }       


        throw new Error("Unable to copy obj! Its type isn't supported.");
    }
    var cloneObj = cloneRecursive(obj);



    //remove the unique ids
    for (var i = 0; i < originalObjectsArray.length; i++)
    {
        delete originalObjectsArray[i].__obj_id;
    };

    return cloneObj;
}

සමහර ඉක්මන් පරීක්ෂණ

var auxobj = {
    prop1 : "prop1 aux val", 
    prop2 : ["prop2 item1", "prop2 item2"]
    };

var obj = new Object();
obj.prop1 = "prop1_value";
obj.prop2 = [auxobj, auxobj, "some extra val", undefined];
obj.nr = 3465;
obj.bool = true;

obj.f1 = function (){
    this.prop1 = "prop1 val changed by f1";
};

objclone = clone(obj);

//some tests i've made
console.log("test number, boolean and string cloning: " + (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool));

objclone.f1();
console.log("test function cloning 1: " + (objclone.prop1 == 'prop1 val changed by f1'));
objclone.f1.prop = 'some prop';
console.log("test function cloning 2: " + (obj.f1.prop == undefined));

objclone.prop2[0].prop1 = "prop1 aux val NEW";
console.log("test multiple references cloning 1: " + (objclone.prop2[1].prop1 == objclone.prop2[0].prop1));
console.log("test multiple references cloning 2: " + (objclone.prop2[1].prop1 != obj.prop2[0].prop1));

1
2016 සැප්තැම්බර් වන විට, ප්‍රශ්නයට ඇති එකම නිවැරදි විසඳුම මෙයයි.
DomQ

6

මට අවශ්‍ය වූයේ සියල්ලටම එකතු කිරීමයි Object.create මෙම ලිපියේ විසඳුම් , මෙය nodejs සමඟ අපේක්ෂිත ආකාරයෙන් ක්‍රියා නොකරයි.

ෆයර්ෆොක්ස් හි ප්‍රති result ලය

var a = {"test":"test"};
var b = Object.create(a);
console.log(b);´

වේ

{test:"test"}.

නෝඩ්ජස් වල එය එසේ ය

{}

මෙය මූලාකෘති උරුමය මිස ක්ලෝන කිරීම නොවේ.
d13

1
13 d13 ඔබේ තර්කය වලංගු වන අතර, වස්තුවක් ක්ලෝන කිරීමට ජාවාස්ක්‍රිප්ට්හි ප්‍රමිතිගත ක්‍රමයක් නොමැති බව සලකන්න. මෙය මූලාකෘති උරුමයකි, නමුත් ඔබ සංකල්ප තේරුම් ගන්නේ නම් එය ක්ලෝන ලෙස භාවිතා කළ හැකිය.
froginvasion

rofroginvasion. Object.create භාවිතා කිරීමේ ඇති එකම ගැටළුව වන්නේ කූඩු කරන ලද වස්තූන් සහ අරා යනු මූලාකෘතියේ කැදැලි වස්තු සහ අරා පිළිබඳ දර්ශක යොමු කිරීම් පමණි. jsbin.com/EKivInO/2/edit?js,console . තාක්ෂණික වශයෙන් “ක්ලෝන කරන ලද” වස්තුවකට එහි අද්විතීය ගුණාංග තිබිය යුතු අතර එය වෙනත් වස්තූන්ගේ ගුණාංග පිළිබඳ බෙදා නොගත් ඒවා වේ.
d13

13 d13 හරි, මම දැන් ඔබේ අදහස දකිමි. නමුත් මා අදහස් කළේ බොහෝ අය මූලාකෘති උරුමය පිළිබඳ සංකල්පය සමඟ en ත් වී ඇති අතර එය ක්‍රියාත්මක වන ආකාරය ඉගෙන ගැනීමට මා අසමත් වීමයි. මා වරදවා වටහා නොගත්තොත්, Object.hasOwnPropertyඔබ සතුව අරාව අයිතිද නැද්ද යන්න පරීක්ෂා කිරීමට ඇමතීමෙන් ඔබේ උදාහරණය නිවැරදි කළ හැකිය . ඔව්, මෙය මූලාකෘති උරුමය සමඟ කටයුතු කිරීමට අමතර සංකීර්ණතාවයක් එක් කරයි.
froginvasion

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

2
if(!src && typeof src != "object"){. මම විය යුතුයි කියලා ||නැහැ &&.
මයික්

6

ක්ලෝන කළ යුතු වස්තුව 'වචනානුසාරයෙන් සාදන ලද' වස්තුවක් බව මනසින් ප්‍රකාශ කර ඇති හෙයින් , විසඳුමක් වනුයේ වස්තුවක උදාහරණයක් ක්ලෝන කරනවාට වඩා කිහිප වතාවක් වස්තුව උත්පාදනය කිරීමයි:

function createMyObject()
{
    var myObject =
    {
        ...
    };
    return myObject;
}

var myObjectInstance1 = createMyObject();
var myObjectInstance2 = createMyObject();

6

මම මගේම ක්‍රියාත්මක කිරීම ලියා ඇත. එය වඩා හොඳ විසඳුමක් ලෙස සලකන්නේ දැයි විශ්වාස නැත:

/*
    a function for deep cloning objects that contains other nested objects and circular structures.
    objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object.
                                    index (z)
                                         |
                                         |
                                         |
                                         |
                                         |
                                         |                      depth (x)
                                         |_ _ _ _ _ _ _ _ _ _ _ _
                                        /_/_/_/_/_/_/_/_/_/
                                       /_/_/_/_/_/_/_/_/_/
                                      /_/_/_/_/_/_/...../
                                     /................./
                                    /.....            /
                                   /                 /
                                  /------------------
            object length (y)    /
*/

ක්‍රියාත්මක කිරීම පහත දැක්වේ:

function deepClone(obj) {
    var depth = -1;
    var arr = [];
    return clone(obj, arr, depth);
}

/**
 *
 * @param obj source object
 * @param arr 3D array to store the references to objects
 * @param depth depth of the current object relative to the passed 'obj'
 * @returns {*}
 */
function clone(obj, arr, depth){
    if (typeof obj !== "object") {
        return obj;
    }

    var length = Object.keys(obj).length; // native method to get the number of properties in 'obj'

    var result = Object.create(Object.getPrototypeOf(obj)); // inherit the prototype of the original object
    if(result instanceof Array){
        result.length = length;
    }

    depth++; // depth is increased because we entered an object here

    arr[depth] = []; // this is the x-axis, each index here is the depth
    arr[depth][length] = []; // this is the y-axis, each index is the length of the object (aka number of props)
    // start the depth at current and go down, cyclic structures won't form on depths more than the current one
    for(var x = depth; x >= 0; x--){
        // loop only if the array at this depth and length already have elements
        if(arr[x][length]){
            for(var index = 0; index < arr[x][length].length; index++){
                if(obj === arr[x][length][index]){
                    return obj;
                }
            }
        }
    }

    arr[depth][length].push(obj); // store the object in the array at the current depth and length
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) result[prop] = clone(obj[prop], arr, depth);
    }

    return result;
}

මගේ නඩුව ටිකක් සංකීර්ණ වුවත් මගේ වස්තුව සඳහා වැඩ නොකරයි.
සජුක්
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.