কীভাবে জাভাস্ক্রিপ্টে ডিপ ক্লোন করবেন


105

আপনি কীভাবে জাভাস্ক্রিপ্ট অবজেক্টের গভীর ক্লোন করবেন?

আমি জানি যে ফ্রেমওয়ার্কের উপর ভিত্তি করে বিভিন্ন ফাংশন রয়েছে JSON.parse(JSON.stringify(o))এবং $.extend(true, {}, o)তবে আমি এর মতো ফ্রেমওয়ার্ক ব্যবহার করতে চাই না।

একটি গভীর ক্লোন তৈরি করার জন্য সবচেয়ে মার্জিত বা কার্যকর উপায় কী।

ক্লোনিং অ্যারে এর মতো প্রান্তের ক্ষেত্রে আমরা যত্ন নিই। প্রোটোটাইপ চেইনগুলি ভাঙা নয়, স্ব-রেফারেন্সের সাথে ডিল করা।

আমরা ডিওএম অবজেক্ট এবং অনুলিপি অনুলিপি সমর্থন করার বিষয়ে চিন্তা করি না কারণ .cloneNodeযে কারণে বিদ্যমান।

যেহেতু আমি প্রধানত node.jsভি 8 ইঞ্জিনের ইএস 5 বৈশিষ্ট্যগুলি ব্যবহার করে গভীর ক্লোন ব্যবহার করতে চাই তা গ্রহণযোগ্য।

[সম্পাদনা]

কেউ আমাকে পরামর্শ দেওয়ার আগে আমাকে উল্লেখ করতে দিন যে কোনও বস্তুটি প্রোটোটাইপিকভাবে উত্তরাধিকার সূত্রে তৈরি করে এবং এটির ক্লোনিং করে একটি অনুলিপি তৈরি করতে পার্থক্য রয়েছে । প্রোটোটাইপ শৃঙ্খলে একটি জগাখিচুড়ি করে দেয় প্রাক্তন।

[আরও সম্পাদনা]

আপনার উত্তরটি পড়ার পরে আমি বিরক্তিকর আবিষ্কারে পৌঁছে গেলাম যে পুরো বস্তুর ক্লোনিং করা একটি খুব বিপজ্জনক এবং কঠিন খেলা game উদাহরণস্বরূপ নীচের ক্লোজার ভিত্তিক অবজেক্টটি ধরুন

var o = (function() {
     var magic = 42;

     var magicContainer = function() {
          this.get = function() { return magic; };
          this.set = function(i) { magic = i; };
     }

      return new magicContainer;
}());

var n = clone(o); // how to implement clone to support closures

কোনও ক্লোন ফাংশন লেখার কোনও উপায় আছে যা অবজেক্টটিকে ক্লোন করে, ক্লোনিংয়ের সময় একই অবস্থা থাকে তবে oজেএসে জেএস পার্সার না লিখে অবস্থার পরিবর্তন করতে পারে না ।

এই জাতীয় ফাংশনটির আর কোনও বাস্তব জগতের দরকার নেই। এটি নিছক একাডেমিক আগ্রহ।


2
এটি সদৃশ চিহ্নিত হওয়ার আগে, আমি stackoverflow.com/questions/122102/… তাকিয়েছি এবং কোনও উত্তর খুঁজে পাইনি যা সমস্ত প্রান্তের ক্ষেত্রে মোকাবেলা করেছে।
রায়নস

"আরও সম্পাদনা" বিভাগের প্রয়োজনীয়তাটি অবজেক্ট থেকে নিজেই "সহায়তা" ছাড়াই অর্জন করা অসম্ভব, যেহেতু এই জাতীয় ব্যক্তিগত ভেরিয়েবলগুলি সত্যই ব্যক্তিগত , এবং ফলস্বরূপ জেনেরিক cloneফাংশন দ্বারা অ্যাক্সেসযোগ্য নয় । প্রশ্নের মধ্যে থাকা অবজেক্টটির নিজস্ব দর্জি দ্বারা তৈরি cloneপদ্ধতিটি প্রকাশ করা উচিত ।
ট্রিনকোট

আমি আজ রাতে এই গুচ্ছ সম্পর্কে পড়ছি, এবং আমি যে সংস্থানগুলি পেয়েছি তার মধ্যে এই কুরুচিপূর্ণ
ক্যাট

উত্তর:


67

আপনি কী ক্লোন করতে চান তা এটি নির্ভর করে। এটি কি সত্যিই JSON অবজেক্ট বা জাভাস্ক্রিপ্টে কেবল কোনও অবজেক্ট? আপনি যদি কোনও ক্লোন করতে চান তবে এটি আপনাকে কোনও সমস্যার মধ্যে ফেলতে পারে। কোন ঝামেলা? আমি এটি নীচে ব্যাখ্যা করব, তবে প্রথমে একটি কোড উদাহরণ যা ক্লোরনকে আক্ষরিক, কোনও আদিম, অ্যারে এবং ডিওএম নোডের অবজেক্ট করে।

