javascript - webcoachbd - জাভাস্ক্রিপ্ট লুপ




কিভাবে আমি সঠিকভাবে একটি জাভাস্ক্রিপ্ট বস্তুর ক্লোন করবেন? (20)

আমি একটি বস্তু আছে, x । আমি বস্তু y হিসাবে এটি অনুলিপি করতে চাই, যেমন y পরিবর্তন x পরিবর্তন করে না। আমি বুঝতে পেরেছি যে অন্তর্নির্মিত জাভাস্ক্রিপ্ট বস্তুর থেকে প্রাপ্ত বস্তু অনুলিপি করা অতিরিক্ত, অবাঞ্ছিত বৈশিষ্ট্যগুলির ফলস্বরূপ হবে। এটি একটি সমস্যা নয়, যেহেতু আমি নিজের একটি, আক্ষরিক-নির্মিত বস্তুর অনুলিপি করছি।

কিভাবে আমি সঠিকভাবে একটি জাভাস্ক্রিপ্ট বস্তুর ক্লোন করবেন?


একটি লাইন কোড একটি জাভাস্ক্রিপ্ট বস্তুর ক্লোন একটি মার্জিত উপায়

একটি Object.assign পদ্ধতি ECMAScript 2015 (ES6) মানদন্ডের অংশ এবং আপনার যা দরকার তা ঠিক করে।

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

Object.assign () পদ্ধতিটি এক বা একাধিক উত্স বস্তু থেকে লক্ষ্যবস্তু বস্তুর সমস্ত সংখ্যাসূচক নিজের বৈশিষ্ট্যগুলির মানগুলি অনুলিপি করার জন্য ব্যবহৃত হয়।

আরও পড়ুন ...

পুরানো ব্রাউজার সমর্থন করার জন্য পলিফিল :

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

AngularJS ব্যবহার করে যারা, এই লাইব্রেরিতে বস্তু cloning বা প্রসারিত করার জন্য সরাসরি পদ্ধতি আছে।

var destination = angular.copy(source);

অথবা

angular.copy(source, destination);

Angular.copy documentation ...


JQuery দিয়ে, আপনি extend সঙ্গে অগভীর কপি করতে পারেন:

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

copyiedObject পরবর্তী পরিবর্তন মূল Object প্রভাবিত করবে না, এবং বিপরীত।

অথবা একটি গভীর কপি করতে :

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

অনেক উত্তর আছে, কিন্তু Object.create 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

কেন আমি এই সমাধান উচ্চতর বিবেচনা? এটা নেটিভ, এইভাবে কোন looping, কোন recursion। যাইহোক, পুরানো ব্রাউজার একটি পলিফিল প্রয়োজন হবে।


আপনি কেবল রেফারেন্স ছাড়া একটি বস্তুর অনুলিপি করতে একটি স্প্রেড সম্পত্তি ব্যবহার করতে পারেন। কিন্তু সতর্কতা অবলম্বন করুন (মন্তব্য দেখুন), 'অনুলিপি' সর্বনিম্ন বস্তু / অ্যারে স্তরের উপর। নেস্টেড বৈশিষ্ট্য এখনও রেফারেন্স!

সম্পূর্ণ ক্লোন:

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


আপনি যদি আপনার বস্তুর মধ্যে ফাংশনগুলি ব্যবহার করেন না, তবে একটি খুব সাধারণ এক লাইনার নিম্নলিখিত হতে পারে:

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

এটি বস্তু, অ্যারে, স্ট্রিং, বুলিয়ান এবং সংখ্যা ধারণকারী সমস্ত ধরনের বস্তুর জন্য কাজ করে।

ব্রাউজারগুলির গঠনযুক্ত ক্লোন অ্যালগরিদম সম্পর্কে এই নিবন্ধটি দেখুন যা কোনও কর্মীকে এবং তার থেকে বার্তা পোস্ট করার সময় ব্যবহৃত হয়। এটি গভীর cloning জন্য একটি ফাংশন রয়েছে।


একটি বিশেষভাবে মার্জিত সমাধান সদস্য পদ্ধতি নেই এমন বস্তুর গভীর কপি তৈরি করতে JSON এনকোডিং ব্যবহার করা হয়। পদ্ধতি JSON আপনার লক্ষ্য বস্তু এনকোড হয়, তারপর এটি ডিকোডিং দ্বারা, আপনি যে কপি খুঁজছেন আপনি পেতে। আপনি প্রয়োজন হিসাবে অনেক কপি করতে চান হিসাবে আপনি অনেক বার ডিকোড করতে পারেন।

