ජාවාස්ක්‍රිප්ට් හි ඇති වස්තුවක් ගැඹුරු ක්ලෝන කිරීමට වඩාත්ම කාර්යක්ෂම ක්‍රමය කුමක්ද?


5180

ජාවාස්ක්‍රිප්ට් වස්තුවක් ක්ලෝන කිරීමට වඩාත්ම කාර්යක්ෂම ක්‍රමය කුමක්ද? මම දැකලා තියෙනවාobj = eval(uneval(o)); , නමුත් එය සම්මත නොවන අතර ෆයර්ෆොක්ස් පමණක් සහාය දක්වයි .

මම obj = JSON.parse(JSON.stringify(o));කාර්යක්ෂමතාව ගැන ප්‍රශ්න කරනවා වගේ දේවල් කළා .

විවිධ අඩුපාඩු සහිත පුනරාවර්තන පිටපත් කිරීමේ කාර්යයන් ද මම දැක ඇත්තෙමි.
මට පුදුමයි කැනොනිකල් විසඳුමක් නැති බව.


566
ඊවාල් නපුරක් නොවේ. Eval දුර්වල ලෙස භාවිතා කිරීම. එහි අතුරු ආබාධ ගැන ඔබ බිය වන්නේ නම් ඔබ එය වැරදි ලෙස භාවිතා කරයි. ඔබ බිය වන අතුරු ආබාධ එය භාවිතා කිරීමට හේතු වේ. ඔබේ ප්‍රශ්නයට කිසිවෙකු පිළිතුරු දී තිබේද?
ජේම්ස්

15
වස්තූන් ක්ලෝන කිරීම යනු අත්තනෝමතික එකතු කිරීම්වල අභිරුචි වස්තු සමඟ උපායශීලී ව්‍යාපාරයකි. බොහෝ විට එය කිරීමට පිටතින් ක්‍රමයක් නොමැති වීමට හේතුව එයයි.
b01

12
eval()සාමාන්‍යයෙන් නරක අදහසක් වන්නේ බොහෝ ජාවාස්ක්‍රිප්ට් එන්ජින්වල ප්‍රශස්තකරණය මඟින් විචල්‍යයන් සමඟ කටයුතු කිරීමේදී ක්‍රියා විරහිත කළ යුතුeval බැවිනි. යන්තම් ඇති eval()ඔබගේ කේතය බෙහෙවින් නරක අතට කාර්ය සාධන ඇති විය හැක.
user56reinstatemonica8


12
මෙම JSONක්‍රමය JSON හි සමාන නොවන ඕනෑම ජාවාස්ක්‍රිප්ට් වර්ගයක් නැති කරන බව සලකන්න . උදාහරණයක් ලෙස: JSON.parse(JSON.stringify({a:null,b:NaN,c:Infinity,d:undefined,e:function(){},f:Number,g:false}))ජනනය කරනු ඇත{a: null, b: null, c: null, g: false}
ඔරියඩම්

Answers:


4731

දේශීය ගැඹුරු ක්ලෝනකරණය

එය "ව්‍යුහාත්මක ක්ලෝනකරණය" ලෙස හැඳින්වේ, 11 වන සහ පසුව පර්යේෂණාත්මකව ක්‍රියා කරයි. මෙම පිළිතුර බලන්න වැඩි විස්තර සඳහා.

දත්ත නැතිවීම සමඟ වේගයෙන් ක්ලෝන කිරීම - JSON.parse / stringify

ඔබ භාවිතා නොකරන කරන්නේ නම් Dates, කාර්යයන්, undefined, Infinityගැඹුරු පරිගණක ක්රිඩාවට සමාන කිරීමට, RegExps, සිතියම්, කට්ටල, Blobs, FileLists, ImageDatas, විරල අරා, කළ හැකි පරිඝණක අරා හෝ ඔබේ වස්තුව තුළ අනෙකුත් සංකීර්ණ වර්ග, ඉතා සරල එක් නෞකාවක් වස්තුවක්:

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'
  re: /.*/,  // lost
}
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()

කෝබන්ගේ පිළිතුර බලන්නමිණුම් සලකුණු සඳහා .

පුස්තකාලයක් භාවිතා කරමින් විශ්වසනීය ක්ලෝනකරණය

වස්තූන් ක්ලෝන කිරීම සුළුපටු නොවන බැවින් (සංකීර්ණ වර්ග, රවුම් යොමු, ශ්‍රිතය ආදිය), බොහෝ ප්‍රධාන පුස්තකාල ක්ලෝන වස්තු සඳහා ක්‍රියාකාරීත්වය සපයයි. රෝදය ප්‍රතිනිර්මාණය නොකරන්න - ඔබ දැනටමත් පුස්තකාලයක් භාවිතා කරන්නේ නම්, එයට වස්තු ක්ලෝනකරණ ශ්‍රිතයක් තිබේදැයි පරීක්ෂා කරන්න. උදාහරණයක් වශයෙන්,

  • lodash - cloneDeep; lodash.clonedeep හරහා වෙන වෙනම ආනයනය කළ හැකිය මොඩියුලය අතර ගැඹුරු ක්ලෝනකරණ ශ්‍රිතයක් සපයන පුස්තකාලයක් ඔබ දැනටමත් භාවිතා නොකරන්නේ නම් ඔබේ හොඳම තේරීම විය හැකිය.
  • AngularJS - angular.copy
  • jQuery - jQuery.extend(true, { }, oldObject); .clone()ක්ලෝන DOM මූලද්‍රව්‍ය පමණි

ES6

සම්පූර්ණත්වය සඳහා, ES6 නොගැඹුරු පිටපත් යාන්ත්‍රණ දෙකක් ඉදිරිපත් කරන බව සලකන්න: Object.assign()සහ පැතිරීමේ සින්ටැක්ස් . එමඟින් එක් වස්තුවක සිට තවත් වස්තුවකට ගණනය කළ හැකි සියලු දේපලවල අගයන් පිටපත් කරයි. උදාහරණයක් වශයෙන්:

var A1 = {a: "2"};
var A2 = Object.assign({}, A1);
var A3 = {...A1};  // Spread Syntax

7
6ThiefMaster github.com/jquery/jquery/blob/master/src/core.js 276 වන පේළියේ (වෙනත් යමක් කරන කේතයක් ඇත, නමුත් "JS හි මෙය කරන්නේ කෙසේද" යන කේතය තිබේ :)
රූන් එෆ්එස්

7
උනන්දුවක් දක්වන ඕනෑම කෙනෙකුට jQuery ගැඹුරු පිටපත පිටුපස ඇති JS කේතය මෙන්න: github.com/jquery/jquery/blob/master/src/core.js#L265-327
ඇලෙක්ස් ඩබ්ලිව්

194
වෝ! ඉතා පැහැදිලිව කිවහොත් : මෙම ප්‍රතිචාරය නිවැරදි පිළිතුර ලෙස තෝරාගත්තේ මන්දැයි නොදැන, මෙය පහත දැක්වෙන ප්‍රතිචාර වලට පිළිතුරක් විය: stackoverflow.com/a/122190/6524 (එය නිර්දේශ කරමින් .clone()සිටි අතර එය නිවැරදි කේතය නොවේ මෙම සන්දර්භය තුළ භාවිතා කිරීම). අවාසනාවට මෙම ප්‍රශ්නය බොහෝ සංශෝධන හරහා ගොස් ඇති අතර මුල් සාකච්ඡාව තවදුරටත් නොපෙනේ! කරුණාකර කෝබන්ගේ උපදෙස් පිළිපදින්න, ඔබ වේගය ගැන සැලකිලිමත් වන්නේ නම්, ලූපයක් ලියන්න හෝ ගුණාංග සෘජුවම නව වස්තුවකට පිටපත් කරන්න. නැතහොත් එය ඔබම අත්හදා බලන්න!
ජෝන් රෙසිග්

9
මෙය ජාවාස්ක්‍රිප්ට් ප්‍රශ්නයකි (jQuery ගැන සඳහනක් නැත).
gphilip

60
JQuery භාවිතා නොකර යමෙක් මෙය කරන්නේ කෙසේද?
නියමයි 01

2266

මෙම මිණුම් ලකුණ පරීක්ෂා කරන්න: http://jsben.ch/#/bWfk9

මගේ පෙර පරීක්ෂණ වලදී වේගය ප්‍රධාන වශයෙන් සැලකිලිමත් විය

JSON.parse(JSON.stringify(obj))

වස්තුවක් ගැඹුරු ක්ලෝන කිරීමට ඇති මන්දගාමී ක්‍රමය වීම (එය jQuery.extend ට වඩා මන්දගාමී වේ සමග deepධජය 10-20% කින් සැබෑ කර).

jQuery.extend ඉතා වේගවත් වේ deepධජය false(නොගැඹුරු ක්ලෝන) ලෙස සකසා ඇති වේ . එය හොඳ විකල්පයකි, මන්ද එය වර්ග වලංගු කිරීම සඳහා අමතර තර්කනයක් ඇතුළත් වන අතර නිර්වචනය නොකළ ගුණාංග ආදිය පිටපත් නොකෙරේ, නමුත් මෙයද ඔබව ටිකක් මන්දගාමී කරනු ඇත.