function clone(item) {
    if (!item) { return item; } // null, undefined values check

    var types = [ Number, String, Boolean ], 
        result;

    // normalizing primitives if someone did new String('aaa'), or new Number('444');
    types.forEach(function(type) {
        if (item instanceof type) {
            result = type( item );
        }
    });

    if (typeof result == "undefined") {
        if (Object.prototype.toString.call( item ) === "[object Array]") {
            result = [];
            item.forEach(function(child, index, array) { 
                result[index] = clone( child );
            });
        } else if (typeof item == "object") {
            // testing that this is DOM
            if (item.nodeType && typeof item.cloneNode == "function") {
                result = item.cloneNode( true );    
            } else if (!item.prototype) { // check that this is a literal
                if (item instanceof Date) {
                    result = new Date(item);
                } else {
                    // it is an object literal
                    result = {};
                    for (var i in item) {
                        result[i] = clone( item[i] );
                    }
                }
            } else {
                // depending what you would like here,
                // just keep the reference, or create new object
                if (false && item.constructor) {
                    // would not advice to do that, reason? Read below
                    result = new item.constructor();
                } else {
                    result = item;
                }
            }
        } else {
            result = item;
        }
    }

    return result;
}

var copy = clone({
    one : {
        'one-one' : new String("hello"),
        'one-two' : [
            "one", "two", true, "four"
        ]
    },
    two : document.createElement("div"),
    three : [
        {
            name : "three-one",
            number : new Number("100"),
            obj : new function() {
                this.name = "Object test";
            }   
        }
    ]
})

এবং এখন, আসল বিষয়গুলির ক্লোনিং শুরু করার সময় আপনি যে সমস্যার মুখোমুখি হতে পারেন সে সম্পর্কে কথা বলি। আমি এখন কথা বলছি, আপনি এমন কিছু করে তৈরি করা জিনিসগুলির বিষয়ে about

var User = function(){}
var newuser = new User();

অবশ্যই আপনি এগুলি ক্লোন করতে পারেন, এটি কোনও সমস্যা নয়, প্রতিটি বস্তু নির্মাণকারীর সম্পত্তি প্রকাশ করে এবং আপনি এটি বস্তুর ক্লোন করতে ব্যবহার করতে পারেন, তবে এটি সর্বদা কার্যকর হবে না। আপনি for inএই বস্তুগুলিতে সহজ কাজ করতে পারেন , তবে এটি একই দিক - সমস্যাতে চলে যায়। আমি কোডের ভিতরে ক্লোন কার্যকারিতাও অন্তর্ভুক্ত করেছি, তবে if( false )বিবৃতি দিয়ে এটি বাদ দেওয়া হয়েছে।

সুতরাং, ক্লোনিং একটি ব্যথা হতে পারে কেন? ওয়েল, প্রথমত, প্রতিটি বস্তুর / দৃষ্টান্তের কিছুটা অবস্থা থাকতে পারে। আপনি কখনই নিশ্চিত হতে পারবেন না যে আপনার বস্তুর উদাহরণস্বরূপ একটি ব্যক্তিগত ভেরিয়েবল নেই, এবং যদি এটি হয় তবে ক্লোনিং অবজেক্ট দ্বারা, আপনি কেবল রাষ্ট্রটি ভেঙে দিন।

ভাবুন তো কোনও রাজ্য নেই, তা ঠিক আছে। তারপরে আমাদের আরও একটি সমস্যা রয়েছে। "কনস্ট্রাক্টর" পদ্ধতির মাধ্যমে ক্লোনিং আমাদের আরও একটি বাধা দেয়। এটি একটি যুক্তি নির্ভরতা। আপনি কখনই নিশ্চিত হতে পারবেন না যে যে কেউ এই বস্তুটি তৈরি করেছেন, করেননি, কোনও প্রকারের

new User({
   bike : someBikeInstance
});

যদি এটি হয় তবে আপনার ভাগ্যের বাইরে, কিছু বাইকইনস্ট্যান্স সম্ভবত কোনও প্রসঙ্গে তৈরি হয়েছিল এবং সেই প্রসঙ্গটি ক্লোন পদ্ধতির জন্য অজানা।

তো এখন কি করা? আপনি এখনও for inসমাধান করতে পারেন , এবং এই জাতীয় অবজেক্টগুলিকে সাধারণ অবজেক্ট ল্যাটারালগুলির মতো চিকিত্সা করতে পারেন , তবে সম্ভবত এই জাতীয় বস্তুটি মোটেও ক্লোন না করা এবং কেবল এই অবজেক্টের রেফারেন্সটি পাস করা কোনও ধারণা?

আর একটি সমাধান হ'ল - আপনি একটি কনভেনশন সেট করতে পারেন যে ক্লোন করা আবশ্যক এমন সমস্ত বস্তুর নিজেরাই এই অংশটি প্রয়োগ করতে হবে এবং যথাযথ এপিআই পদ্ধতি সরবরাহ করতে হবে (ক্লোনঅবজেক্টের মতো)। কিছু কি cloneNodeকরে DOM জন্য করছে।