অবশ্যই, ফাংশন JSON এর অন্তর্গত নয়, তাই এটি শুধুমাত্র সদস্য পদ্ধতি ছাড়া বস্তুর জন্য কাজ করে।

এই পদ্ধতিটি আমার ব্যবহারের ক্ষেত্রে নিখুঁত ছিল, যেহেতু আমি একটি কী-মান স্টোরের মধ্যে JSON Blobs সংরক্ষণ করছি, এবং যখন তারা JavaScript 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

এলি এর উত্তর প্রায় সম্পূর্ণ, এখানে আমার সামান্য অবদান: পুনরাবৃত্তিমূলক রেফারেন্সগুলি কীভাবে পরিচালনা করবেন তার একটি উপায় রয়েছে , এই লাইনটি দেখুন

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

যদি বস্তু এক্সএমএল ডোম উপাদান হয়, তবে আমাদের পরিবর্তে ক্লোনডোড ব্যবহার করতে হবে

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

উত্তর এন্ডি Burke এর নোট দেখুন।


MDN প্রতি:

  • আপনি অগভীর অনুলিপি চান, Object.assign({}, a)
  • "গভীর" কপি জন্য, JSON.parse(JSON.stringify(a)) ব্যবহার JSON.parse(JSON.stringify(a))

বাহ্যিক লাইব্রেরিগুলির জন্য কোন প্রয়োজন নেই তবে আপনাকে প্রথমে ব্রাউজারের সামঞ্জস্য পরীক্ষা করতে হবে।


ঠিক আছে, কল্পনা করুন আপনার নীচের এই বস্তু আছে এবং আপনি এটি ক্লোন করতে চান:

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

অথবা

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

ES6+ এ আপনি যে ECMAscript ব্যবহার করছেন তার উত্তরটি মূলত বঞ্চিত করা হয়েছে, আপনি কেবল Object.assign করার জন্য 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

এখানে আপনি ব্যবহার করতে পারেন একটি ফাংশন।

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

লোডশ ব্যবহার করে:

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

ES-6 তে আপনি সহজেই Object.assign ব্যবহার করতে পারেন (...)। উদা:

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

এখানে একটি ভাল রেফারেন্স রয়েছে: https://googlechrome.github.io/samples/object-assign-es6/


আপনি একটি বস্তুর ক্লোন করতে পারেন এবং কোডের একক লাইন ব্যবহার করে পূর্ববর্তী থেকে কোনও রেফারেন্স মুছে ফেলতে পারেন। শুধু করুন:

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

বর্তমানে ব্রাউজার / ইঞ্জিনগুলির জন্য যা অবজেক্টকে সমর্থন করে না। আপনি এই পলিফিলটি ব্যবহার করতে পারেন:

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

আমি শুধু Object.createএই পোস্টে সমস্ত সমাধান যুক্ত করতে চেয়েছিলাম , এটি নোডজেসের সাথে পছন্দসই ভাবে কাজ করে না।

ফায়ারফক্স এর ফলাফল

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

হয়

{test:"test"}

এটা nodejs হয়

{}


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

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

জন টুর্নন এর উত্তর খুব কাছাকাছি, এবং সামঞ্জস্যের সমস্যাগুলির কারণে ব্রাউজারে ব্যবহার করা সেরা হতে পারে, তবে এটি সম্ভবত কিছু অদ্ভুত গণনার সমস্যা সৃষ্টি করবে। উদাহরণস্বরূপ, নির্বাহ:

for ( var i in someArray ) { ... }

অ্যারের উপাদানগুলির মাধ্যমে পুনরাবৃত্তি করার পরে আমি ক্লোন () পদ্ধতিটি বরাদ্দ করব। এখানে একটি অভিযোজন যা গণনা এড়ানো এবং node.js দিয়ে কাজ করে:

Object.defineProperty( Object.prototype, "clone", {
    value: 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;
    }
});

Object.defineProperty( Date.prototype, "clone", {
    value: function() {
        var copy = new Date();
        copy.setTime( this.getTime() );
        return copy;
    }
});

Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } );

এটি ক্লোন () পদ্ধতিকে সংখ্যাসূচক করতে বাধা দেয় কারণ defineProperty () মিথ্যাতে সংখ্যার ডিফল্ট।


যেহেতু mindeavor বলা হয়েছে যে ক্লোন করা বস্তুটি একটি 'আক্ষরিক-নির্মিত' বস্তু, বস্তুর একটি উদাহরণ ক্লোন করার পরিবর্তে কেবলমাত্র বস্তুটিকে একাধিকবার উৎপন্ন করার একটি সমাধান হতে পারে :

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

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

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




clone