ඔබ ක්ලෝන කිරීමට උත්සාහ කරන වස්තූන්ගේ ව්‍යුහය ඔබ දන්නේ නම් හෝ ගැඹුරු කැදැලි අරා වළක්වා ගත හැකිය for (var i in obj) hasOwnProperty පරික්ෂා කිරීමේදී ඔබේ වස්තුව ක්ලෝන කිරීම ලූපයක් අතර එය jQuery වලට වඩා වේගවත් වනු ඇත.

අවසාන වශයෙන් ඔබ දන්නා වස්තු ව්‍යුහයක් උණුසුම් පුඩුවක් තුළ ක්ලෝන කිරීමට උත්සාහ කරන්නේ නම්, ක්ලෝන ක්‍රියාපටිපාටිය සරලව සකස් කර වස්තුව අතින් තැනීමෙන් ඔබට බොහෝ කාර්ය සාධනය ලබා ගත හැකිය.

ජාවාස්ක්‍රිප්ට් for..inට්‍රේස් එන්ජින් ලූප ප්‍රශස්තිකරණයට හසු වන අතර hasOwnProperty පරික්ෂා කිරීමද ඔබගේ වේගය අඩු කරයි. වේගය අත්‍යවශ්‍ය වන විට අතින් ක්ලෝන කරන්න.

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

වස්තූන් JSON.parse(JSON.stringify(obj))මත ඇති ක්‍රමය භාවිතා කිරීමෙන් පරිස්සම් වන්න Date- JSON.stringify(new Date())අයිඑස්ඕ ආකෘතියෙන් දිනයෙහි තන්තු නිරූපණයක් ලබා දෙයි, එය නැවත වස්තුවක් බවට පරිවර්තනය JSON.parse() නොවේDate . වැඩි විස්තර සඳහා මෙම පිළිතුර බලන්න .

මීට අමතරව, ක්‍රෝම් 65 හි අවම වශයෙන් ස්වදේශික ක්ලෝනකරණය යා යුතු මාර්ගය නොවන බව කරුණාවෙන් සලකන්න. JSPerf ට අනුව, නව කාර්යයක් නිර්මාණය කිරීමෙන් ස්වදේශික ක්ලෝනකරණය සිදු කිරීම JSON.stringify භාවිතා කිරීමට වඩා 800x කට වඩා මන්දගාමී වේ.

ES6 සඳහා යාවත්කාලීන කරන්න

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

Object.assign({}, obj);

4
rytrysis Object.create වස්තුව ක්ලෝන කිරීම නොවේ, මූලාකෘති වස්තුව භාවිතා කරයි ... jsfiddle.net/rahpuser/yufzc1jt/2
rahpuser

105
මෙම ක්‍රමය keysඔබගේ ද ඉවත් කරයිobjectfunctions අගයන්ගෙන් ඇති ඒවා , මන්ද එය JSONකාර්යයන් සඳහා සහාය නොදක්වයි.
කාර්ලන් කිෂ්මිරියන්

39
JSON.parse(JSON.stringify(obj))දිනය වස්තු භාවිතා කිරීම ISO8601 ආකෘතියේ නූල් නිරූපණයෙන් දිනය යූටීසී බවට පරිවර්තනය කරන බව මතක තබා ගන්න .
dnlgmzddr

31
JSON ප්‍රවේශය රවුම් යොමු කිරීම් ද යටපත් කරයි.
පොහොසත් රිමර්

28
@velop, Object.assign ({}, objToClone) එය නොගැඹුරු ක්ලෝනයක් කරන බවක් පෙනේ - dev මෙවලම් කොන්සෝලය තුළ සෙල්ලම් කරමින් සිටියදී එය භාවිතා කරමින්, වස්තු ක්ලෝනය තවමත් ක්ලෝන කරන ලද වස්තුව පිළිබඳ සඳහනකට යොමු කරයි. එබැවින් එය මෙහි සැබවින්ම අදාළ යැයි මම නොසිතමි.
ගැරට් සිම්සන්

473

ඔබට ඇත්තේ විචල්‍යයන් පමණක් බවත් ඔබේ වස්තුවේ කිසිදු කාර්යයක් නොමැති බවත් උපකල්පනය කිරීමෙන් ඔබට භාවිතා කළ හැක්කේ:

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

86
මම දැන් සොයාගෙන ඇති පරිදි මෙම ප්‍රවේශයේ හරය නම්, ඔබේ වස්තුවට කිසියම් ක්‍රියාකාරිත්වයක් තිබේ නම් (මගේ අභ්‍යන්තර ලබා ගන්නන් සහ සැකසුම් කරුවන් සිටී නම්) ඒවා තද කළ විට නැති වී යයි .. එපමණක් නම් ඔබට අවශ්‍ය නම් මෙම ක්‍රමය හොඳයි ..
මාර්කිව්

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

35
JSON.stringify({key: undefined}) //=> "{}"
Web_Designer

32
මෙම තාක්‍ෂණය මඟින් Dateවස්තුව තුළ ගබඩා කර ඇති සියලුම වස්තූන් ද විනාශ වන අතර ඒවා නූල් ස්වරූපයට පරිවර්තනය වේ.
fstab

13
JSON පිරිවිතරයේ ( json.org ) කොටසක් නොවන කිසිවක් පිටපත් කිරීමට එය අසමත් වනු ඇත
cdmckay

397

ව්‍යුහගත ක්ලෝනකරණය

HTML ප්‍රමිතියට අභ්‍යන්තර ව්‍යුහගත ක්ලෝනකරණය / අනුක්‍රමිකකරණ ඇල්ගොරිතම ඇතුළත් වේ එමඟින් වස්තූන්ගේ ගැඹුරු ක්ලෝන නිර්මාණය කළ හැකිය. එය තවමත් ඇතැම් බිල්ට් වර්ග වලට සීමා වී ඇත, නමුත් JSON විසින් සහය දක්වන වර්ග කිහිපයකට අමතරව එය දින, රෙජෙක්ස්, සිතියම්, කට්ටල, බ්ලොබ්, ගොනු ලැයිස්තු, රූප දත්ත, විරල අරා, ටයිප් කළ අරා සහ අනාගතයේ දී තවත් බොහෝ දේ සඳහා සහය දක්වයි. . එය ක්ලෝන කරන ලද දත්ත තුළ ඇති යොමු කිරීම් ද ආරක්ෂා කරයි, එමඟින් JSON සඳහා දෝෂ ඇති විය හැකි චක්‍රීය හා පුනරාවර්තන ව්‍යුහයන්ට සහාය වීමට ඉඩ සලසයි.

Node.js හි සහාය: පර්යේෂණාත්මක

v8Node.js හි මොඩියුලය දැනට (Node 11 වන විට) ව්‍යුහාත්මක අනුක්‍රමික API සෘජුවම නිරාවරණය කරයි , නමුත් මෙම ක්‍රියාකාරිත්වය තවමත් "පර්යේෂණාත්මක" ලෙස සලකුණු කර ඇති අතර අනාගත අනුවාදවල වෙනස් කිරීමට හෝ ඉවත් කිරීමට යටත් වේ. ඔබ අනුකූල අනුවාදයක් භාවිතා කරන්නේ නම්, වස්තුවක් ක්ලෝන කිරීම තරම් සරල ය:

const v8 = require('v8');

const structuredClone = obj => {
  return v8.deserialize(v8.serialize(obj));
};

බ්‍රව්සර්වල Support ජු සහාය: සමහර විට අවසානයේ? 😐

ව්‍යුහාත්මක ක්ලෝනින් ඇල්ගොරිතම සඳහා බ්‍රව්සර් දැනට සෘජු අතුරු මුහුණතක් සපයන්නේ නැත, නමුත් ගෝලීය structuredClone()ශ්‍රිතයක් GitHub හි whatwg / html # 793 හි සාකච්ඡා කර ඇත . දැනට යෝජනා කර ඇති පරිදි, බොහෝ අරමුණු සඳහා එය භාවිතා කිරීම තරම් සරල වනු ඇත:

const clone = structuredClone(original);

මෙය නැව්ගත නොකරන්නේ නම්, බ්‍රව්සර්වල ව්‍යුහගත ක්ලෝන ක්‍රියාත්මක කිරීම නිරාවරණය වන්නේ වක්‍රව පමණි.

අසමමුහුර්ත ක්‍රියාකාරිත්වය: භාවිතා කළ හැකිය. 😕

පවත්නා ඒපීඅයි සමඟ ව්‍යුහාත්මක ක්ලෝනයක් නිර්මාණය කිරීම සඳහා පහළ මට්ටමේ ක්‍රමය වන්නේ පණිවුඩ චැනල්වල එක් වරායක් හරහා දත්ත පළ කිරීමයි . අනෙක් වරාය messageඅමුණා ඇති ව්‍යුහාත්මක ක්ලෝනයක් සහිත සිදුවීමක් විමෝචනය කරයි .data. අවාසනාවකට මෙන්, මෙම සිදුවීම් වලට ඇහුම්කන් දීම අනිවාර්යයෙන්ම අසමමුහුර්ත වන අතර සමමුහුර්ත විකල්ප අඩු ප්‍රායෝගික වේ.

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