তুমি ঠিক কর.


আমি নিজের অবস্থানটি গোপন করতে ক্লোজার ব্যবহার করে এমন বস্তুগুলির সাথে লেনদেনের অন্তরায় এসেছি ap কীভাবে কোনও কোনও বস্তু এবং তার সম্পূর্ণ রাজ্যের ক্লোন করতে পারে তবে তবুও নিশ্চিত করতে পারে যে ক্লোনটি ক্যান্সার নিজেই মূল রাজ্যের পরিবর্তন করতে পারে। result = new item.constructor();খারাপ হওয়ার একটি গুরুত্বপূর্ণ বিষয় হল কনস্ট্রাক্টর ফাংশন এবং আইটেমের অবজেক্টের পরে আপনি কনস্ট্রাক্টরটিতে পাস হওয়া কোনও প্যারামিটারগুলি আরই করতে সক্ষম হওয়া উচিত।
রায়নস

7
@ রায়নোস: যদি অবজেক্টগুলি রাষ্ট্রকে আড়াল করতে ক্লোজার ব্যবহার করে তবে আপনি সেগুলি ক্লোন করতে পারবেন না। সুতরাং 'বন্ধ' শব্দটি। নিমিসজ শেষে বলেছে, সর্বোত্তম উপায় হ'ল ক্লোনিংয়ের জন্য একটি এপিআই পদ্ধতি প্রয়োগ করা (বা সিরিয়ালাইজেশন / ডিসরিয়ালাইজেশন) যদি এটি কোনও বিকল্প হয়।
মিচিয়েল কালকম্যান

@ মিচিয়েলক্লকম্যান আমার কাছে একটি অনুভূতি হয়েছিল যা ঘটেছে। যদিও কারও কারও কাছে এর খুব চতুর সমাধান থাকতে পারে।
রায়নস

এর প্রভাব কী false && item.constructor? তা কি ifঅকেজো নয়?
গ্যাব্রিয়েল পেট্রোয়ে

2
@ গ্যাব্রিয়েলপেট্রোয়ে ifএটি কার্যকরী দৃষ্টিকোণ থেকে 'অকেজো', কারণ এটি কখনই চলবে না, তবে এর একটি অনুমানমূলক বাস্তবায়ন দেখানোর একাডেমিক উদ্দেশ্য রয়েছে যা লেখক পরবর্তীকালে ব্যাখ্যা করার কারণ হিসাবে পরামর্শ দেয় না। সুতরাং, হ্যাঁ, এটি elseশর্তটি মূল্যায়িত করে প্রত্যেকটি ধারাটিকে ট্রিগার করবে , এবং এখনও কোডটি থাকার কারণ রয়েছে।
গুই ইমামুরা

155

খুব সহজ উপায়, খুব সহজ:

var cloned = JSON.parse(JSON.stringify(objectToClone));

12
কোনও অবজেক্টের মান কোনও ক্রিয়াকলাপ না হলে দুর্দান্ত, সেই মুহুর্তে আপনাকে গৃহীত উত্তরের মতো কিছু ব্যবহার করতে হবে। বা cloneDeepলোড্যাশের মতো কোনও সহায়ক ফাংশন ব্যবহার করুন ।
ম্যাথোইল্যান্ড

31
যদি কোনও বস্তুর মান একটি ফাংশন হয় তবে অবজেক্টটি কোনও জেএসএন নয়।
জোস ডি জং

5
কোন ব্যবহারের ক্ষেত্রে কেবল কোনও ক্রিয়াকলাপটি ব্যবহার না করে তার ক্লোন করার ন্যায্যতা থাকতে পারে?
জি। গেজ

3
যদি আমি সঠিকভাবে মনে রাখি তবে এটি তারিখগুলিকে স্ট্রিংয়ে রূপান্তর করে।
পিটার

3
@ জি.গিজ আপনি যদি এমন কোনও ক্লোন ক্লোন করেন যা কোনও ফাংশন ধারণ করে যে ফাংশনটি হারিয়ে যাবে ..
পিটার

38

JSON.parse(JSON.stringify())যেমন JSON তথ্য জন্য অভিপ্রেত ছিল গভীর কপি জাভাস্ক্রিপ্ট বস্তু সমন্বয়, একটি অকার্যকর হ্যাক হয়। এটা তোলে মান সমর্থন করে না undefinedবা function () {}, এবং কেবল তাদের (অথবা উপেক্ষা করা হবে nullতাদের) যখন "stringifying" (marshalling) JSON, জাভাস্ক্রিপ্ট অবজেক্ট।

একটি গভীর সমাধান হ'ল একটি অনুলিপি ফাংশন ব্যবহার করা। গভীর কপিগুলি অবজেক্টগুলির নীচে ফাংশনটির জন্য এবং কোনও তৃতীয় পক্ষের লাইব্রেরি (জিকুয়ারি, লোড্যাশ ইত্যাদি) প্রয়োজন হয় না।

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

7
যখন অ্যাওজেক্ট (বা এটিতে থাকা অন্য কোনও অবজেক্ট) বাদে নিজের কাছে একটি স্ব-রেফারেন্স থাকে ... স্ট্যাকওভারফ্লো ™!
e2-e4

@ রিংø - আপনি কিছু "স্ব-রেফারেন্স" পরীক্ষার কেস সরবরাহ করতে পারেন?
tfmontague

4
var o = { a:1, b:2 } ; o["oo"] = { c:3, m:o };
e2-e4

4
আমি এই সমাধানটি পছন্দ করি। কেবলমাত্র আমার জন্য ঠিক করা bObject[k] = (v === null) ? null : (typeof v === "object") ? copy(v) : v;
ডেভিড কির্কল্যান্ড

2
এই ফাংশনটি সহজ, বোধগম্য এবং প্রায় সব ক্ষেত্রেই ধরা পড়বে। জাভাস্ক্রিপ্ট বিশ্বে যে আপনি পেতে পারেন প্রায় নিখুঁত।
icc97

21

এখানে একটি ES6 ফাংশন যা চক্রীয় রেফারেন্স সহ বস্তুর জন্যও কাজ করবে:

function deepClone(obj, hash = new WeakMap()) {
    if (Object(obj) !== obj) return obj; // primitives
    if (hash.has(obj)) return hash.get(obj); // cyclic reference
    const result = obj instanceof Set ? new Set(obj) // See note about this!
                 : obj instanceof Map ? new Map(Array.from(obj, ([key, val]) => 
                                        [key, deepClone(val, hash)])) 
                 : obj instanceof Date ? new Date(obj)
                 : obj instanceof RegExp ? new RegExp(obj.source, obj.flags)
                 // ... add here any specific treatment for other classes ...
                 // and finally a catch-all:
                 : obj.constructor ? new obj.constructor() 
                 : Object.create(null);
    hash.set(obj, result);
    return Object.assign(result, ...Object.keys(obj).map(
        key => ({ [key]: deepClone(obj[key], hash) }) ));
}

// Sample data
var p = {
  data: 1,
  children: [{
    data: 2,
    parent: null
  }]
};
p.children[0].parent = p;

var q = deepClone(p);

console.log(q.children[0].parent.data); // 1

সেট এবং মানচিত্র সম্পর্কে একটি নোট

কিভাবে সেট এবং মানচিত্রের কী এর মাধ্যমে মোকাবেলা করতে তর্কসাপেক্ষ হল: ঐ চাবিগুলা প্রায়ই প্রিমিটিভের (যে ক্ষেত্রে কোন বিতর্ক আছে), কিন্তু তারা করতে পারেন এছাড়াও বস্তু হতে। সেক্ষেত্রে প্রশ্ন ওঠে: এই কীগুলি ক্লোন করা উচিত?

কেউ তর্ক করতে পারে যে এটি করা উচিত, যাতে those বিষয়গুলি অনুলিপি করা হয়, তবে মূল বস্তুগুলি প্রভাবিত হয় না এবং বিপরীতে।

অন্যদিকে, কেউ চাইবেন যে কোনও সেট / ম্যাপ যদি hasকোনও কী থাকে তবে এটি মূল এবং অনুলিপি উভয় ক্ষেত্রেই সত্য হওয়া উচিত - কমপক্ষে কোনও একটির পরিবর্তনের আগে কোনও পরিবর্তন করা উচিত। অনুলিপি হবে যদি অনুলিপিটি এমন সেট / ম্যাপ হয়ে থাকে যা কীগুলি আগে কখনও ঘটে না (যেমন তারা ক্লোনিং প্রক্রিয়া চলাকালীন তৈরি হয়েছিল): অবশ্যই কোনও কোডের জন্য এটি খুব কার্যকর নয় যা প্রদত্ত বস্তুটি কিনা তা জানা দরকার সেট / মানচিত্রের কী বা না।

আপনি লক্ষ্য করেছেন, আমি দ্বিতীয় মতামতের চেয়ে বেশি: সেট এবং মানচিত্রের কীগুলি মান (সম্ভবত রেফারেন্স ) যা একই থাকবে।

এই জাতীয় পছন্দগুলি প্রায়শই অন্যান্য (সম্ভবত কাস্টম) অবজেক্টগুলির সাথেও প্রকাশিত হয়। কোনও সাধারণ সমাধান নেই, যতটা ক্লোন করা বস্তু আপনার নির্দিষ্ট ক্ষেত্রে আচরণ করবে বলে আশা করা যায় তার উপর নির্ভর করে।


তারিখ এবং
regexp

1
@ মেকেরেমগুক, আপনার মন্তব্যের জন্য ধন্যবাদ। তারিখ এবং রেজিপ্সকে সমর্থন করার জন্য আমি কোডটি আপডেট করেছি।
ট্রিনকোট

মানচিত্র সহ দুর্দান্ত সমাধান। এস 6 সেট ক্লোনিংয়ের জন্য কেবল সমর্থন অনুপস্থিত।
রবার্ট বিগস 5:38