උදාහරණ භාවිතය:

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

සමමුහුර්ත වැඩකිරීම්: භයානකයි! 🤢

ව්යුහාත්මක ක්ලෝන සමමුහුර්තව නිර්මාණය කිරීම සඳහා හොඳ විකල්ප නොමැත. මෙන්න ඒ වෙනුවට ප්‍රායෝගික නොවන හක්ක කිහිපයක්.

history.pushState()හා history.replaceState()ඔවුන්ගේ පළමු තර්කය ව්යුහගත පරිගණක ක්රිඩාවට සමාන, සෑදීමට සහ එම අගය නියම දෙකම history.state. මෙවැනි ඕනෑම වස්තුවක ව්‍යුහාත්මක ක්ලෝනයක් නිර්මාණය කිරීමට ඔබට මෙය භාවිතා කළ හැකිය:

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

උදාහරණ භාවිතය:

සමමුහුර්ත වුවද මෙය අතිශයින් මන්දගාමී විය හැකිය. එය බ්‍රව්සර් ඉතිහාසය හැසිරවීම හා සම්බන්ධ සියලු පොදු කාර්යයන්ට යටත් වේ. මෙම ක්‍රමය නැවත නැවත ඇමතීමෙන් ක්‍රෝම් තාවකාලිකව ප්‍රතිචාර නොදක්වයි.

මෙම Notificationඉදිකිරීමටත් එයට සම්බන්ධිත දත්ත ව්යුහගත පරිගණක ක්රිඩාවට සමාන නිර්මාණය කරයි. එය පරිශීලකයාට බ්‍රව්සර් දැනුම්දීමක් ප්‍රදර්ශනය කිරීමට ද උත්සාහ කරයි, නමුත් ඔබ දැනුම් දීමේ අවසරය ඉල්ලා නොමැති නම් මෙය නිහ ly ව අසාර්ථක වනු ඇත. ඔබට වෙනත් අරමුණු සඳහා අවසර තිබේ නම්, අපි වහාම නිර්මාණය කළ දැනුම්දීම වසා දමමු.

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

උදාහරණ භාවිතය:


3
@rynah මම නැවත පිරිවිතර දෙස බැලුවෙමි, ඔබ නිවැරදියි: history.pushState()සහ history.replaceState()ක්‍රම දෙකම history.stateඔවුන්ගේ පළමු තර්කයේ ව්‍යුහාත්මක ක්ලෝනයකට සමමුහුර්තව සකසා ඇත. ටිකක් අමුතුයි, නමුත් එය ක්රියා කරයි. මම දැන් මගේ පිළිතුර යාවත්කාලීන කරමි.
ජෙරමි බෑන්ක්ස්

40
මෙය එතරම්ම වැරදියි! එම API එක මේ ආකාරයෙන් භාවිතා කිරීමට අදහස් නොකෙරේ.
ෆාර්ඩින් කේ.

209
ෆයර්ෆොක්ස් හි පුෂ් ස්ටේට් ක්‍රියාත්මක කළ පුද්ගලයා ලෙස, මෙම අනවසරයෙන් මට ආඩම්බරයක් හා පිළිකුලක් දැනේ. හොඳයි, යාලුවනේ.
ජස්ටින් එල්.

Function
Shishir Arora

323

බිල්ඩින් එකක් නොතිබුනේ නම්, ඔබට උත්සාහ කළ හැකිය:

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

20
JQuery විසඳුම DOM මූලද්‍රව්‍ය සඳහා ක්‍රියා කරනු ඇති නමුත් ඕනෑම වස්තුවකට පමණක් නොවේ. මූටූල් වලට එකම සීමාවක් ඇත. ඕනෑම වස්තුවක් සඳහා ඔවුන්ට සාමාන්‍ය “ක්ලෝනයක්” තිබුනේ නම් ... පුනරාවර්තන විසඳුම ඕනෑම දෙයක් සඳහා ක්‍රියා කළ යුතුය. එය බොහෝ විට යා යුතු මාර්ගයයි.
jschrab

5
ක්ලෝන කරන ලද වස්තුවට පරාමිතීන් අවශ්‍ය වන ඉදිකිරීම්කරුවෙකු සිටී නම් මෙම ශ්‍රිතය කැඩී යයි. අපට එය "var temp = new Object ()" ලෙස වෙනස් කළ හැකි බව පෙනේ, එය සෑම අවස්ථාවකම ක්‍රියාත්මක වී තිබේද?
ඇන්ඩ rew ආර්නට්

3
ඇන්ඩ rew, ඔබ එය var temp = new Object () ලෙස වෙනස් කළහොත්, ඔබේ ක්ලෝනයට මුල් වස්තුවට සමාන මූලාකෘතියක් නොමැත. භාවිතා කිරීමට උත්සාහ කරන්න: 'var newProto = ශ්‍රිතය () {}; newProto.prototype = obj.constructor; var temp = නව නව ප්‍රොටෝ (); '
ලිම්ස්කෝඩර්

1
ලිම්ස්කෝඩර්ගේ පිළිතුරට සමානව, ඉදිකිරීම්කරු අමතන්නේ
Matt Browne

3
උප කොටස් (එනම්, වස්තු ජාල) වෙත යොමු වන වස්තු සඳහා, මෙය ක්‍රියා නොකරයි: යොමු දෙකක් එකම උප වස්තුවකට යොමු කරන්නේ නම්, පිටපතෙහි එහි වෙනස් පිටපත් දෙකක් අඩංගු වේ. පුනරාවර්තන යොමු කිරීම් තිබේ නම්, ශ්‍රිතය කිසි විටෙකත් අවසන් නොවේ (හොඳයි, අවම වශයෙන් ඔබට අවශ්‍ය ආකාරයට නොවේ :-) මෙම සාමාන්‍ය අවස්ථා සඳහා, ඔබ දැනටමත් පිටපත් කර ඇති වස්තූන්ගේ ශබ්ද කෝෂයක් එක් කළ යුතු අතර, ඔබ එය දැනටමත් පිටපත් කර ඇත්දැයි පරීක්ෂා කරන්න. ... ඔබ සරල භාෂාවක් භාවිතා කරන විට ක්‍රමලේඛනය සංකීර්ණ වේ
අතථ්‍යනොබි

153

එක් කේත පේළියක ඇති වස්තුවක් ක්ලෝන කිරීමට (ගැඹුරු ක්ලෝන නොවේ) කාර්යක්ෂම ක්‍රමය

ඇන් 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;
    }
  });
}

82
මෙය පුනරාවර්තන ලෙස පිටපත් නොකරන බැවින් වස්තුවක් ක්ලෝන කිරීමේ ගැටලුවට විසඳුමක් ලබා නොදේ.
mwhite

5
මෙම ක්‍රමය ක්‍රියාත්මක වූ අතර, මම කිහිපයක් පරීක්‍ෂා කළද, _.extend ({}, (obj)) වේගවත්ම වේ: JSON.parse ට වඩා 20x වේගවත් සහ Object.assign ට වඩා 60% වේගවත්, උදාහරණයක් ලෙස. එය සියළුම උප වස්තු හොඳින් පිටපත් කරයි.
නිකෝ

11
wmwhite ක්ලෝන සහ ගැඹුරු ක්ලෝන අතර වෙනසක් ඇත. මෙම පිළිතුර ඇත්ත වශයෙන්ම ක්ලෝන කරයි, නමුත් එය ගැඹුරු ක්ලෝන නොවේ.
මීරියන් හියුස්

57
දෘෂ්ටි කෝණයෙන් ගැඹුරු ක්ලෝනයක් ඉල්ලා සිටියේය. මෙය ගැඹුරු ක්ලෝනයක් නොකරයි.
user566245

9
මෙම ක්‍රමය මඟින් SHALLOW පිටපතක් සාදනු ඇත , නමුත් DEEP පිටපතක් නොවේ ! මේ නිසා එය සම්පූර්ණයෙන්ම වැරදි පිළිතුරකි !
භාරත

97

කේතය:

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

පරීක්ෂණය:

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

3
කුමක් ගැන var obj = {}සහobj.a = obj
නියුමුසික්

5
මට මෙම ක්‍රියාව තේරෙන්නේ නැත. සිතන්න from.constructorවේ Dateඋදාහරණයක්. if2 වන ifපරීක්ෂණය සාර්ථක වූ විට සහ ශ්‍රිතය නැවත පැමිණීමට (එතැන් සිට Date != Object && Date != Array) තුන්වන පරීක්ෂණයට ළඟා වන්නේ කෙසේද?
ඇඩම් මැකී

1
DAdamMcKee ජාවාස්ක්‍රිප්ට් පරාමිතිය සම්මත කිරීම සහ විචල්‍ය පැවරුම උපක්‍රමශීලී නිසා . මෙම ප්‍රවේශය දින වකවානු ඇතුළුව (සැබවින්ම දෙවන පරීක්ෂණය මගින් හසුරුවනු ලැබේ) - මෙහි පරීක්ෂා කිරීමට ප්‍රහේලිකාව : jsfiddle.net/zqv9q9c6 .
බ්‍රිචින්ස්

1
IckNickSweeting: උත්සාහ කරන්න - එය ක්‍රියාත්මක විය හැකිය. එසේ නොවේ නම් - එය නිවැරදි කර පිළිතුර යාවත්කාලීන කරන්න. ප්‍රජාව තුළ එය ක්‍රියාත්මක වන්නේ
එලෙසිනි

1
මෙම ශ්‍රිතය පරීක්ෂණයෙහි රීජෙක්ස් ක්ලෝන නොකරයි, "from.constructor! = Object && from.constructor! = Array" යන කොන්දේසිය සෑම විටම අංක, දිනය සහ වෙනත් ඉදිකිරීම්කරුවන් සඳහා සත්‍ය වේ.
aMarCruz

95

මම භාවිතා කරන්නේ මෙයයි:

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

8
මෙය නිවැරදි යැයි නොපෙනේ. cloneObject({ name: null })=>{"name":{}}
නියාස්

13
මෙය ජාවාස්ක්‍රිප්ට් හි තවත් ගොළු දෙයක් නිසා typeof null > "object"නමුත් Object.keys(null) > TypeError: Requested keys of a value that is not an object.තත්වය වෙනස් කරන්නif(typeof(obj[i])=="object" && obj[i]!=null)
Vitim.us

මෙමඟින් වස්තුවෙහි උරුම වූ ගණන් කළ නොහැකි ගුණාංග කෙලින්ම ක්ලෝනයට පැවරෙනු ඇති අතර, වස්තුව සරල වස්තුවක් යැයි උපකල්පනය කරයි .
රොබ්

මෙය සංඛ්‍යාත්මක යතුරු සහිත වස්තූන් බවට පරිවර්තනය වන අරා අවුල් කරයි.
බ්ලේඩ්

ඔබ ශුන්‍ය භාවිතා නොකරන්නේ නම් ගැටළුවක් නොවේ.
ජෝර්ජ් බුකරන්

78

කාර්ය සාධනය අනුව ගැඹුරු පිටපත: හොඳම සිට නරකම දක්වා ශ්‍රේණිගත කර ඇත

  • නැවත පැවරීම "=" (නූල් අරා, අංක අරා - පමණි)
  • පෙත්ත (නූල් අරා, අංක අරා - පමණි)
  • සම්මුතිය (නූල් අරා, අංක අරා - පමණි)
  • අභිරුචි ශ්‍රිතය: for-loop හෝ පුනරාවර්තන පිටපත
  • jQuery හි $ .extend
  • JSON.parse (නූල් අරා, අංක අරා, වස්තු අරා - පමණි)
  • Underscore.js හි _.clone (නූල් අරා, අංක අරා - පමණි)
  • ලො-ඩෑෂ්ගේ _.cloneDeep

නූල් හෝ සංඛ්‍යා සමූහයක් ගැඹුරින් පිටපත් කරන්න (එක් මට්ටමක් - යොමු දර්ශක නොමැත):

අරාවෙහි අංක සහ නූල් අඩංගු වන විට - .slice (), .concat (), .splice (), පැවරුම් ක්‍රියාකරු "=", සහ Underscore.js හි ක්ලෝන ක්‍රියාකාරිත්වය; අරාවෙහි මූලද්‍රව්‍යයන්ගේ ගැඹුරු පිටපතක් සාදනු ඇත.

නැවත පැවරීම වේගවත්ම කාර්ය සාධනය ඇති තැන:

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

සහ .slice () .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

වස්තු සමූහයක් ගැඹුරින් පිටපත් කරන්න (මට්ටම් දෙකක් හෝ වැඩි ගණනක් - යොමු දර්ශක):

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

අභිරුචි ශ්‍රිතයක් ලියන්න (performance .extend () හෝ 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);

තෙවන පාර්ශවීය උපයෝගිතා කාර්යයන් භාවිතා කරන්න:

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

JQuery හි $ .extend වඩා හොඳ කාර්ය සාධනයක් ඇති තැන:


මම කිහිපයක් පරීක්‍ෂා කළ අතර _.extend ({}, (obj)) වේගවත්ම වේ: JSON.parse ට වඩා 20x වේගවත් සහ Object.assign ට වඩා 60% වේගවත්, උදාහරණයක් ලෙස. එය සියළුම උප වස්තු හොඳින් පිටපත් කරයි.
නිකෝ

4
ඔබගේ සියලු උදාහරණ නොගැඹුරු, එක් මට්ටමකි. මෙය හොඳ පිළිතුරක් නොවේ. ප්‍රශ්නය වූයේ ගැඹුරු ක්ලෝනකරණය, එනම් අවම වශයෙන් මට්ටම් දෙකක් සම්බන්ධයෙනි.
කාල් මොරිසන්

1
ගැඹුරු පිටපතක් යනු වෙනත් වස්තූන් වෙත යොමු දර්ශක භාවිතා නොකර වස්තුවක් සම්පුර්ණයෙන්ම පිටපත් කිරීමයි. JQuery.extend () සහ අභිරුචි ශ්‍රිතය (පුනරාවර්තන) වැනි “අවම වශයෙන් මට්ටම් දෙකක්” සහිත වස්තු පිටපත් කිරීම වැනි “ගැඹුරු පිටපත් වස්තු සමූහයක්” යටතේ ඇති ශිල්පීය ක්‍රම. එබැවින්, සියලු උදාහරණ "එක් මට්ටමේ" පිටපත් නොවේ.
tfmontague

1
මම ඔබේ අභිරුචි පිටපත් ශ්‍රිතයට කැමතියි, නමුත් ඔබ ශුන්‍ය අගයන් බැහැර කළ යුතුය, එසේ නොමැතිනම් සියලු ශුන්‍ය අගයන් වස්තු බවට පරිවර්තනය වේ, එනම්:out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
josi

2
Oss හොසම්මුරාඩ් - දෝෂය ජොසි විසින් පෙබරවාරි 1 වන දින නිවැරදි කරන ලදි (ඉහත අදහස් දැක්වීමේදී), පිළිතුර නිවැරදිව යාවත්කාලීන කිරීමට මා අසමත් විය. කණගාටුයි, මෙම දෝෂය නිසා ඔබේ කේත පදනම නැවත ප්‍රතිස්ථාපනය විය.
tfmontague

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

හොඳ පිළිතුරක් නමුත් මෙය රවුම් යොමු සඳහා අසමත් වේ.
ලූක්

59

ජාවාස්ක්‍රිප්ට් හි ගැඹුරු පිටපත් කිරීමේ වස්තු (මම හිතන්නේ හොඳම හා සරලම)

1. JSON.parse භාවිතා කිරීම (JSON.stringify (වස්තුව));

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. සාදන ලද ක්‍රමය භාවිතා කිරීම

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. Lo-Dash හි _.cloneDeep link lodash භාවිතා කිරීම

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

නමුත් වැරදි විට

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

නමුත් වැරදි විට

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.)

JSBEN.CH කාර්ය සාධන මිණුම් සලකුණු ක්‍රීඩා පිටිය 1 ~ 3 http://jsben.ch/KVQLd කාර්ය සාධනය ජාවාස්ක්‍රිප්ට් හි ගැඹුරු පිටපත් කිරීමේ වස්තු


5
Object.assign()ගැඹුරු පිටපතක් සිදු නොකරයි
රොයිමන්සන්

1
ඔබ මේවා සඳහා මිණුම් සලකුණු එකතු කළ යුතුය; එය ඉතා ප්‍රයෝජනවත් වනු ඇත
jcollum

අරාව අඩංගු වස්තුවක් මත “සාදන ලද ක්‍රමය” භාවිතා කළ විට මට එහි පොප් () හෝ ස්ප්ලයිස් () භාවිතා කිරීමට නොහැකි විය, ඒ ඇයි දැයි මට නොතේරේ. let data = {title:["one", "two"]}; let tmp = cloneObject(data); tmp.title.pop();එය විසි කරයි: TypeError: tmp.title.pop is not a function(ඇත්ත වශයෙන්ම පොප් () මම පමණක් නම් හොඳින් ක්‍රියා කරයි do let tmp = data; නමුත් දත්ත වලට බලපෑමක් නොකර මට tmp වෙනස් කළ නොහැක)
hugogogo

හේයි, ඔබේ අවසාන උදාහරණය වැරදියි. මගේ මතය අනුව, ඔබ භාවිතා කළ යුත්තේ _clone මිස වැරදි උදාහරණය සඳහා _cloneDeep නොවේ.
kenanyildiz

මෙම සාදන ලද ක්‍රමය (2.) අරා සඳහා ක්‍රියා නොකරනු ඇත, එසේ ද?
ටොයිවෝ සෝවාන්

57