যদি আমি ভুল না হয়ে থাকি তবে আপনি সম্ভবত সেটগুলির সাথে সমর্থনটি যোগ করতে পারেন:if (object instanceof Set) Array.from(object, val => result.add(deepClone(val, hash)));
রবার্ট বিগস

@ রবার্টবিগস, এটিই একটি সম্ভাবনা, তবে আমার মতে যদি কোনও সেটের একটি নির্দিষ্ট কী থাকে তবে সেটি সেটের ক্লোন সংস্করণেও সত্য হওয়া উচিত। আপনার প্রস্তাবিত কোড সহ যদি কীগুলি অবজেক্ট হয় তবে এটি সত্য হবে না। অতএব আমি কীগুলি ক্লোনিং না করার পরামর্শ দেব - আমি সত্যিই মনে করি এটি তখন প্রত্যাশার সাথে আরও আচরণ করবে। এই সম্মানের সাথে আমার উত্তর আপডেট দেখুন।
ট্রিনকোট

10

Underscore.js contrib গ্রন্থাগার গ্রন্থাগার একটি ফাংশন বলা স্ন্যাপশট গভীর ক্লোনস একটি বস্তু যে

উত্স থেকে স্নিপেট:

snapshot: function(obj) {
  if(obj == null || typeof(obj) != 'object') {
    return obj;
  }

  var temp = new obj.constructor();

  for(var key in obj) {
    if (obj.hasOwnProperty(key)) {
      temp[key] = _.snapshot(obj[key]);
    }
  }

  return temp;
}

একবার আপনার প্রকল্পের সাথে গ্রন্থাগারটি সংযুক্ত হয়ে গেলে কেবল ব্যবহার করে ফাংশনটি শুরু করুন

_.snapshot(object);

4
ভাল সমাধান, মনে রাখার জন্য মাত্র একটি পয়েন্ট: ক্লোন এবং মূল একই প্রোটোটাইপ শেয়ার করে। যদি সমস্যাটি "টেম্প .__ প্রোটো__ = .স্নাপশট (আপত্তি । ঠিক "রিটার্ন টেম্প" এর উপরে, এবং 'নোমেট্রেট' হিসাবে চিহ্নিত বৈশিষ্ট্যযুক্ত বিল্ট-ইন ক্লাসগুলিকে সমর্থন করার জন্য আপনি "ফর (ওজ অব কী)" এর পরিবর্তে getOwNPropertyNames () এ পুনরাবৃত্তি করতে পারবেন
রোনেন নেস

3

এটি আমি গভীরতর ক্লোনিং পদ্ধতিটি ব্যবহার করি, আমি এটি দুর্দান্ত মনে করি, আশা করি আপনি পরামর্শ দিবেন

function deepClone (obj) {
    var _out = new obj.constructor;

    var getType = function (n) {
        return Object.prototype.toString.call(n).slice(8, -1);
    }

    for (var _key in obj) {
        if (obj.hasOwnProperty(_key)) {
            _out[_key] = getType(obj[_key]) === 'Object' || getType(obj[_key]) === 'Array' ? deepClone(obj[_key]) : obj[_key];
        }
    }
    return _out;
}

3

অন্যরা যেমন এবং এই জাতীয় প্রশ্নগুলিতে লক্ষ্য করেছে, সাধারণ অর্থে কোনও "অবজেক্ট" ক্লোনিং করা জাভাস্ক্রিপ্টে সন্দেহজনক।

যাইহোক, এখানে একটি শ্রেণীর অবজেক্ট রয়েছে, যাকে আমি "ডেটা" অবজেক্ট বলি, এটি কেবলমাত্র { ... }আক্ষরিক এবং / অথবা সাধারণ সম্পত্তি অ্যাসাইনমেন্ট থেকে তৈরি করা হয়েছে বা জেএসএন থেকে deserialized যার জন্য এটি ক্লোন করতে চান যুক্তিযুক্ত। আজকের দিনে আমি কোনও সার্ভারের কাছ থেকে প্রাপ্ত তথ্য 5x দ্বারা কৃত্রিমভাবে স্ফীত করতে চেয়েছিলাম বড় ডেটা সেটের জন্য কী ঘটেছিল তা পরীক্ষা করার জন্য, তবে জিনিসগুলি সঠিকভাবে কাজ করার জন্য অবজেক্ট (একটি অ্যারে) এবং তার বাচ্চাদের আলাদা আলাদা জিনিস হতে হয়েছিল be ক্লোনিং আমার ডেটা সেটটিকে বহুগুণে এটি করার অনুমতি দিয়েছে:

return dta.concat(clone(dta),clone(dta),clone(dta),clone(dta));