එය තියෙනවා ( "පරිගණක ක්රිඩාවට සමාන" ලෙස හැඳින්වෙන) පුස්තකාල ඉතා හොඳින් මෙය කරන,. එය මා දන්නා අත්තනෝමතික වස්තූන්ගේ වඩාත් සම්පූර්ණ පුනරාවර්තන ක්ලෝනකරණය / පිටපත් කිරීම සපයයි. එය තවමත් අනෙක් පිළිතුරු වලින් ආවරණය නොවන චක්‍රලේඛ යොමු කිරීම් සඳහා සහය දක්වයි.

ඔබට එය npmසොයාගත හැකිය . එය බ්‍රව්සරයට මෙන්ම Node.js සඳහාද භාවිතා කළ හැකිය.

එය භාවිතා කරන්නේ කෙසේද යන්න පිළිබඳ උදාහරණයක් මෙන්න:

සමඟ එය ස්ථාපනය කරන්න

npm install clone

හෝ එය එන්ඩර් සමඟ ඇසුරුම් කරන්න .

ender build clone [...]

ඔබට ප්‍රභව කේතය අතින් බාගත කළ හැකිය.

එවිට ඔබට එය ඔබේ ප්‍රභව කේතයෙන් භාවිතා කළ හැකිය.

var clone = require('clone');

var a = { foo: { bar: 'baz' } };  // inital value of a
var b = clone(a);                 // clone a -> b
a.foo.bar = 'foo';                // change a

console.log(a);                   // { foo: { bar: 'foo' } }
console.log(b);                   // { foo: { bar: 'baz' } }

(වියාචනය: මම පුස්තකාලයේ කතුවරයා වෙමි.)


3
අත්තනෝමතික ලෙස කැදැලි කරන ලද වස්තූන් ක්ලෝන කිරීම සඳහා npm ක්ලෝනය මට මිල කළ නොහැකිය. මෙය නිවැරදි පිළිතුරයි.
ඇන්ඩි රේ

අපි කියමු හා සසඳන විට ඔබේ ලිබයේ ක්‍රියාකාරිත්වය JSON.parse(JSON.stringify(obj))කුමක්ද?
pkyeck

මෙන්න වේගවත් විකල්ප ඇති බව සඳහන් පුස්තකාලයක් . පරීක්ෂා කර නැත.
pvorb

හොඳ විසඳුමක් වන අතර මෙය චක්‍රලේඛ යොමු කිරීම් සඳහා සහය දක්වයි (JSON විග්‍රහය මෙන් නොව)
ලූක්

55

Cloning වස්තුවක් සැමවිටම JS හි සැලකිලිමත් විය, නමුත් එය සියල්ලම ES6 ට පෙර විය, මම පහත දැක්වෙන ජාවාස්ක්‍රිප්ට් හි වස්තුවක් පිටපත් කිරීමේ විවිධ ක්‍රම ලැයිස්තුගත කරමි, ඔබට පහත වස්තුව ඇති බව සිතන්න සහ එහි ගැඹුරු පිටපතක් ලබා ගැනීමට කැමතියි:

var obj = {a:1, b:2, c:3, d:4};

මූලාරම්භය වෙනස් නොකර මෙම වස්තුව පිටපත් කිරීමට ක්‍රම කිහිපයක් තිබේ:

1) ES5 +, ඔබ වෙනුවෙන් පිටපතක් කිරීම සඳහා සරල ශ්‍රිතයක් භාවිතා කිරීම:

function deepCopyObj(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }
    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 this object.");
}

2) ES5 +, JSON.parse සහ JSON.stringify භාවිතා කිරීම.

var  deepCopyObj = JSON.parse(JSON.stringify(obj));

3) AngularJs:

var  deepCopyObj = angular.copy(obj);

4) jQuery:

var deepCopyObj = jQuery.extend(true, {}, obj);

5) UnderscoreJs & Loadash:

var deepCopyObj = _.cloneDeep(obj); //latest version UndescoreJs makes shallow copy

මෙම උදව් බලාපොරොත්තු වේ ...


2
යටි ඉරි වල ක්ලෝනය වර්තමාන අනුවාදයේ ගැඹුරු ක්ලෝනයක් නොවේ
රොජලියෝ ට්‍රිවිනෝ

ස්තූතියි. ඔව්, අන්ඩර්ස්කෝර් සඳහා නව ලේඛනයක් ලෙස ... clone_.clone (වස්තුව) සපයා ඇති සරල වස්තුවෙහි නොගැඹුරු පිටපත් කළ ක්ලෝනයක් සාදන්න. ඕනෑම කැදැලි වස්තූන් හෝ අරා අනුපිටපත් නොකර පිටපත් කරනු ලැබේ. _.clone ({නම: 'moe'}); => {නම: 'moe'};
අලිරේසා

59
Object.assignනැහැ නැහැ ගැඹුරු පිටපත් කරගන්න. උදාහරණය : var x = { a: { b: "c" } }; var y = Object.assign({}, x); x.a.b = "d". මෙය ගැඹුරු පිටපතක් නම්, y.a.bතවමත් පවතිනු ඇත c, නමුත් එය දැන් ය d.
kba

8
Object.assign () ක්ලෝන කරන්නේ පළමු මට්ටමේ ගුණාංග පමණි!
haemse

5
cloneSO () ශ්‍රිතය යනු කුමක්ද?
pastorello

53

මෙය පැරණි පෝස්ට් එකක් බව මම දනිමි, නමුත් මම සිතුවේ මෙය පැකිලෙන ඊළඟ පුද්ගලයාට යම් උපකාරයක් විය හැකි බවයි.

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

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

16
මෙම පිළිතුර සැබවින්ම අදාළ නොවේ. මන්දයත් උදාහරණයකට b පිටපතක් නිර්මාණය කරන්නේ කෙසේද? කර්මාන්තශාලාව ගැන නොදැන හෝ කර්මාන්තශාලාව භාවිතා කිරීමට අකමැති විට. යමෙකුට කර්මාන්තශාලාව භාවිතා කිරීමට අකමැති වීමට හේතුව, ක්ෂණිකකරණයෙන් පසු අමතර දත්ත සමඟ ආරම්භ කිරීම b (උදා: පරිශීලක ආදානය).
නොයෙල් ඒබ්‍රහම්ස්

12
මෙය ඇත්ත වශයෙන්ම ප්‍රශ්නයට පිළිතුරක් නොවන බව සත්‍යයකි, නමුත් මෙහි පැමිණීම වැදගත් යැයි මම සිතමි. මන්ද මෙහි පැමිණෙන බොහෝ දෙනා ඇසීමට අර්ථයක් ඇති බවට මා සැක කරන ප්‍රශ්නයට පිළිතුර එයයි.
අර්ධ සළකුණ

8
සමාවෙන්න යාලුවනේ, මට තේරෙන්නේ නැහැ ඇයි මෙතරම් ඉහළට එන්නේ කියලා. වස්තුවක් ක්ලෝන කිරීම ඉතා පැහැදිලි සංකල්පයකි, ඔබ වෙනත් වස්තුවකින් වස්තුවක් කේතනය කරන අතර කර්මාන්තශාලා රටාව සමඟ නව එකක් නිර්මාණය කිරීම සඳහා එයට බොහෝ දේ කළ නොහැක.
opensas

2
මෙය පූර්ව නිශ්චිත වස්තූන් සඳහා ක්‍රියා කරන අතර, මේ ආකාරයෙන් "ක්ලෝනකරණය" මඟින් මුල් වස්තුවට එකතු කරන ලද නව ගුණාංග හඳුනා නොගනී. ඔබ a නිර්මාණය කරන්නේ නම්, a ට නව දේපලක් එක් කරන්න, ඉන්පසු b සාදන්න. b ට නව දේපල නොමැත. අත්‍යවශ්‍යයෙන්ම කර්මාන්තශාලා රටාව නව දේපලවලට වෙනස් කළ නොහැක. මෙය පරමාදර්ශී ක්ලෝන කිරීමක් නොවේ. බලන්න: jsfiddle.net/jzumbrun/42xejnbx
ජෝන්