আমি প্রায়শই ডেটা অবজেক্টগুলির ক্লোনিং শেষ করি সেই অন্য স্থানটি হস্টের কাছে ডেটা ফেরত জমা দেওয়ার জন্য যেখানে আমি পাঠানোর আগে ডেটা মডেলটিতে অবজেক্ট থেকে রাষ্ট্র ক্ষেত্রগুলি ছাঁটাই করতে চাই। উদাহরণস্বরূপ, ক্লোন হয়ে যাওয়ার সাথে সাথে আমি অবজেক্ট থেকে "_" দিয়ে শুরু করতে সমস্ত ক্ষেত্রগুলি ছাঁটাই করতে চাই।

এই কোডটি আমি লেখার আগে জেনারিকভাবে এই কাজটি করতে পেরেছি, সমর্থনকারী অ্যারেগুলি এবং কোন নির্বাচককে কোন সদস্য ক্লোন করবেন তা বেছে নিতে (যা প্রসঙ্গ নির্ধারণের জন্য "পথ" স্ট্রিং ব্যবহার করে) সহ:

function clone(obj,sel) {
    return (obj ? _clone("",obj,sel) : obj);
    }

function _clone(pth,src,sel) {
    var ret=(src instanceof Array ? [] : {});

    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }

        var val=src[key], sub;

        if(sel) {
            sub+=pth+"/"+key;
            if(!sel(sub,key,val)) { continue; }
            }

        if(val && typeof(val)=='object') {
            if     (val instanceof Boolean) { val=Boolean(val);        }
            else if(val instanceof Number ) { val=Number (val);        }
            else if(val instanceof String ) { val=String (val);        }
            else                            { val=_clone(sub,val,sel); }
            }
        ret[key]=val;
        }
    return ret;
    }

নন-নাল রুট অবজেক্ট এবং কোনও সদস্য নির্বাচন না করে ধরে নেওয়া সহজতম যুক্তিসঙ্গত গভীর-ক্লোন সমাধান:

function clone(src) {
    var ret=(src instanceof Array ? [] : {});
    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }
        var val=src[key];
        if(val && typeof(val)=='object') { val=clone(val);  }
        ret[key]=val;
        }
    return ret;
    }

2

লো-ড্যাশ , এখন অ্যান্ডস্কোর.জেএস এর সুপারস্টার , বেশ কয়েকটি গভীর ক্লোন ফাংশন রয়েছে:

লেখক নিজেই একটি উত্তর থেকে :

lodash underscore অ্যান্ডকোরের সর্বশেষ স্থিতিশীল সংস্করণের সাথে সামঞ্জস্যতা নিশ্চিত করতে বিল্ড সরবরাহ করা হয়েছে।


প্রশ্নটি বলেছিল "আমি গ্রন্থাগারগুলি ব্যবহার করতে চাই না"
ফেমি ওনি

@ ফেমিওনি প্রশ্নের লাইব্রেরি (এমনকি এটির পুরাতন সম্পাদনাগুলিতে) সম্পর্কে কিছুই নেই ... এখানে আরও কয়েকটি উত্তরও একটি লাইব্রেরি বা অন্য একটি ব্যবহার করছে।
সিপিএইচপিথন

@ ফেমিওনির উত্তর গতকাল হ্রাস পেয়েছে। আমি অবাক হই ... যাইহোক, এটি একটি শেখার জায়গা এবং ঠিক যদি কেউ সত্যই গভীর ক্লোনটি নিজে প্রয়োগ করতে চলেছেbaseClone তবে লোডাস উত্স কোডটি কিছু ধারণা দিতে পারে।
সিপিএইচপিথন

@ ফেমিওনি জেএসওএন অবজেক্টটি কোনও গ্রন্থাগার বা কাঠামো নয় ... আপনি যদি ফাংশনটি বাস্তবায়ন করতে চলেছেন তবে আমি ওপেন সোর্স লাইব্রেরিগুলির মধ্যে একটি সন্ধান করার পরামর্শ দিচ্ছি এবং আপনার প্রয়োজনীয় অংশগুলি ব্যবহার করার পরামর্শ দিচ্ছি (বহু বছর ধরে পরীক্ষা করা হয়েছে)। এটি দীর্ঘমেয়াদে বাগ এবং মিস করা বিবেচনাগুলি এড়াতে পারবে।
সিপিএইচপিথন

2

নীচের ফাংশনটি গভীর ক্লোন জাভাস্ক্রিপ্ট অবজেক্টগুলির সবচেয়ে কার্যকর উপায় way

function deepCopy(obj){
    if (!obj || typeof obj !== "object") return obj;

    var retObj = {};

    for (var attr in obj){
        var type = obj[attr];

        switch(true){
            case (type instanceof Date):
                var _d = new Date();
                _d.setDate(type.getDate())
                retObj[attr]= _d;
                break;

            case (type instanceof Function):
                retObj[attr]= obj[attr];
                break;

            case (type instanceof Array):
                var _a =[];
                for (var e of type){
                    //_a.push(e);
                    _a.push(deepCopy(e));
                }
                retObj[attr]= _a;
                break;

            case (type instanceof Object):
                var _o ={};
                for (var e in type){
                    //_o[e] = type[e];
                    _o[e] = deepCopy(type[e]);
                }
                retObj[attr]= _o;
                break;

            default:
                retObj[attr]= obj[attr];
        }
    }
    return retObj;
}