1
මම හිතන්නේ මෙය හොඳ උපදෙසක්, සාමාන්‍යයෙන්, භාවිතා කිරීම වෙනුවට const defaultFoo = { a: { b: 123 } };ඔබට යා හැකි const defaultFoo = () => ({ a: { b: 123 } };අතර ඔබේ ගැටලුව විසඳනු ඇත. කෙසේ වෙතත්, එය ඇත්ත වශයෙන්ම ප්‍රශ්නයට පිළිතුරක් නොවේ. එය සම්පූර්ණ පිළිතුරක් නොව ප්‍රශ්නය පිළිබඳ අදහස් දැක්වීමක් ලෙස වඩාත් අර්ථවත් වන්නට ඇත.
ජෝෂ් කරිබෝ සිට

48

ඔබ එය භාවිතා කරන්නේ නම්, Underscore.js පුස්තකාලයට ක්ලෝන ක්‍රමයක් ඇත.

var newObject = _.clone(oldObject);

24
ලොඩාෂ්ට ක්ලෝන ඩීප් ක්‍රමයක් ඇත, එය ගැඹුරු කිරීම සඳහා ක්ලෝන කිරීමට තවත් පරාමිතියකට සහය දක්වයි: lodash.com/docs#clone සහ lodash.com/docs#cloneDeep
opensas

12
ඔපෙන්සාස් එකඟ විය. Lodash අවධාරනය කිරීමට සාමාන්යයෙන් සුපිරි වේ
nha

7
උපයෝගිතා පුස්තකාලයක .clone(...)ක්‍රමයට එක් පේළියක් පමණක් වන මෙය සහ අනෙකුත් සියලුම පිළිතුරු මකා දැමීමට මම යෝජනා කරමි . සෑම ප්‍රධාන පුස්තකාලයකම ඒවා ඇති අතර, නැවත නැවත කෙටියෙන් සවිස්තරාත්මක නොවන පිළිතුරු බොහෝ අමුත්තන්ට ප්‍රයෝජනවත් නොවේ, ඔවුන් එම පුස්තකාලය භාවිතා නොකරනු ඇත.
ජෙරමි බෑන්ක්ස්

41

ඉදිකිරීම්කරුට අවශ්‍ය පරාමිතීන් තිබුණත් ක්‍රියාත්මක වන ඉහත කොන්රෝයිපී පිළිතුරේ අනුවාදය මෙන්න:

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

function deepCopy(obj) {
    if(obj == null || typeof(obj) !== 'object'){
        return obj;
    }
    //make sure the returned object has the same prototype as the original
    var ret = object_create(obj.constructor.prototype);
    for(var key in obj){
        ret[key] = deepCopy(obj[key]);
    }
    return ret;
}

මෙම ක්‍රියාව මගේ සරල පුස්තකාලයේ ද ඇත.

සංස්කරණය කරන්න:

මෙන්න වඩාත් ශක්තිමත් අනුවාදයක් (ජස්ටින් මැකන්ඩ්ලස් ට ස්තූතියි මෙය දැන් චක්‍රීය යොමු කිරීම් සඳහා ද සහාය වේ):

/**
 * Deep copy an object (make copies of all its object properties, sub-properties, etc.)
 * An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
 * that doesn't break if the constructor has required parameters
 * 
 * It also borrows some code from http://stackoverflow.com/a/11621004/560114
 */ 
function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {
    if(src === null || typeof(src) !== 'object'){
        return src;
    }

    //Honor native/custom clone methods
    if(typeof src.clone == 'function'){
        return src.clone(true);
    }

    //Special cases:
    //Date
    if(src instanceof Date){
        return new Date(src.getTime());
    }
    //RegExp
    if(src instanceof RegExp){
        return new RegExp(src);
    }
    //DOM Element
    if(src.nodeType && typeof src.cloneNode == 'function'){
        return src.cloneNode(true);
    }

    // Initialize the visited objects arrays if needed.
    // This is used to detect cyclic references.
    if (_visited === undefined){
        _visited = [];
        _copiesVisited = [];
    }

    // Check if this object has already been visited
    var i, len = _visited.length;
    for (i = 0; i < len; i++) {
        // If so, get the copy we already made
        if (src === _visited[i]) {
            return _copiesVisited[i];
        }
    }

    //Array
    if (Object.prototype.toString.call(src) == '[object Array]') {
        //[].slice() by itself would soft clone
        var ret = src.slice();

        //add it to the visited array
        _visited.push(src);
        _copiesVisited.push(ret);

        var i = ret.length;
        while (i--) {
            ret[i] = deepCopy(ret[i], _visited, _copiesVisited);
        }
        return ret;
    }

    //If we've reached here, we have a regular object

    //make sure the returned object has the same prototype as the original
    var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
    if (!proto) {
        proto = src.constructor.prototype; //this line would probably only be reached by very old browsers 
    }
    var dest = object_create(proto);

    //add this object to the visited array
    _visited.push(src);
    _copiesVisited.push(dest);

    for (var key in src) {
        //Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
        //For an example of how this could be modified to do so, see the singleMixin() function
        dest[key] = deepCopy(src[key], _visited, _copiesVisited);
    }
    return dest;
}

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

30

පහත දැක්වෙන්නේ එකම වස්තුවක අවස්ථා දෙකක් නිර්මාණය කිරීමයි. මම එය සොයා ගත් අතර දැනට එය භාවිතා කරමි. එය සරල හා භාවිතා කිරීමට පහසුය.

var objToCreate = JSON.parse(JSON.stringify(cloneThis));

මෙම පිළිතුරේ යම් වැරැද්දක් තිබේද? ස්වාධීන විසඳුමක් ලෙස එය වඩාත් ප්‍රයෝජනවත් නමුත් සරල ය; නමුත් jQuery විසඳුම වඩාත් ජනප්‍රියයි. ඇයි ඒ?
මස්තිෂ්කය

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

4
සරල වස්තුවක් සඳහා, මෙය ලබා දී ඇති පිළිතුරට වඩා ක්‍රෝම් හි 6 ගුණයකින් මන්දගාමී වන අතර වස්තුවේ සංකීර්ණතාව වැඩි වන විට එය මන්දගාමී වේ. එය ඉතා දරුණු ලෙස පරිමාණය වන අතර ඔබගේ යෙදුමට ඉතා ඉක්මණින් බාධා කළ හැකිය.
ටික්

1
ඔබට දත්ත අවශ්‍ය නැත, සිදුවන්නේ කුමක්ද යන්න පිළිබඳ අවබෝධයක් පමණි. මෙම ක්ලෝනකරණ තාක්‍ෂණය මඟින් මුළු වස්තුවම නූලකට අනුක්‍රමණය කරයි, පසුව එම වස්තු අනුක්‍රමිකකරණය වස්තුවක් තැනීමට විග්‍රහ කරයි. සහජයෙන්ම එය හුදෙක් මතකය නැවත පිළිවෙලට තැබීමට වඩා මන්දගාමී වනු ඇත (වඩාත් නවීන ක්ලෝන කරන්නේ එයයි). නමුත් එසේ පැවසීමත් සමඟ කුඩා හා මධ්‍යම ප්‍රමාණයේ ව්‍යාපෘති සඳහා (“මධ්‍යම ප්‍රමාණයේ” යන්නෙහි ඔබේ අර්ථ දැක්වීම අනුව) එය 1000x අඩු කාර්යක්ෂමතාවයක් ඇත්දැයි සැලකිලිමත් වන්නේ කවුද? ඔබේ වස්තූන් කුඩා වන අතර ඔබ ඒවා ටොන් 1000x ක්ලෝන නොකරන්නේ නම් කිසිවක් නැති තරම්ය.
machineghost

3
එසේම, මෙම ක්‍රමයට ක්‍රම අහිමි වේ (හෝ JSON හි අවසර නැති ඕනෑම දෙයක්), ප්ලස් - JSON.stringify මඟින් දිනය වස්තු නූල් බවට පරිවර්තනය කරයි, සහ වෙනත් ආකාරයකින් නොවේ;) මෙම විසඳුමෙන් වළකින්න.
මන්ත්රී මෙට්රික් ටොන්

22

ක්‍රොක්ෆර්ඩ් මෙම ශ්‍රිතය භාවිතා කිරීමට යෝජනා කරයි (සහ මම කැමතියි):

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

var newObject = object(oldObject);

එය දැඩි, බලාපොරොත්තු වූ පරිදි ක්‍රියාත්මක වන අතර ඔබට පුස්තකාලයක් අවශ්‍ය නොවේ.


සංස්කරණය කරන්න:

මෙය බහු පිරවුමකි Object.create, එබැවින් ඔබට මෙයද භාවිතා කළ හැකිය.

var newObject = Object.create(oldObject);

සටහන: ඔබ මේවායින් සමහරක් භාවිතා කරන්නේ නම්, භාවිතා කරන සමහර පුනරාවර්තන සමඟ ඔබට ගැටළු ඇති විය හැකිය hasOwnProperty. මන්ද, createඋරුම වූ නව හිස් වස්තුවක් සාදන්නoldObject . නමුත් වස්තූන් ක්ලෝන කිරීම සඳහා එය තවමත් ප්රයෝජනවත් හා ප්රායෝගික ය.

නිදහස් නම් oldObject.a = 5;

newObject.a; // is 5

එහෙත්:

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

9
මා වැරදියි නම් මාව නිවැරදි කරන්න, නමුත් එය ක්‍රෝක්ෆර්ඩ්ගේ මූලාකෘති උරුමය සඳහා වූ කාර්යයක් නොවේද? ක්ලෝන සඳහා එය අදාළ වන්නේ කෙසේද?
ඇලෙක්ස් නොලාස්කෝ