var obj = {
    string: 'test',
    array: ['1'],
    date: new Date(),
    object:{c: 2, d:{e: 3}},
    function: function(){
        return this.date;
    }
};

var copyObj = deepCopy(obj);

console.log('object comparison', copyObj === obj); //false
console.log('string check', copyObj.string === obj.string); //true
console.log('array check', copyObj.array === obj.array); //false
console.log('date check', copyObj2.date === obj.date); //false
console.log('object check', copyObj.object === obj.object); //false
console.log('function check', copyObj.function() === obj.function()); //true

2
আপনার দাবি সমর্থন করার জন্য আপনার কি কোনও যুক্তি আছে?
ফ্যাবিয়ান ভন এলার্টস

আমি ফাংশন নীচে একটি উদাহরণ দিয়েছি। আপনার কি সন্দেহ আছে?
কোল্ডান্ডি

এই উদাহরণগুলি দেখায় যে ফাংশনটি কাজ করছে, যা দুর্দান্ত তবে এটি "সবচেয়ে কার্যকর উপায়" কেন?
ফ্যাবিয়ান ভন এলার্টস

কারণ এটি পুনরাবৃত্তভাবে একক লুপে অবজেক্টের বৈশিষ্ট্যগুলি অনুলিপি করছে। এছাড়াও তারিখ, ফাংশন, অবজেক্ট, অ্যারে, সংখ্যা, স্ট্রিং সমস্ত থিস সঠিকভাবে পরিচালনা করা হয়। আপনার চারপাশে অন্য কোনও উপায় আছে?
কোল্ডান্ডি

2

এই জাতীয় ফাংশনটির আর কোনও বাস্তব জগতের দরকার নেই। এটি নিছক একাডেমিক আগ্রহ।

খাঁটি অনুশীলন হিসাবে এটি করার এটি আরও কার্যকরী উপায়। আমি @ গিগাবাইট ব্লক যুক্ত করার পরামর্শ দেওয়ার সাথে সাথে এটি @ টিফমন্টীগের উত্তরের বর্ধিতাংশ । তবে আমি ES6 তে বাধ্য হয়ে এবং সমস্ত জিনিসকে কার্যকরী করতে দেখছি, এখানে আমার পিম্পড সংস্করণ। আপনাকে অ্যারের উপরে মানচিত্র তৈরি করতে এবং অবজেক্টের ওপরে হ্রাস করতে হওয়ায় এটি যুক্তিটিকে জটিল করে তোলে তবে এটি কোনও রূপান্তর এড়িয়ে চলে।

const cloner = (x) => {
    const recurseObj = x => (typeof x === 'object') ? cloner(x) : x
    const cloneObj = (y, k) => {
        y[k] = recurseObj(x[k])
        return y
    }
    // Guard blocks
    // Add extra for Date / RegExp if you want
    if (!x) {
        return x
    }
    if (Array.isArray(x)) {
        return x.map(recurseObj)
    }
    return Object.keys(x).reduce(cloneObj, {})
}
const tests = [
    null,
    [],
    {},
    [1,2,3],
    [1,2,3, null],
    [1,2,3, null, {}],
    [new Date('2001-01-01')], // FAIL doesn't work with Date
    {x:'', y: {yx: 'zz', yy: null}, z: [1,2,3,null]},
    {
        obj : new function() {
            this.name = "Object test";
        }
    } // FAIL doesn't handle functions
]
tests.map((x,i) => console.log(i, cloner(x)))


1

আমি লক্ষ্য করেছি যে মানচিত্রটির জন্য বিশেষ চিকিত্সা প্রয়োজন, এই থ্রেডের সমস্ত পরামর্শ সহ কোডটি হবে:

function deepClone( obj ) {
    if( !obj || true == obj ) //this also handles boolean as true and false
        return obj;
    var objType = typeof( obj );
    if( "number" == objType || "string" == objType ) // add your immutables here
        return obj;
    var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
    if( obj instanceof Map )
        for( var key of obj.keys() )
            result.set( key, deepClone( obj.get( key ) ) );
    for( var key in obj )
        if( obj.hasOwnProperty( key ) )
            result[key] = deepClone( obj[ key ] );
    return result;
}

1

সমস্ত উত্তর আমার যোগ

deepCopy = arr => {
  if (typeof arr !== 'object') return arr
  if(arr.pop) return [...arr].map(deepCopy)
  const copy = {}
  for (let prop in arr)
    copy[prop] = deepCopy(arr[prop])
  return copy
}

0

এটি অ্যারে, অবজেক্টস এবং আদিমতার জন্য কাজ করে। সন্দেহজনকভাবে পুনরাবৃত্তির অ্যালগরিদম যা দুটি ট্র্যাভারসাল পদ্ধতির মধ্যে স্যুইচ করে:

const deepClone = (objOrArray) => {

  const copyArray = (arr) => {
    let arrayResult = [];
    arr.forEach(el => {
        arrayResult.push(cloneObjOrArray(el));
    });
    return arrayResult;
  }

  const copyObj = (obj) => {
    let objResult = {};
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        objResult[key] = cloneObjOrArray(obj[key]);
      }
    }
    return objResult;
  }

  const cloneObjOrArray = (el) => {
    if (Array.isArray(el)) {
      return copyArray(el);
    } else if (typeof el === 'object') {
      return copyObj(el);
    } else {
      return el;
    }
  }

  return cloneObjOrArray(objOrArray);
}

0

ডিপকপি তৈরির জন্য আমরা পুনরাবৃত্তিটি কাজে লাগাতে পারি। এটি অ্যারে, অবজেক্ট, অবজেক্টের অ্যারে, ফাংশন সহ অবজেক্টের কপি তৈরি করতে পারে। যদি আপনি চান, আপনি অন্যান্য ধরণের ডেটা স্ট্রাকচারের মতো মানচিত্র ইত্যাদির জন্য ফাংশন যুক্ত করতে পারেন etc.

function deepClone(obj) {
         var retObj;
        _assignProps = function(obj, keyIndex, retObj) {
               var subType = Object.prototype.toString.call(obj[keyIndex]);
               if(subType === "[object Object]" || subType === "[object Array]") {
                    retObj[keyIndex] = deepClone(obj[keyIndex]);
               }
               else {
                     retObj[keyIndex] = obj[keyIndex];
               }
        };

        if(Object.prototype.toString.call(obj) === "[object Object]") {
           retObj = {};
           for(key in obj) {
               this._assignProps(obj, key, retObj);
           }
        }
        else if(Object.prototype.toString.call(obj) == "[object Array]") {
           retObj = [];
           for(var i = 0; i< obj.length; i++) {
              this._assignProps(obj, i, retObj);
            }
        };

        return retObj;
    };

0

অপরিবর্তনীয় জেএস ব্যবহার করুন

import { fromJS } from 'immutable';

// An object we want to clone
let objA = { 
   a: { deep: 'value1', moreDeep: {key: 'value2'} } 
};

let immB = fromJS(objA); // Create immutable Map
let objB = immB.toJS(); // Convert to plain JS object

console.log(objA); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }
console.log(objB); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }

// objA and objB are equalent, but now they and their inner objects are undependent
console.log(objA === objB); // false
console.log(objA.a === objB.a); // false
console.log(objA.moreDeep === objB.moreDeep); // false

অথবা লোডাশ / মার্জ করুন

import merge from 'lodash/merge'

var objA = {
    a: [{ 'b': 2 }, { 'd': 4 }]
};
// New deeply cloned object:
merge({}, objA ); 

// We can also create new object from several objects by deep merge:
var objB = {
    a: [{ 'c': 3 }, { 'e': 5 }]
};
merge({}, objA , objB ); // Object { a: [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }

0

বিজ্ঞপ্তি রেফারেন্স ব্যবহার করে এটি আমার পক্ষে কাজ করে

 //a test-object with circular reference :
 var n1 = {   id:0,   text:"aaaaa",   parent:undefined} 
 var n2 = {  id:1,   text:"zzzzz",   parent:undefined } 
 var o = { arr:[n1,n2],   parent:undefined } 
 n1.parent = n2.parent = o;
 var obj = {   a:1,   b:2,   o:o }
 o.parent = obj;

 function deepClone(o,output){ 

     if(!output) output = {};  
     if(o.______clone) return o.______clone;
     o.______clone = output.______clone = output;

   for(var z in o){

     var obj = o[z];
     if(typeof(obj) == "object") output[z] = deepClone(obj)
     else output[z] = obj; 
    }

   return output;
}

console.log(deepClone(obj));

0

var newDate = নতুন তারিখ (this.oldDate); আমি পুরনো তারিখটি ফাংশনটিতে পাস করছিলাম এবং এই.ওল্ড তারিখ থেকে নতুন তারিখ উত্পন্ন করছিলাম, তবে এটি এই ডাবলডেটকেও পরিবর্তন করছিল o সুতরাং আমি সেই সমাধানটি ব্যবহার করেছি এবং এটি কাজ করেছে।


0

[... লক্ষ্য] বা {... লক্ষ্য {ব্যবহার করার সময় এই সমাধান পুনরাবৃত্তি সমস্যাগুলি এড়াতে পারে

function shallowClone(target) {
  if (typeof a == 'array') return [...target]
  if (typeof a == 'object') return {...target}
  return target
}

/* set skipRecursion to avoid throwing an exception on recursive references */
/* no need to specify refs, or path -- they are used interally */
function deepClone(target, skipRecursion, refs, path) {
  if (!refs) refs = []
  if (!path) path = ''
  if (refs.indexOf(target) > -1) {
    if (skipRecursion) return null
    throw('Recursive reference at ' + path)
  }
  refs.push(target)
  let clone = shallowCopy(target)
  for (i in target) target[i] = deepClone(target, refs, path + '.' + i)
  return clone
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.