3
ඔව්, මම මෙම සාකච්ඡාවට බිය වූවෙමි: ක්ලෝන, පිටපත් සහ මූලාකෘති උරුමය අතර ඇති ප්‍රායෝගික වෙනස කුමක්ද, ඔබ ඒවා භාවිතා කළ යුත්තේ කවදාද සහ මෙම පිටුවේ කුමන කාර්යයන් ඇත්ත වශයෙන්ම කරන්නේ කුමක්ද? "මෙම ජාවාස්ක්‍රිප්ට් පිටපත් වස්තුව" ගූගල් කිරීමෙන් මට මෙම SO පිටුව හමු විය. මම ඇත්තටම සොයමින් සිටියේ ඉහත ක්‍රියාකාරිත්වය නිසා මම නැවත බෙදා ගැනීමට පැමිණියෙමි. මගේ අනුමානය නම් අසන්නා මෙය ද සොයමින් සිටි බවයි.
ක්‍රිස් බ්‍රොස්කි

51
ක්ලෝන / පිටපත සහ උරුමය අතර වෙනස නම්, එනම් - ඔබේ උදාහරණය භාවිතා කරමින්, මම පරණ වස්තුවක දේපලක් වෙනස් කරන විට, දේපල ද නව වස්තුවක වෙනස් වේ. ඔබ පිටපතක් සාදන්නේ නම්, නව ඕබෙක්ට් වෙනස් නොකර පැරණි ඕබෙක්ට් සමඟ ඔබට අවශ්‍ය දේ කළ හැකිය.
රිඩ්කුලි

13
මෙය hasOwnProperty චෙක්පත බිඳ දමනු ඇති අතර එමඟින් වස්තුවක් ක්ලෝන කිරීමට එය ඉතා අනර්ථකාරී ක්‍රමයක් වන අතර ඔබට අනපේක්ෂිත ප්‍රති .ල ලබා දෙනු ඇත.
කෝබන් බ ok ක්

var extendObj = function(childObj, parentObj) { var tmpObj = function () {} tmpObj.prototype = parentObj.prototype; childObj.prototype = new tmpObj(); childObj.prototype.constructor = childObj; };... davidshariff.com/blog/javascript-inheritance-patterns
කෝඩි

22

ලොඩාෂ් සතුව ලස්සන _.cloneDeep (අගය) ක්‍රමයක් ඇත:

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

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

5
උපයෝගිතා පුස්තකාලයක .clone(...)ක්‍රමයට එක් පේළියක් පමණක් වන මෙය සහ අනෙකුත් සියලුම පිළිතුරු මකා දැමීමට මම යෝජනා කරමි . සෑම ප්‍රධාන පුස්තකාලයකම ඒවා ඇති අතර, නැවත නැවත කෙටියෙන් සවිස්තරාත්මක නොවන පිළිතුරු බොහෝ අමුත්තන්ට ප්‍රයෝජනවත් නොවේ, ඔවුන් එම පුස්තකාලය භාවිතා නොකරනු ඇත.
ජෙරමි බෑන්ක්ස්

පහසු ක්‍රමයක් වන්නේ භාවිතා කිරීමයි _.merge({}, objA). ලොඩාෂ් පමණක් වස්තූන් මුලින් විකෘති නොකළේ නම් cloneශ්‍රිතය අවශ්‍ය නොවේ.
රීබ්ස්

7
JS වස්තු ක්ලෝන කිරීම සඳහා ගූගල් සෙවුම් මෙහි යොමු වේ. මම ලොඩාෂ් භාවිතා කරන බැවින් මෙම පිළිතුර මට අදාළ වේ. කරුණාකර පිළිතුරු සඳහා "විකිපීඩියා මකාදැමීමේ" සියලු දෙනා නොයමු.
Rebs

2
Node 9 හි, JSON.parse (JSON.stringify (arrayOfAbout5KFlatObjects)) _.deepClone (arrayOfAbout5KFlatObjects) ට වඩා බොහෝ වේගවත්ය.
ඩෑන් ඩස්කලෙස්කු

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

17
ක්‍රමවේදය පිළිබඳ ගැටළුව නම්, ඔබ සතුව වස්තුව තුළ උප වස්තු තිබේ නම්, ඒවායේ යොමු කිරීම් ක්ලෝන කරනු ලැබේ, සෑම උප වස්තුවකම අගයන් නොවේ.
කමරේ

1
උප වස්තූන් ගැඹුරින් ක්ලෝන කරනු ලබන බැවින් එය පුනරාවර්තනය කරන්න.
fiatjaf

කුතුහලය දනවන ... ක්ලෝන විචල්‍යයට මුල් වස්තුවේ ගුණාංග වෙත දර්ශක තිබිය හැකිද? එය නව මතක වෙන් කිරීමක් නොමැති බව පෙනේ
රූපේෂ් පටෙල්

3
ඔව්. මෙය නොගැඹුරු පිටපතක් පමණි, එබැවින් ක්ලෝනය මුල් වස්තුවෙන් පෙන්වා ඇති එකම වස්තූන් වෙත යොමු වේ.
මාර්ක් සිඩාඩ්

මෙය පිළිතුරක් නොවේ. ඔබ වචනානුසාරයෙන් වෙනත් වස්තුවක් වෙත යොමු කරමින් වස්තුවක් පුරවනවා. ප්‍රභව වස්තුවෙහි වෙනස්කම් සිදු කිරීමෙන් "ක්ලෝන" හි වෙනස්කම් සිදු වේ.
ෂෝන් වින්නරි

20

නොගැඹුරු පිටපත් එක්-ලයිනර් ( ECMAScript 5 වන සංස්කරණය ):

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

සහ නොගැඹුරු පිටපත් එක්-ලයිනර් ( ECMAScript 6 වන සංස්කරණය , 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

6
සරල වස්තූන් සඳහා මෙය හොඳ විය හැකි නමුත් එය පිටපත් කරන්නේ දේපල අගයන් පමණි. එය මූලාකෘති දාමයට අත නොතබන අතර Object.keysඑය භාවිතා කිරීමෙන් ගණන් කළ නොහැකි හා උරුම වූ ගුණාංග මඟ හැරේ. එසේම, සෘජු පැවරුම් කිරීමෙන් දේපල විස්තර කරන්නන් අහිමි වේ.
මැට් බියර්නර්

ඔබ මූලාකෘතියද පිටපත් කරන්නේ නම්, ඔබට අතුරුදහන් වනුයේ ගණන් කළ නොහැකි සහ දේපල විස්තර කරන්නන් පමණි, ඔව්? හුඟක් හොඳයි. :)
සෑම්

කාර්ය සාධනය පසෙකට දැමුවහොත්, මෙය වස්තුවක් නොගැඹුරු ලෙස පිටපත් කිරීමට සැබවින්ම පහසු ක්‍රමයකි. මගේ ප්‍රතික්‍රියාකාරක සංරචකවල විනාශකාරී පැවරුමක ව්‍යාජ විවේක දේපල වර්ග කිරීම සඳහා මම බොහෝ විට මෙය භාවිතා කරමි.
mjohnsonengr

17

AngularJS සඳහන් කර නැති නිසා සහ මිනිසුන් දැන ගැනීමට අවශ්‍ය යැයි සිතූ නිසා ...

angular.copy ගැඹුරු පිටපත් කිරීමේ වස්තු සහ අරා ක්‍රමයක් ද සපයයි.


නැතහොත් එය jQiery දිගු කරන ආකාරයටම භාවිතා කළ හැකිය:angular.extend({},obj);
ගැල්වානි

2
@Galvani: එය බව සඳහන් කළ යුතු ය jQuery.extendසහ angular.extendනොගැඹුරු පිටපත් දෙකම ඇත. angular.copyගැඹුරු පිටපතකි.
ඩෑන් ඇට්කින්සන්

16

අරාව වැනි වස්තූන් සඳහා පරිපූර්ණ ගැඹුරු ක්ලෝන ක්‍රියාකරුවෙකු තවමත් නොමැති බව පෙනේ. පහත කේතය පැහැදිලි කරන පරිදි, ජෝන් රෙසිග්ගේ jQuery ක්ලෝනරය සංඛ්‍යාත්මක නොවන ගුණාංග සහිත අරා අරා නොවන වස්තූන් බවට හරවන අතර රෙග්ඩ්වයිට්ගේ JSON ක්ලෝනරය සංඛ්‍යාත්මක නොවන ගුණාංග පහත වැටේ. පහත දැක්වෙන පරීක්ෂණ මඟින් මෙම කරුණු බහු බ්‍රව්සර්වල දැක්වේ:

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)

14
අනෙක් අය රෙසිග්ගේ පිළිතුරට අදහස් දැක්වීමේදී, ඔබට අරාව වැනි වස්තුවක් ක්ලෝන කිරීමට අවශ්‍ය නම්, ඔබ call} [[] දක්වා දීර් call ඇමතුම වෙනස් කරයි, උදා: jQuery.extend (true, [], obj)
Anentropic

15

ඔබේ පරමාර්ථය "සරල පැරණි ජාවාස්ක්‍රිප්ට් වස්තුවක්" ක්ලෝන කිරීම හෝ නොකිරීම මත මට හොඳ පිළිතුරු දෙකක් තිබේ.

මූලාශ්‍ර වස්තුව වෙත නැවත මූලාකෘති යොමු කිරීම් නොමැතිව සම්පූර්ණ ක්ලෝනයක් නිර්මාණය කිරීම ඔබේ අභිප්‍රාය යැයි උපකල්පනය කරමු. ඔබ සම්පූර්ණ ක්ලෝනයක් ගැන උනන්දුවක් නොදක්වන්නේ නම්, ඔබට වෙනත් පිළිතුරු වලින් ලබා දී ඇති Object.clone () චර්යාවන් බොහොමයක් භාවිතා කළ හැකිය (ක්‍රොක්ෆර්ඩ්ගේ රටාව).

පැරණි පැරණි ජාවාස්ක්‍රිප්ට් වස්තු සඳහා, නවීන ධාවන කාලවලදී වස්තුවක් ක්ලෝන කිරීමට උත්සාහ කළ සහ සැබෑ හොඳ ක්‍රමයක් වන්නේ සරලවම ය:

var clone = JSON.parse(JSON.stringify(obj));

ප්‍රභව වස්තුව පිරිසිදු JSON වස්තුවක් විය යුතු බව සලකන්න. මෙයින් කියැවෙන්නේ, එහි ඇති සියලුම කැදැලි ගුණාංග පරිමාණයන් විය යුතුය (බූලියන්, නූල්, අරාව, වස්තුව යනාදිය). RegExp හෝ දිනය වැනි ඕනෑම කාර්යයක් හෝ විශේෂ වස්තු ක්ලෝන නොකෙරේ.

එය කාර්යක්ෂමද? ඔව්. අපි සියලු වර්ගවල ක්ලෝනකරණ ක්‍රම අත්හදා බලා ඇති අතර මෙය වඩාත් සුදුසුය. මට විශ්වාසයි සමහර නින්ජා වලට වේගවත් ක්‍රමයක් හුවා දැක්විය හැකිය. නමුත් මම සැක කරන්නේ අපි ආන්තික වාසි ගැන කතා කරන බවයි.

මෙම ප්‍රවේශය සරල හා ක්‍රියාත්මක කිරීමට පහසුය. එය පහසුව සඳහා ඔතා, ඔබට යම් වාසියක් මිරිකීමට අවශ්‍ය නම්, පසුව යන්න.

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

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

අප ලියා ඇත්තේ අපේම ය, නමුත් මා දුටු හොඳම පොදු ප්‍රවේශය මෙහි ආවරණය වේ:

http://davidwalsh.name/javascript-clone

මෙය නිවැරදි අදහසයි. කතුවරයා (ඩේවිඩ් වොල්ෂ්) සාමාන්‍යකරණය කරන ලද කාර්යයන් ක්ලෝන කිරීම පිළිබඳව අදහස් දක්වා ඇත. මෙය ඔබගේ භාවිත අවස්ථාව අනුව ඔබ කිරීමට තෝරා ගත හැකි දෙයකි.

ප්‍රධාන අදහස නම්, එක් එක් වර්ගයේ පදනම මත ඔබේ කාර්යයන් (හෝ මූලාකෘති පංති, කථා කිරීම සඳහා) ක්ෂණිකව හැසිරවිය යුතු බවයි. මෙන්න, ඔහු RegExp සහ දිනය සඳහා උදාහරණ කිහිපයක් සපයා ඇත.

මෙම කේතය කෙටියෙන් පමණක් නොව එය ඉතා පහසුවෙන් කියවිය හැකිය. එය දිගු කිරීම පහසුය.

මෙය කාර්යක්ෂමද? ඔව්. සත්‍ය ගැඹුරු පිටපත් ක්ලෝනයක් නිපදවීම ඉලක්කය බව සලකන විට, ඔබට ප්‍රභව වස්තු ප්‍රස්ථාරයේ සාමාජිකයන් ගමන් කළ යුතුය. මෙම ප්‍රවේශය සමඟ, ඔබට කුමන ළමා සාමාජිකයින්ට සැලකිය යුතුද යන්න සහ අභිරුචි වර්ග අතින් හැසිරවිය යුතු ආකාරය හරියටම වෙනස් කළ හැකිය.

ඉතින් ඔන්න එතනට යන්න. ප්රවේශයන් දෙකක්. දෙකම මගේ දැක්ම අනුව කාර්යක්ෂම වේ.


13

මෙය සාමාන්‍යයෙන් වඩාත්ම කාර්යක්ෂම විසඳුම නොවේ, නමුත් එය මට අවශ්‍ය දේ කරයි. සරල පරීක්ෂණ අවස්ථා පහතින් ...

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

චක්‍රීය අරාව පරීක්ෂණය ...

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

ක්‍රියාකාරී පරීක්ෂණය ...

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

11

AngularJS

හොඳයි, ඔබ කෝණික භාවිතා කරන්නේ නම් ඔබටත් මෙය කළ හැකිය

var newObject = angular.copy(oldObject);

11

මෙහි ඇති විශාලතම ඡන්ද සමඟ පිළිතුරට මම එකඟ නොවෙමි . ඒ ආවර්තනික ගැඹුරු තවානේ වේ වඩා වේගවත් වඩා JSON.parse (JSON.stringify (එය විවෘත)) ප්රවේශය සඳහන්.

  • Jsperf මෙහි අංක එකේ ශ්‍රේණිගත කරයි: https://jsperf.com/deep-copy-vs-json-stringify-json-parse/5
  • පුනරාවර්තන ගැඹුරු ක්ලෝනයක් සඳහන් කළ අනෙක් සියල්ලන්ටම පහර දෙන බව පෙන්වීමට ඉහත පිළිතුරෙන් ජෙස්බෙන් යාවත්කාලීන කරන ලදි: http://jsben.ch/13YKQ

ඉක්මන් යොමු කිරීම සඳහා ශ්‍රිතය මෙන්න:

function cloneDeep (o) {
  let newO
  let i

  if (typeof o !== 'object') return o

  if (!o) return o

  if (Object.prototype.toString.apply(o) === '[object Array]') {
    newO = []
    for (i = 0; i < o.length; i += 1) {
      newO[i] = cloneDeep(o[i])
    }
    return newO
  }

  newO = {}
  for (i in o) {
    if (o.hasOwnProperty(i)) {
      newO[i] = cloneDeep(o[i])
    }
  }
  return newO
}

2
මම මෙම ප්‍රවේශයට කැමති නමුත් එය දින වකවානු නිසි ලෙස හසුරුවන්නේ නැත; if(o instanceof Date) return new Date(o.valueOf());ශුන්‍ය `
ලුයිස්

රවුම් යොමු මත බිඳ වැටීම්.
හැරී

නවතම ස්ථායී ෆයර්ෆොක්ස් වලදී, මෙය Jsben.ch සබැඳියේ ඇති අනෙක් උපාය මාර්ග වලට වඩා විශාල වේ. එය අනෙක් අයට වැරදි දිශාවකට පහර දෙයි.
WBT

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

10

ඔබට ECMAScript 6 හෝ ට්‍රාන්ස්පයිලර් භාවිතා කළ හැකි විට පමණි .

විශේෂාංග:

  • පිටපත් කිරීමේදී getter / setter අවුලුවන්නේ නැත.
  • Getter / setter ආරක්ෂා කරයි.
  • මූලාකෘති තොරතුරු ආරක්ෂා කරයි.
  • දෙකම ක්රියා වස්තුව-සාහිත්යමය හා ක්රියාකාරී OO ලිවීම සමන්විතය.

කේතය:

function clone(target, source){

    for(let key in source){

        // Use getOwnPropertyDescriptor instead of source[key] to prevent from trigering setter/getter.
        let descriptor = Object.getOwnPropertyDescriptor(source, key);
        if(descriptor.value instanceof String){
            target[key] = new String(descriptor.value);
        }
        else if(descriptor.value instanceof Array){
            target[key] = clone([], descriptor.value);
        }
        else if(descriptor.value instanceof Object){
            let prototype = Reflect.getPrototypeOf(descriptor.value);
            let cloneObject = clone({}, descriptor.value);
            Reflect.setPrototypeOf(cloneObject, prototype);
            target[key] = cloneObject;
        }
        else {
            Object.defineProperty(target, key, descriptor);
        }
    }
    let prototype = Reflect.getPrototypeOf(source);
    Reflect.setPrototypeOf(target, prototype);
    return target;
}

9

ඕනෑම ජාවාස්ක්‍රිප්ට් වස්තුවක් ක්ලෝන කළ හැකි පුළුල් ක්ලෝන () ක්‍රමයක් මෙන්න. එය සෑම අවස්ථාවකම පාහේ හසුරුවයි:

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

එය ප්‍රාථමිකයන් එතීමේ වස්තූන් බවට පරිවර්තනය කරයි, බොහෝ අවස්ථාවන්හිදී හොඳ විසඳුමක් නොවේ.
ඩැනුබියන් නාවිකයා

An ඩැනුබියන් සේලර් - මම හිතන්නේ නැහැ ... එය ආරම්භයේ සිටම ප්‍රාථමිකයන් ආපසු ලබා දෙන බවක් පෙනේ, ඔවුන් ආපසු එන විට ඒවා ඔතා ඇති වස්තූන් බවට පත් කරන කිසිවක් ඔවුන්ට කරන බවක් නොපෙනේ.
ජිම්බෝ ජොනී
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.