অগভীর একত্রীকরণের পরিবর্তে গভীর মার্জ কীভাবে?


339

অবজেক্ট.অ্যাসাইন এবং অবজেক্ট উভয়ই কেবল অগভীর মার্জ করে।

সমস্যার উদাহরণ:

// No object nesting
const x = { a: 1 }
const y = { b: 1 }
const z = { ...x, ...y } // { a: 1, b: 1 }

আউটপুটটি আপনি প্রত্যাশা করতেন। তবে আমি যদি এটি চেষ্টা করি:

// Object nesting
const x = { a: { a: 1 } }
const y = { a: { b: 1 } }
const z = { ...x, ...y } // { a: { b: 1 } }

পরিবর্তে

{ a: { a: 1, b: 1 } }

তুমি পাও

{ a: { b: 1 } }

এক্স সম্পূর্ণরূপে ওভাররাইট করা হয়েছে কারণ স্প্রেড সিনট্যাক্সটি কেবল এক স্তর গভীরে যায়। এটিও একই রকম Object.assign()

এই কাজ করতে একটি উপায় আছে কি?


এক জিনিস থেকে অন্য বস্তুতে অনুলিপি করার মতো কি গভীরভাবে মার্জ করা হচ্ছে?

2
না, বস্তুর বৈশিষ্ট্যগুলিকে ওভাররাইট করা উচিত নয়, বরং প্রতিটি শিশু বস্তু যদি ইতিমধ্যে বিদ্যমান থাকে তবে লক্ষ্যবস্তুতে একই সন্তানের সাথে একত্রী করা উচিত।
মাইক 6

ইএস final চূড়ান্ত হয়েছে এবং নতুন বৈশিষ্ট্যগুলি আর যুক্ত করা হবে না, এএফআইএকে।
কঙ্গাক্স


1
@ অরিওলকে যদিও jQuery প্রয়োজন ...
এম0meni

উত্তর:


331

ES6 / ES7 অনুমানে গভীর সংশ্লেষের উপস্থিত রয়েছে কিনা কেউ কি জানেন?

না, তা হয় না।


21
সম্পাদনা ইতিহাস পর্যালোচনা করুন। আমি এটির উত্তর দিয়েছিলাম এমন সময়, প্রশ্নটি ছিল যে ES6 / ES7 অনুমানে গভীর সংশ্লেষ বিদ্যমান কিনা তা কি কেউ জানেন?

37
এই উত্তরটি এখন আর এই প্রশ্নের জন্য প্রযোজ্য নয় - এটি আপডেট করা বা মুছে ফেলা উচিত
ডোনভন

13
প্রশ্নটি এই ডিগ্রীতে সম্পাদিত করা উচিত হয়নি। সম্পাদনাগুলি স্পষ্ট করার জন্য। একটি নতুন প্রশ্ন পোস্ট করা উচিত ছিল।
সিজে থম্পসন

170

আমি জানি এটি কিছুটা পুরানো সমস্যা তবে ES2015 / ES6 এর মধ্যে সবচেয়ে সহজ সমাধানটি আমি সামনে আসতে পেরেছিলাম যা আসলে অবজেক্ট.সেসাইন () ব্যবহার করে বেশ সহজ ছিল,

আশা করি এটি সাহায্য করে:

/**
 * Simple object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item));
}

/**
 * Deep merge two objects.
 * @param target
 * @param ...sources
 */
export function mergeDeep(target, ...sources) {
  if (!sources.length) return target;
  const source = sources.shift();

  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }

  return mergeDeep(target, ...sources);
}

ব্যবহারের উদাহরণ:

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }

নীচের উত্তরে আপনি এর একটি অপরিবর্তনীয় সংস্করণ পাবেন।

নোট করুন যে এটি বিজ্ঞপ্তি সংক্রান্ত রেফারেন্সগুলিতে অসীম পুনরাবৃত্তির দিকে পরিচালিত করবে। বিজ্ঞপ্তি সংক্রান্ত রেফারেন্সগুলি কীভাবে সনাক্ত করতে হয় সে সম্পর্কে এখানে কিছু দুর্দান্ত উত্তর রয়েছে আপনি যদি ভাবেন যে আপনি এই সমস্যার মুখোমুখি হয়েছিলেন।


1
যদি আপনার অবজেক্ট গ্রাফটিতে এমন চক্র থাকে যা অসীম পুনরাবৃত্তির দিকে পরিচালিত করে
The8472

2
কেন এটি লিখুন: Object.assign(target, { [key]: {} })যদি এটি সহজভাবে হতে পারে target[key] = {}?
জার্গ লেহনী

1
... এবং এর target[key] = source[key]পরিবর্তেObject.assign(target, { [key]: source[key] });
জার্গ লেহনী

3
এটি এতে কোনও অপ-সরল অবজেক্টকে সমর্থন করে না target। উদাহরণস্বরূপ, mergeDeep({a: 3}, {a: {b: 4}})একটি বর্ধিত Numberবস্তুর ফলাফল হবে , যা স্পষ্টভাবে পছন্দসই নয়। এছাড়াও, isObjectঅ্যারে গ্রহণ করে না, তবে অন্য কোনও নেটিভ অবজেক্টের ধরণ গ্রহণ করে যেমন Dateগভীর অনুলিপি করা উচিত নয়।
রিভ

2
আমি বুঝতে পারছি এটি অ্যারে নিয়ে কাজ করে না?
বেদমন্ত

121

আপনি লোডাশ মার্জটি ব্যবহার করতে পারেন :

var object = {
  'a': [{ 'b': 2 }, { 'd': 4 }]
};

var other = {
  'a': [{ 'c': 3 }, { 'e': 5 }]
};

_.merge(object, other);
// => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }

6
ওহে লোকেরা, এটি হ'ল সহজ এবং সর্বাধিক সুন্দর সমাধান। লোডাশ দুর্দান্ত, তাদের এটিকে মূল
জেএস

11
ফলাফল হওয়া উচিত নয় { 'a': [{ 'b': 2 }, { 'c': 3 }, { 'd': 4 }, { 'e': 5 }] }?
জে হিস্টার

ভাল প্রশ্ন. এটি আলাদা প্রশ্ন বা লোডাশ রক্ষণাবেক্ষণকারীদের জন্য একটি হতে পারে।
অ্যান্ড্রুহেন্ডারসন

7
ফলাফলটি { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }সঠিক, কারণ আমরা একটি অ্যারের উপাদানগুলি মার্জ করছি। উপাদান 0এর object.aহয় {b: 2}উপাদান 0এর other.aহয় {c: 3}। যখন এই দুটি একত্রীকরণ করা হয় কারণ তাদের একই অ্যারে সূচক হয়, ফলাফল হয় { 'b': 2, 'c': 3 }যা 0নতুন বস্তুর উপাদান ।
আলেকজান্দ্রু ফুরকুলিটা

আমি পছন্দ এই এক , এটা 6x ছোট gzipped আছে।
একক

101

সমস্যাটি যখন অপ্রয়োজনীয় বা হোস্টিং অবজেক্ট বা কোনও ধরণের অবজেক্টের ক্ষেত্রে আসে যেখানে মানগুলির ব্যাগের চেয়ে জটিল

  • আপনি কি কোনও প্রাপ্তির কাছে কোনও মূল্য পেতে অনুরোধ করেন বা আপনি সম্পত্তি বর্ণনাকারীর অনুলিপি করেন?
  • যদি মার্জ টার্গেটটির একটি সেটার থাকে (হয় তার নিজস্ব সম্পত্তি বা এর প্রোটোটাইপ শৃঙ্খলে থাকে)? আপনি কি মানটিকে ইতিমধ্যে উপস্থিত হিসাবে বিবেচনা করেন বা বর্তমান মানটি আপডেট করার জন্য সেটারকে কল করেন?
  • আপনি কি নিজের সম্পত্তি ফাংশন প্রার্থনা করেন বা তাদের অনুলিপি করেন? যদি তারা নির্ধারিত সময়ে তাদের স্কোপ চেইনের কোনও কিছুর উপর নির্ভর করে ফাংশন বা তীর ফাংশনগুলি আবদ্ধ হয় তবে কী হবে?
  • যদি এটি কোনও ডোম নোডের মতো কিছু হয়? আপনি অবশ্যই এটিকে সাধারণ অবজেক্ট হিসাবে বিবেচনা করতে এবং এর সমস্ত বৈশিষ্ট্যকে গভীরভাবে মার্জ করতে চান না
  • অ্যারে বা মানচিত্র বা সেটগুলির মতো "সাধারণ" কাঠামোগুলি কীভাবে মোকাবেলা করবেন? তাদের ইতিমধ্যে উপস্থিত বিবেচনা করুন বা তাদের খুব একীভূত?
  • অগণিত নিজস্ব বৈশিষ্ট্যগুলি কীভাবে মোকাবেলা করবেন?
  • নতুন সাবট্রির কী হবে? কেবল রেফারেন্স বা গভীর ক্লোন দ্বারা নির্ধারিত?
  • হিমায়িত / সিল করা / অ-এক্সটেনসিবল অবজেক্টগুলির সাথে কীভাবে व्यवहार করবেন?

আরেকটি বিষয় মনে রাখবেন: গ্রাফগুলিতে চক্র রয়েছে। এটি মোকাবেলা করা সাধারণত কঠিন নয় - কেবল একটি রাখুন keepSet ইতিমধ্যে পরিদর্শন করা উত্স অবজেক্টগুলির একটি রাখুন - তবে প্রায়শই ভুলে যান।

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

অন্য কথায়, কোনও এক-আকারের-ফিট-সব অ্যালগরিদম নেই, আপনাকে হয় নিজস্ব রোল করতে হবে বা আপনার ব্যবহারের কেসগুলি কভার করার জন্য ঘটে এমন একটি লাইব্রেরির পদ্ধতি সন্ধান করতে হবে।


2
ভি 8
ডিভসকে

আপনি অনেক ভাল ইস্যু উত্থাপন করেন এবং আমি আপনার প্রস্তাবনার বাস্তবায়ন দেখতে পছন্দ করতাম। তাই আমি নীচে একটি করার চেষ্টা করেছি। আপনি দয়া করে একটি চেহারা এবং মন্তব্য করতে পারেন? stackoverflow.com/a/48579540/8122487
RaphaMex

66

এখানে @ সালাকার উত্তরের একটি অপরিবর্তনীয় (ইনপুটগুলি সংশোধন করে না) সংস্করণ দেওয়া আছে। কার্যকর যদি আপনি কার্যকরী প্রোগ্রামিং টাইপ স্টাফ করছেন।

export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item));
}

export default function mergeDeep(target, source) {
  let output = Object.assign({}, target);
  if (isObject(target) && isObject(source)) {
    Object.keys(source).forEach(key => {
      if (isObject(source[key])) {
        if (!(key in target))
          Object.assign(output, { [key]: source[key] });
        else
          output[key] = mergeDeep(target[key], source[key]);
      } else {
        Object.assign(output, { [key]: source[key] });
      }
    });
  }
  return output;
}

1
@ টোরাজাবুরো আইজ অব ফাংশনের জন্য আমার আগের পোস্টটি দেখুন
সালাকার

এটি আপডেট। কিছু পরীক্ষার পরে আমি গভীরভাবে নেস্টেড বস্তুগুলির সাথে একটি বাগ পেয়েছি
সিপিআইএলিল

3
এটি একটি গণনা করা সম্পত্তির নাম, প্রথমে keyসম্পত্তির নাম হিসাবে মানটি ব্যবহার করবে , পরে সম্পত্তিটির নাম "কী" করবে will দেখুন: es6-features.org/# CompompPPerertyNames
CpIL

2
মধ্যে isObjectআপনি না পরীক্ষা প্রয়োজন হবে না && item !== null, শেষে কারণ সঙ্গে সঙ্গতিপূর্ণ শুরু item &&, তাই না?
ইফেমার

2
যদি উত্সটি লক্ষ্যমাত্রার চেয়েও গভীরভাবে শিশুদের বস্তুগুলিকে বাসা বেঁধে রাখে তবে objects অবজেক্টগুলি এখনও একই মানগুলির mergedDeepআউটপুটে রেফারেন্স দেবে (আমার মনে হয়)। উদাহরণস্বরূপ const target = { a: 1 }; const source = { b: { c: 2 } }; const merged = mergeDeep(target, source); merged.b.c; // 2 source.b.c = 3; merged.b.c; // 3 এটি একটি সমস্যা? এটি ইনপুটগুলিকে রূপান্তরিত করে না, তবে ভবিষ্যতের ইনপুটগুলিতে ভবিষ্যতের কোনও রূপান্তর আউটপুটকে রূপান্তর করতে পারে এবং তদ্বিপরীত ডব্লু / মিউটেশনগুলিকে আউটপুট মিউটিং ইনপুটগুলিতে রূপান্তর করতে পারে। এটি মূল্যবান কি জন্য, যদিও, রামদা এর R.merge()একই আচরণ আছে।
জেমস কনকলিং

40

যেহেতু এই সমস্যাটি এখনও সক্রিয়, তাই এখানে আরও একটি পদ্ধতির উপায় রয়েছে:

  • ES6 / 2015
  • অপরিবর্তনীয় (মূল বিষয়গুলি সংশোধন করে না)
  • অ্যারে পরিচালনা করে (তাদের সাথে সম্মতি জানায়)

/**
* Performs a deep merge of objects and returns new object. Does not modify
* objects (immutable) and merges arrays via concatenation.
*
* @param {...object} objects - Objects to merge
* @returns {object} New object with merged key/values
*/
function mergeDeep(...objects) {
  const isObject = obj => obj && typeof obj === 'object';
  
  return objects.reduce((prev, obj) => {
    Object.keys(obj).forEach(key => {
      const pVal = prev[key];
      const oVal = obj[key];
      
      if (Array.isArray(pVal) && Array.isArray(oVal)) {
        prev[key] = pVal.concat(...oVal);
      }
      else if (isObject(pVal) && isObject(oVal)) {
        prev[key] = mergeDeep(pVal, oVal);
      }
      else {
        prev[key] = oVal;
      }
    });
    
    return prev;
  }, {});
}

// Test objects
const obj1 = {
  a: 1,
  b: 1, 
  c: { x: 1, y: 1 },
  d: [ 1, 1 ]
}
const obj2 = {
  b: 2, 
  c: { y: 2, z: 2 },
  d: [ 2, 2 ],
  e: 2
}
const obj3 = mergeDeep(obj1, obj2);

// Out
console.log(obj3);


এটা সুন্দর. তবে যখন আমরা বারবার উপাদানগুলির সাথে অ্যারে থাকি তখন এগুলি সংমিশ্রিত হয় (পুনরাবৃত্ত উপাদান রয়েছে)। আমি এটি একটি প্যারামিটার নিতে অভিযোজিত (অ্যারে অনন্য: সত্য / মিথ্যা)।
নভোচারী

1
অ্যারে অনন্য করতে আপনি পরিবর্তন করতে পারেন prev[key] = pVal.concat(...oVal);থেকেprev[key] = [...pVal, ...oVal].filter((element, index, array) => array.indexOf(element) === index);
রিচার্ড Herries

1
খুব সুন্দর এবং পরিষ্কার !! অবশ্যই এখানে সেরা উত্তর!
538 রোমো

মহিমান্বিত। এইটি অ্যারে মার্জ হয়ে যায় তাও দেখায়, যা আমি খুঁজছিলাম।
তুষাল্লাকা

হ্যাঁ, @ সিপিএলএলএল দ্রবণটি অপরিবর্তনীয় বলে মনে হয় তবে ব্যবহারের সময় ফাংশনের অভ্যন্তরে প্রকৃত অবজেক্ট মিউটিবিলিটি ব্যবহার reduce করে।
আগস্টিন রিডিংগার

30

আমি জানি ইতিমধ্যে প্রচুর উত্তর রয়েছে এবং তত যুক্তিযুক্ত যে তারা কাজ করবে না। একমাত্র sensক্যমত্য এটি এত জটিল যে এটির জন্য কেউ কোনও মানক তৈরি করেনি । তবে এসও-তে গৃহীত বেশিরভাগ উত্তরগুলি "সরল কৌশলগুলি" প্রকাশ করে যা ব্যাপকভাবে ব্যবহৃত হয়। সুতরাং, আমাদের মতো আমাদের মতো যারা বিশেষজ্ঞ নন তবে জাভাস্ক্রিপ্টের জটিলতা সম্পর্কে আরও কিছুটা উপলব্ধি করে নিরাপদ কোডটি লিখতে চান, আমি কিছুটা আলোকপাত করার চেষ্টা করব।

আমাদের হাত নোংরা করার আগে, আমি 2 পয়েন্টগুলি স্পষ্ট করে বলি:

  • [DISCLAIMER পড়ুন] আমি যে ধরেছেন কিভাবে আমরা নিচে একটি ফাংশন প্রস্তাব গভীর লুপ মধ্যে javascript অবজেক্ট কপি এবং প্রকাশ করে কি সাধারণত খুব খুব শীঘ্রই মন্তব্য নেই। এটি উত্পাদন-প্রস্তুত নয়। স্পষ্টতার স্বার্থে, আমি উদ্দেশ্য নিয়ে বৃত্তাকার বস্তুগুলি (একটি সেট বা অনিচ্ছাকৃত প্রতীক সম্পত্তি দ্বারা ট্র্যাক) , রেফারেন্স মান বা গভীর ক্লোন অনুলিপি , অপরিবর্তনীয় গন্তব্য অবজেক্ট (আবার গভীর ক্লোন?), কেস-বাই-কেস স্টাডির মতো বিষয় বিবেচনা বাদ দিয়েছি cla প্রতিটি ধরণের অবজেক্টস , অ্যাক্সেসরের মাধ্যমে সম্পত্তি সেট / সেট করুন ... এছাড়াও, আমি পারফরম্যান্স পরীক্ষা করিনি - এটি যথেষ্ট গুরুত্বপূর্ণ - কারণ এটি এখানে বিন্দুও নয়।
  • আমি ব্যবহার করব কপি বা বরাদ্দ পরিবর্তে পদ একত্রীকরণ । কারণ আমার মনে একীভূত হওয়া রক্ষণশীল এবং বিরোধের ক্ষেত্রে ব্যর্থ হওয়া উচিত। এখানে, বিরোধের সময়, আমরা উত্সটি গন্তব্যটিকে ওভাররাইট করতে চাই। যেমন Object.assignকরে।

উত্তরগুলি for..inবা Object.keysবিভ্রান্তিমূলক

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

আমি যখন প্রথম পড়তে Salakar এর উত্তর , আমি সত্যি সত্যি মনে হয়েছে আমি আরো ভালো করতে পারে এবং সহজ (আপনার সাথে এটা তুলনা করতে পারবেন Object.assignউপর x={a:1}, y={a:{b:1}})। তারপরে আমি 848472 এর উত্তরটি পড়েছিলাম এবং আমি ভেবেছিলাম ... এত সহজে কোনও দূরে সরে যায় না, ইতিমধ্যে প্রদত্ত উত্তরগুলির উন্নতি আমাদের এতদূর পাবে না।

আসুন গভীর অনুলিপি এবং একটি তাত্ক্ষণিক সরাইয়া যাক। খুব সহজ বিষয়টিকে অনুলিপি করতে কীভাবে (ভুলভাবে) লোকেরা সম্পত্তিগুলি পার্স করে তা বিবেচনা করুন।

const y = Object.create(
    { proto : 1 },
    { a: { enumerable: true, value: 1},
      [Symbol('b')] : { enumerable: true, value: 1} } )

Object.assign({},y)
> { 'a': 1, Symbol(b): 1 } // All (enumerable) properties are copied

((x,y) => Object.keys(y).reduce((acc,k) => Object.assign(acc, { [k]: y[k] }), x))({},y)
> { 'a': 1 } // Missing a property!

((x,y) => {for (let k in y) x[k]=y[k];return x})({},y)
> { 'a': 1, 'proto': 1 } // Missing a property! Prototype's property is copied too!

Object.keysনিজস্ব অ-গণনাযোগ্য বৈশিষ্ট্য, নিজস্ব প্রতীক-কীড বৈশিষ্ট্য এবং সমস্ত প্রোটোটাইপের বৈশিষ্ট্য বাদ দেবে। আপনার জিনিসগুলিতে এর কোনও একটি না থাকলে এটি ঠিক হতে পারে। তবে এটি মনে রাখবেন যে Object.assignনিজস্ব প্রতীক-কীডযুক্ত অসংখ্য গুণাবলী পরিচালনা করে। সুতরাং আপনার কাস্টম অনুলিপিটি তার পুষ্প হারিয়েছে।

for..inউত্সটির প্রোটোটাইপ এবং সম্পূর্ণ প্রোটোটাইপ শৃঙ্খলে আপনাকে না চাওয়ার (বা এটি না জেনে) বৈশিষ্ট্য সরবরাহ করবে। প্রোটোটাইপ বৈশিষ্ট্য এবং নিজস্ব বৈশিষ্ট্যগুলি মিশ্রণ করে আপনার লক্ষ্যটি অনেক বেশি সংখ্যক বৈশিষ্ট্যের সাথে শেষ হতে পারে।

আপনি যদি একটি সাধারণ কাজের ফাংশন লেখার করে থাকেন এবং ব্যবহার করছেন না Object.getOwnPropertyDescriptors, Object.getOwnPropertyNames, Object.getOwnPropertySymbolsবা Object.getPrototypeOf, আপনি সম্ভবত এটা ভুল করছেন।

আপনার ফাংশনটি লেখার আগে বিবেচনা করার বিষয়গুলি

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

একটি সম্পত্তি কী ( stringবা symbol) এবং বর্ণনাকারী ( valueবা get/ setঅ্যাকসেসর ) এবং এর মতো বৈশিষ্ট্যগুলির একটি জুড়িenumerable ) এর ।

অবশেষে, অনেক ধরণের অবজেক্ট রয়েছে । আপনি কোনও অবজেক্টের তারিখ বা অবজেক্ট ফাংশন থেকে কোনও অবজেক্ট অবজেক্টকে আলাদাভাবে পরিচালনা করতে চাইতে পারেন।

সুতরাং, আপনার গভীর অনুলিপিটি লিখে আপনার কমপক্ষে এই প্রশ্নের উত্তর দেওয়া উচিত:

  1. আমি গভীর (পুনরাবৃত্ত চেহারা জন্য উপযুক্ত) বা ফ্ল্যাট কী বিবেচনা করব?
  2. আমি কোন সম্পত্তি অনুলিপি করতে চান? (গণনাযোগ্য / অ-গণনাযোগ্য, স্ট্রিং-কিড / সিম্বল-কিড, নিজস্ব বৈশিষ্ট্য / প্রোটোটাইপের নিজস্ব বৈশিষ্ট্য, মান / বর্ণনাকারী ...)

আমার উদাহরণস্বরূপ, আমি বিবেচনা করি যে কেবলমাত্র object Objectগুলি গভীর , কারণ অন্যান্য নির্মাণকারীর দ্বারা তৈরি অন্যান্য বস্তুগুলি গভীর -বর্ণের জন্য উপযুক্ত নাও হতে পারে। এই এসও থেকে কাস্টমাইজড ।

function toType(a) {
    // Get fine type (object, array, function, null, error, date ...)
    return ({}).toString.call(a).match(/([a-z]+)(:?\])/i)[1];
}

function isDeepObject(obj) {
    return "Object" === toType(obj);
}

এবং আমি optionsকী অনুলিপি করতে হবে তা বেছে নিতে একটি বস্তু তৈরি করেছি (ডেমো উদ্দেশ্যে) for

const options = {nonEnum:true, symbols:true, descriptors: true, proto:true};

প্রস্তাবিত কার্য

আপনি এই নিমজ্জনকারী এটি পরীক্ষা করতে পারেন ।

function deepAssign(options) {
    return function deepAssignWithOptions (target, ...sources) {
        sources.forEach( (source) => {

            if (!isDeepObject(source) || !isDeepObject(target))
                return;

            // Copy source's own properties into target's own properties
            function copyProperty(property) {
                const descriptor = Object.getOwnPropertyDescriptor(source, property);
                //default: omit non-enumerable properties
                if (descriptor.enumerable || options.nonEnum) {
                    // Copy in-depth first
                    if (isDeepObject(source[property]) && isDeepObject(target[property]))
                        descriptor.value = deepAssign(options)(target[property], source[property]);
                    //default: omit descriptors
                    if (options.descriptors)
                        Object.defineProperty(target, property, descriptor); // shallow copy descriptor
                    else
                        target[property] = descriptor.value; // shallow copy value only
                }
            }

            // Copy string-keyed properties
            Object.getOwnPropertyNames(source).forEach(copyProperty);

            //default: omit symbol-keyed properties
            if (options.symbols)
                Object.getOwnPropertySymbols(source).forEach(copyProperty);

            //default: omit prototype's own properties
            if (options.proto)
                // Copy souce prototype's own properties into target prototype's own properties
                deepAssign(Object.assign({},options,{proto:false})) (// Prevent deeper copy of the prototype chain
                    Object.getPrototypeOf(target),
                    Object.getPrototypeOf(source)
                );

        });
        return target;
    }
}

এটি এভাবে ব্যবহার করা যেতে পারে:

const x = { a: { a: 1 } },
      y = { a: { b: 1 } };
deepAssign(options)(x,y); // { a: { a: 1, b: 1 } }

13

আমি লোডাশ ব্যবহার করি:

import _ = require('lodash');
value = _.merge(value1, value2);

2
মনে রাখবেন যে মার্জটি বস্তুটিকে পরিবর্তিত করবে, আপনি যদি এমন কিছু চান যা বস্তুটিকে রূপান্তরিত করে না, তবে _cloneDeep(value1).merge(value2)
গেকোস

3
@geckos আপনি _.সম ({}, মান 1, মান 2) করতে পারেন
স্পেনহোয়েট

10

এখানে টাইপস্ক্রিপ্ট বাস্তবায়ন:

export const mergeObjects = <T extends object = object>(target: T, ...sources: T[]): T  => {
  if (!sources.length) {
    return target;
  }
  const source = sources.shift();
  if (source === undefined) {
    return target;
  }

  if (isMergebleObject(target) && isMergebleObject(source)) {
    Object.keys(source).forEach(function(key: string) {
      if (isMergebleObject(source[key])) {
        if (!target[key]) {
          target[key] = {};
        }
        mergeObjects(target[key], source[key]);
      } else {
        target[key] = source[key];
      }
    });
  }

  return mergeObjects(target, ...sources);
};

const isObject = (item: any): boolean => {
  return item !== null && typeof item === 'object';
};

const isMergebleObject = (item): boolean => {
  return isObject(item) && !Array.isArray(item);
};

এবং ইউনিট পরীক্ষা:

describe('merge', () => {
  it('should merge Objects and all nested Ones', () => {
    const obj1 = { a: { a1: 'A1'}, c: 'C', d: {} };
    const obj2 = { a: { a2: 'A2'}, b: { b1: 'B1'}, d: null };
    const obj3 = { a: { a1: 'A1', a2: 'A2'}, b: { b1: 'B1'}, c: 'C', d: null};
    expect(mergeObjects({}, obj1, obj2)).toEqual(obj3);
  });
  it('should behave like Object.assign on the top level', () => {
    const obj1 = { a: { a1: 'A1'}, c: 'C'};
    const obj2 = { a: undefined, b: { b1: 'B1'}};
    expect(mergeObjects({}, obj1, obj2)).toEqual(Object.assign({}, obj1, obj2));
  });
  it('should not merge array values, just override', () => {
    const obj1 = {a: ['A', 'B']};
    const obj2 = {a: ['C'], b: ['D']};
    expect(mergeObjects({}, obj1, obj2)).toEqual({a: ['C'], b: ['D']});
  });
  it('typed merge', () => {
    expect(mergeObjects<TestPosition>(new TestPosition(0, 0), new TestPosition(1, 1)))
      .toEqual(new TestPosition(1, 1));
  });
});

class TestPosition {
  constructor(public x: number = 0, public y: number = 0) {/*empty*/}
}

9

এখানে আরও একটি ES6 সমাধান, বস্তু এবং অ্যারে নিয়ে কাজ করে।

function deepMerge(...sources) {
  let acc = {}
  for (const source of sources) {
    if (source instanceof Array) {
      if (!(acc instanceof Array)) {
        acc = []
      }
      acc = [...acc, ...source]
    } else if (source instanceof Object) {
      for (let [key, value] of Object.entries(source)) {
        if (value instanceof Object && key in acc) {
          value = deepMerge(acc[key], value)
        }
        acc = { ...acc, [key]: value }
      }
    }
  }
  return acc
}

3
এটি কি পরীক্ষিত এবং / বা কোনও লাইব্রেরির অংশ, দেখতে দুর্দান্ত দেখাচ্ছে তবে এটি কিছুটা প্রমাণিত হয়েছে তা নিশ্চিত করতে পছন্দ করবেন।

9

এই সমস্যা সমাধানের জন্য ডিপমার্জে এনএমপি প্যাকেজটি সর্বাধিক ব্যবহৃত লাইব্রেরি হিসাবে উপস্থিত বলে মনে হচ্ছে: https://www.npmjs.com/package/ ডিগ্রিমেজ


8

আমি একটি খুব সহজ ES5 বিকল্প উপস্থাপন করতে চাই। ফাংশনটি 2 প্যারামিটার পায় - targetএবং sourceএটি অবশ্যই "অবজেক্ট" টাইপ হওয়া উচিত। Targetফলাফল অবজেক্ট হবে। Targetএটির সমস্ত মূল বৈশিষ্ট্য রাখে তবে তাদের মানগুলি পরিবর্তিত হতে পারে।

function deepMerge(target, source) {
if(typeof target !== 'object' || typeof source !== 'object') return false; // target or source or both ain't objects, merging doesn't make sense
for(var prop in source) {
  if(!source.hasOwnProperty(prop)) continue; // take into consideration only object's own properties.
  if(prop in target) { // handling merging of two properties with equal names
    if(typeof target[prop] !== 'object') {
      target[prop] = source[prop];
    } else {
      if(typeof source[prop] !== 'object') {
        target[prop] = source[prop];
      } else {
        if(target[prop].concat && source[prop].concat) { // two arrays get concatenated
          target[prop] = target[prop].concat(source[prop]);
        } else { // two objects get merged recursively
          target[prop] = deepMerge(target[prop], source[prop]); 
        } 
      }  
    }
  } else { // new properties get added to target
    target[prop] = source[prop]; 
  }
}
return target;
}

মামলা:

  • যদি সম্পত্তি targetনা থাকে তবে তা পায়;sourcetarget
  • যদি targetএকটি আছে sourceসম্পত্তি এবং target& sourceউভয় বস্তু (4 খুঁজে 3 ক্ষেত্রে) হয় না, targetএর সম্পত্তি ওভাররাইড পরার;
  • যদি targetকোনও sourceসম্পত্তি থাকে এবং উভয়ই বস্তু / অ্যারে (1 টি বাকী কেস) হয়, তবে পুনরাবৃত্তি দুটি বস্তু (বা দুটি অ্যারের সংমিশ্রণ) মার্জ করে;

নিম্নলিখিতগুলিও বিবেচনা করুন :

  1. অ্যারে + আপজেক্ট = অ্যারে
  2. আপত্তি + অ্যারে = আপত্তি
  3. আপত্তি + আপত্তি = আপত্তি (পুনরাবৃত্তভাবে মার্জড)
  4. অ্যারে + অ্যারে = অ্যারে (কনক্যাট)

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

একটি উদাহরণ দেখুন (এবং আপনি চান এটির সাথে খেলা) :

var a = {
   "a_prop": 1,
   "arr_prop": [4, 5, 6],
   "obj": {
     "a_prop": {
       "t_prop": 'test'
     },
     "b_prop": 2
   }
};

var b = {
   "a_prop": 5,
   "arr_prop": [7, 8, 9],
   "b_prop": 15,
   "obj": {
     "a_prop": {
       "u_prop": false
     },
     "b_prop": {
        "s_prop": null
     }
   }
};

function deepMerge(target, source) {
    if(typeof target !== 'object' || typeof source !== 'object') return false;
    for(var prop in source) {
    if(!source.hasOwnProperty(prop)) continue;
      if(prop in target) {
        if(typeof target[prop] !== 'object') {
          target[prop] = source[prop];
        } else {
          if(typeof source[prop] !== 'object') {
            target[prop] = source[prop];
          } else {
            if(target[prop].concat && source[prop].concat) {
              target[prop] = target[prop].concat(source[prop]);
            } else {
              target[prop] = deepMerge(target[prop], source[prop]); 
            } 
          }  
        }
      } else {
        target[prop] = source[prop]; 
      }
    }
  return target;
}

console.log(deepMerge(a, b));

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



7

এই কাজ করতে একটি উপায় আছে কি?

যদি এনপিএম লাইব্রেরিগুলি সমাধান হিসাবে ব্যবহার করা যায় তবে আপনার কাছ থেকে অবজেক্ট-মার্জ-অ্যাডভান্সড সত্যিকার অর্থে অবজেক্টগুলিকে গভীরভাবে মার্জ করতে এবং পরিচিত কলব্যাক ফাংশনটি ব্যবহার করে প্রতিটি একক মার্জ ক্রিয়াকে কাস্টমাইজ / ওভাররাইড করতে দেয়। এর মূল ধারণাটি কেবল গভীর মার্জিংয়ের চেয়ে বেশি - যখন দুটি কী একই হয় তখন মানটির সাথে কী ঘটে ? এই গ্রন্থাগারটি এর যত্ন নেয় - যখন দুটি কী সংঘর্ষ হয়, object-merge-advancedপ্রকারগুলি ওজন করে, মার্জ করার পরে যতটা সম্ভব ডেটা বজায় রাখার লক্ষ্য করে:

যতটা সম্ভব ডেটা বজায় রাখতে অবজেক্ট কী একত্রে কী মানের ধরণের ওজনগুলি

প্রথম ইনপুট আর্গুমেন্টের কীটি চিহ্নিত করা হয়েছে # 1, দ্বিতীয় যুক্তির - # 2। প্রতিটি ধরণের উপর নির্ভর করে ফলাফল কী এর মানের জন্য একটি বেছে নেওয়া হয়। ডায়াগ্রামে "একটি বস্তু" অর্থ একটি সরল বস্তু (অ্যারে ইত্যাদি নয়)।

কীগুলি সংঘর্ষ না হলে তারা সকলেই ফলাফলটি প্রবেশ করে।

আপনার উদাহরণ স্নিপেট থেকে, আপনি যদি object-merge-advancedনিজের কোড স্নিপেট একীভূত করতে ব্যবহার করেন:

const mergeObj = require("object-merge-advanced");
const x = { a: { a: 1 } };
const y = { a: { b: 1 } };
const res = console.log(mergeObj(x, y));
// => res = {
//      a: {
//        a: 1,
//        b: 1
//      }
//    }

এটি অ্যালগরিদম পুনরাবৃত্তভাবে সমস্ত ইনপুট অবজেক্ট কীগুলিকে অনুসরণ করে, তুলনা করে এবং বিল্ড করে এবং নতুন সংযুক্ত ফলাফলটি প্রদান করে।


6

নিম্নলিখিত ফাংশনটি অবজেক্টগুলির একটি গভীর অনুলিপি তৈরি করে, এটি আদিম, অ্যারে পাশাপাশি অবজেক্টের অনুলিপি করে covers

 function mergeDeep (target, source)  {
    if (typeof target == "object" && typeof source == "object") {
        for (const key in source) {
            if (source[key] === null && (target[key] === undefined || target[key] === null)) {
                target[key] = null;
            } else if (source[key] instanceof Array) {
                if (!target[key]) target[key] = [];
                //concatenate arrays
                target[key] = target[key].concat(source[key]);
            } else if (typeof source[key] == "object") {
                if (!target[key]) target[key] = {};
                this.mergeDeep(target[key], source[key]);
            } else {
                target[key] = source[key];
            }
        }
    }
    return target;
}

6

ES5 (একটি বিদ্যমান বিদ্যমান ওভাররাইট) সহ একটি সহজ সমাধান:

function merge(current, update) {
  Object.keys(update).forEach(function(key) {
    // if update[key] exist, and it's not a string or array,
    // we go in one level deeper
    if (current.hasOwnProperty(key) 
        && typeof current[key] === 'object'
        && !(current[key] instanceof Array)) {
      merge(current[key], update[key]);

    // if update[key] doesn't exist in current, or it's a string
    // or array, then assign/overwrite current[key] to update[key]
    } else {
      current[key] = update[key];
    }
  });
  return current;
}

var x = { a: { a: 1 } }
var y = { a: { b: 1 } }

console.log(merge(x, y));


আমার যা প্রয়োজন কেবল - এস 6 এটি নির্মাণে সমস্যা সৃষ্টি করছিল - এই এস 5 বিকল্পটি বোমাটি রয়েছে
danday74

5

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

const isObject = (item: any) => typeof item === 'object' && !Array.isArray(item);

export const merge = <A = Object, B = Object>(target: A, source: B): A & B => {
  const isDeep = (prop: string) =>
    isObject(source[prop]) && target.hasOwnProperty(prop) && isObject(target[prop]);
  const replaced = Object.getOwnPropertyNames(source)
    .map(prop => ({ [prop]: isDeep(prop) ? merge(target[prop], source[prop]) : source[prop] }))
    .reduce((a, b) => ({ ...a, ...b }), {});

  return {
    ...(target as Object),
    ...(replaced as Object)
  } as A & B;
};

ঠিক একই ক্ষেত্রে, সরল জেএসে একই জিনিস:

const isObject = item => typeof item === 'object' && !Array.isArray(item);

const merge = (target, source) => {
  const isDeep = prop => 
    isObject(source[prop]) && target.hasOwnProperty(prop) && isObject(target[prop]);
  const replaced = Object.getOwnPropertyNames(source)
    .map(prop => ({ [prop]: isDeep(prop) ? merge(target[prop], source[prop]) : source[prop] }))
    .reduce((a, b) => ({ ...a, ...b }), {});

  return {
    ...target,
    ...replaced
  };
};

আপনি কীভাবে এটি ব্যবহার করতে পারেন তা দেখানোর জন্য আমার পরীক্ষার কেসগুলি এখানে

describe('merge', () => {
  context('shallow merges', () => {
    it('merges objects', () => {
      const a = { a: 'discard' };
      const b = { a: 'test' };
      expect(merge(a, b)).to.deep.equal({ a: 'test' });
    });
    it('extends objects', () => {
      const a = { a: 'test' };
      const b = { b: 'test' };
      expect(merge(a, b)).to.deep.equal({ a: 'test', b: 'test' });
    });
    it('extends a property with an object', () => {
      const a = { a: 'test' };
      const b = { b: { c: 'test' } };
      expect(merge(a, b)).to.deep.equal({ a: 'test', b: { c: 'test' } });
    });
    it('replaces a property with an object', () => {
      const a = { b: 'whatever', a: 'test' };
      const b = { b: { c: 'test' } };
      expect(merge(a, b)).to.deep.equal({ a: 'test', b: { c: 'test' } });
    });
  });

  context('deep merges', () => {
    it('merges objects', () => {
      const a = { test: { a: 'discard', b: 'test' }  };
      const b = { test: { a: 'test' } } ;
      expect(merge(a, b)).to.deep.equal({ test: { a: 'test', b: 'test' } });
    });
    it('extends objects', () => {
      const a = { test: { a: 'test' } };
      const b = { test: { b: 'test' } };
      expect(merge(a, b)).to.deep.equal({ test: { a: 'test', b: 'test' } });
    });
    it('extends a property with an object', () => {
      const a = { test: { a: 'test' } };
      const b = { test: { b: { c: 'test' } } };
      expect(merge(a, b)).to.deep.equal({ test: { a: 'test', b: { c: 'test' } } });
    });
    it('replaces a property with an object', () => {
      const a = { test: { b: 'whatever', a: 'test' } };
      const b = { test: { b: { c: 'test' } } };
      expect(merge(a, b)).to.deep.equal({ test: { a: 'test', b: { c: 'test' } } });
    });
  });
});

আপনি যদি মনে করেন যে আমি কিছু কার্যকারিতা মিস করছি তবে দয়া করে আমাকে জানান।


5

লোড্যাশের মতো বিশাল লাইব্রেরির প্রয়োজন ছাড়াই যদি আপনি একটি লাইনার রাখতে চান তবে আমি আপনাকে গভীর ডুবো ব্যবহারের পরামর্শ দিই । ( npm install deepmerge)

তারপরে, আপনি করতে পারেন

deepmerge({ a: 1, b: 2, c: 3 }, { a: 2, d: 3 });

পেতে

{ a: 2, b: 2, c: 3, d: 3 }

সুন্দর জিনিসটি এই মুহুর্তে টাইপস্ক্রিপ্টের টাইপিংয়ের সাথে আসে। এটি অ্যারেগুলিকে মার্জ করার অনুমতি দেয় । এটি একটি আসল অলরাউন্ডার সমাধান।


4

গভীর মার্জ করার জন্য আমরা ex .extend (সত্য, অবজেক্ট 1, অবজেক্ট 2) ব্যবহার করতে পারি। মানটির সত্য চিহ্ন চিহ্নিত করে দুটি বস্তুকে পুনরাবৃত্তভাবে মার্জ করে, প্রথমটিকে সংশোধন করে।

$ প্রসারিত (সত্য, লক্ষ্য, বস্তু)


9
প্রশ্নকর্তা কখনই নির্দেশ করেননি যে তারা jquery ব্যবহার করছে এবং প্রদর্শিত জাভাস্ক্রিপ্ট সমাধানের জন্য জিজ্ঞাসা করছে।
তেহ জো ই

এটি এটি করার একটি খুব সহজ উপায় এবং এটি কাজ করে। একটি কার্যক্ষম সমাধান যা আমি যদি এই প্রশ্নটি জিজ্ঞাসা করি তবে আমি বিবেচনা করব। :)
কাশীরাজা

এটি খুব ভাল উত্তর তবে উত্স কোডের jQuery এর একটি লিঙ্ক মিস করছে। jQuery এর প্রকল্পে প্রচুর লোক কাজ করছে এবং তারা সঠিকভাবে অনুলিপি করে কাজ করতে কিছু সময় ব্যয় করেছে। এছাড়াও, উত্স কোডটি মোটামুটি "সরল": github.com/jquery/jquery/blob/master/src/core.js#L125 "সরল" উদ্ধৃতিতে রয়েছে কারণ এটি খননের সময় জটিল হতে শুরু করে jQuery.isPlainObject()। এটি কোনও কিছু সরল বস্তু কিনা তা নির্ধারণের জটিলতা প্রকাশ করে, যা এখানে বেশিরভাগ উত্তর একটি দীর্ঘ শট দ্বারা মিস করে। অনুমান করুন কোন ভাষাতে jQuery লেখা আছে?
কিউবিকসফট

4

এখানে সোজা এগিয়ে দেওয়া, সহজ সমাধান যা Object.assignঠিক ডিপ করার মতো কাজ করে এবং কোনও অ্যারেটির জন্য কোনও পরিবর্তন ছাড়াই কাজ করে

function deepAssign(target, ...sources) {
    for( source of sources){
        for(let k in source){
            let vs = source[k], vt = target[k];
            if(Object(vs)== vs && Object(vt)===vt ){
                target[k] = deepAssign(vt, vs)
                continue;
            }
            target[k] = source[k];
        }    
    }
    return target;
}

উদাহরণ

x = { a: { a: 1 }, b:[1,2] };
y = { a: { b: 1 }, b:[3] };
z = {c:3,b:[,,,4]}
x = deepAssign(x,y,z)
// x will be
x ==  {
  "a": {
    "a": 1,
    "b": 1
  },
  "b": [    1,    2,    null,    4  ],
  "c": 3
}


3

ক্যাশেড রেডেক্স রাজ্যটি লোড করার সময় আমার এই সমস্যাটি ছিল। যদি আমি কেবল ক্যাশেড স্টেটটি লোড করি তবে আমি আপডেট হওয়া রাষ্ট্রের কাঠামো সহ নতুন অ্যাপ্লিকেশন সংস্করণটির জন্য ত্রুটিগুলিতে চলে যাব।

এটি ইতিমধ্যে উল্লেখ করা হয়েছিল, যে লোডাশ mergeফাংশনটি সরবরাহ করে, যা আমি ব্যবহার করেছি:

const currentInitialState = configureState().getState();
const mergedState = _.merge({}, currentInitialState, cachedState);
const store = configureState(mergedState);

3

অনেক উত্তরে দশ নম্বর কোডের লাইন ব্যবহার করা হয়, বা প্রকল্পে একটি নতুন লাইব্রেরি যুক্ত করা প্রয়োজন, তবে আপনি যদি পুনরাবৃত্তি ব্যবহার করেন তবে এটি কোডের মাত্র 4 লাইন।

function merge(current, updates) {
  for (key of Object.keys(updates)) {
    if (!current.hasOwnProperty(key) || typeof updates[key] !== 'object') current[key] = updates[key];
    else merge(current[key], updates[key]);
  }
  return current;
}
console.log(merge({ a: { a: 1 } }, { a: { b: 1 } }));

অ্যারে হ্যান্ডলিং: উপরের সংস্করণটি পুরানো অ্যারে মানগুলিকে নতুন করে ওভাররাইট করে। আপনি যদি এটি পুরানো অ্যারে মান রাখতে চান এবং নতুনগুলি যুক্ত করতে চান তবে কেবল স্ট্যাথামেন্টের else if (current[key] instanceof Array && updates[key] instanceof Array) current[key] = current[key].concat(updates[key])উপরে একটি ব্লক যুক্ত করুন elseএবং আপনি প্রস্তুত set


1
আমি এটি পছন্দ করি তবে এটি 'বর্তমান' বা অন্যথায় {foo: অপরিজ্ঞাত} একত্রিত হয় না এর জন্য একটি সাধারণ অপরিজ্ঞাত চেক দরকার। লুপের আগে কেবল একটি if (বর্তমান) যুক্ত করুন।
Andreas Pardeike

পরামর্শের জন্য ধন্যবাদ
ভিনসেন্ট

2

এখানে আর একটি যা আমি স্রেফ লিখেছিলাম যা অ্যারে সমর্থন করে। এটি তাদের সাথে আলোচনা করে।

function isObject(obj) {
    return obj !== null && typeof obj === 'object';
}


function isPlainObject(obj) {
    return isObject(obj) && (
        obj.constructor === Object  // obj = {}
        || obj.constructor === undefined // obj = Object.create(null)
    );
}

function mergeDeep(target, ...sources) {
    if (!sources.length) return target;
    const source = sources.shift();

    if(Array.isArray(target)) {
        if(Array.isArray(source)) {
            target.push(...source);
        } else {
            target.push(source);
        }
    } else if(isPlainObject(target)) {
        if(isPlainObject(source)) {
            for(let key of Object.keys(source)) {
                if(!target[key]) {
                    target[key] = source[key];
                } else {
                    mergeDeep(target[key], source[key]);
                }
            }
        } else {
            throw new Error(`Cannot merge object with non-object`);
        }
    } else {
        target = source;
    }

    return mergeDeep(target, ...sources);
};

2

এই ফাংশনটি ব্যবহার করুন:

merge(target, source, mutable = false) {
        const newObj = typeof target == 'object' ? (mutable ? target : Object.assign({}, target)) : {};
        for (const prop in source) {
            if (target[prop] == null || typeof target[prop] === 'undefined') {
                newObj[prop] = source[prop];
            } else if (Array.isArray(target[prop])) {
                newObj[prop] = source[prop] || target[prop];
            } else if (target[prop] instanceof RegExp) {
                newObj[prop] = source[prop] || target[prop];
            } else {
                newObj[prop] = typeof source[prop] === 'object' ? this.merge(target[prop], source[prop]) : source[prop];
            }
        }
        return newObj;
    }

2

রমদা যা জাভাস্ক্রিপ্ট ফাংশনগুলির একটি দুর্দান্ত লাইব্রেরি রয়েছে ডিপলাইফ্ট এবং মার্জডিপ রাইটে মিলিত হয়েছে। এগুলির যে কোনও একটি এই সমস্যার জন্য বেশ ভাল কাজ করে। দয়া করে এখানে ডকুমেন্টেশনটি একবার দেখুন: https://ramdajs.com/docs/# विसারডিপ লেফট

প্রশ্নে নির্দিষ্ট উদাহরণের জন্য আমরা ব্যবহার করতে পারি:

import { mergeDeepLeft } from 'ramda'
const x = { a: { a: 1 } }
const y = { a: { b: 1 } }
const z = mergeDeepLeft(x, y)) // {"a":{"a":1,"b":1}}

2
// copies all properties from source object to dest object recursively
export function recursivelyMoveProperties(source, dest) {
  for (const prop in source) {
    if (!source.hasOwnProperty(prop)) {
      continue;
    }

    if (source[prop] === null) {
      // property is null
      dest[prop] = source[prop];
      continue;
    }

    if (typeof source[prop] === 'object') {
      // if property is object let's dive into in
      if (Array.isArray(source[prop])) {
        dest[prop] = [];
      } else {
        if (!dest.hasOwnProperty(prop)
        || typeof dest[prop] !== 'object'
        || dest[prop] === null || Array.isArray(dest[prop])
        || !Object.keys(dest[prop]).length) {
          dest[prop] = {};
        }
      }
      recursivelyMoveProperties(source[prop], dest[prop]);
      continue;
    }

    // property is simple type: string, number, e.t.c
    dest[prop] = source[prop];
  }
  return dest;
}

ইউনিট পরীক্ষা:

describe('recursivelyMoveProperties', () => {
    it('should copy properties correctly', () => {
      const source: any = {
        propS1: 'str1',
        propS2: 'str2',
        propN1: 1,
        propN2: 2,
        propA1: [1, 2, 3],
        propA2: [],
        propB1: true,
        propB2: false,
        propU1: null,
        propU2: null,
        propD1: undefined,
        propD2: undefined,
        propO1: {
          subS1: 'sub11',
          subS2: 'sub12',
          subN1: 11,
          subN2: 12,
          subA1: [11, 12, 13],
          subA2: [],
          subB1: false,
          subB2: true,
          subU1: null,
          subU2: null,
          subD1: undefined,
          subD2: undefined,
        },
        propO2: {
          subS1: 'sub21',
          subS2: 'sub22',
          subN1: 21,
          subN2: 22,
          subA1: [21, 22, 23],
          subA2: [],
          subB1: false,
          subB2: true,
          subU1: null,
          subU2: null,
          subD1: undefined,
          subD2: undefined,
        },
      };
      let dest: any = {
        propS2: 'str2',
        propS3: 'str3',
        propN2: -2,
        propN3: 3,
        propA2: [2, 2],
        propA3: [3, 2, 1],
        propB2: true,
        propB3: false,
        propU2: 'not null',
        propU3: null,
        propD2: 'defined',
        propD3: undefined,
        propO2: {
          subS2: 'inv22',
          subS3: 'sub23',
          subN2: -22,
          subN3: 23,
          subA2: [5, 5, 5],
          subA3: [31, 32, 33],
          subB2: false,
          subB3: true,
          subU2: 'not null --- ',
          subU3: null,
          subD2: ' not undefined ----',
          subD3: undefined,
        },
        propO3: {
          subS1: 'sub31',
          subS2: 'sub32',
          subN1: 31,
          subN2: 32,
          subA1: [31, 32, 33],
          subA2: [],
          subB1: false,
          subB2: true,
          subU1: null,
          subU2: null,
          subD1: undefined,
          subD2: undefined,
        },
      };
      dest = recursivelyMoveProperties(source, dest);

      expect(dest).toEqual({
        propS1: 'str1',
        propS2: 'str2',
        propS3: 'str3',
        propN1: 1,
        propN2: 2,
        propN3: 3,
        propA1: [1, 2, 3],
        propA2: [],
        propA3: [3, 2, 1],
        propB1: true,
        propB2: false,
        propB3: false,
        propU1: null,
        propU2: null,
        propU3: null,
        propD1: undefined,
        propD2: undefined,
        propD3: undefined,
        propO1: {
          subS1: 'sub11',
          subS2: 'sub12',
          subN1: 11,
          subN2: 12,
          subA1: [11, 12, 13],
          subA2: [],
          subB1: false,
          subB2: true,
          subU1: null,
          subU2: null,
          subD1: undefined,
          subD2: undefined,
        },
        propO2: {
          subS1: 'sub21',
          subS2: 'sub22',
          subS3: 'sub23',
          subN1: 21,
          subN2: 22,
          subN3: 23,
          subA1: [21, 22, 23],
          subA2: [],
          subA3: [31, 32, 33],
          subB1: false,
          subB2: true,
          subB3: true,
          subU1: null,
          subU2: null,
          subU3: null,
          subD1: undefined,
          subD2: undefined,
          subD3: undefined,
        },
        propO3: {
          subS1: 'sub31',
          subS2: 'sub32',
          subN1: 31,
          subN2: 32,
          subA1: [31, 32, 33],
          subA2: [],
          subB1: false,
          subB2: true,
          subU1: null,
          subU2: null,
          subD1: undefined,
          subD2: undefined,
        },
      });
    });
  });

2

আমি জাভাস্ক্রিপ্টে গভীর একত্রীকরণের জন্য মাত্র 2 লাইন সমাধান পেয়েছি। এটি আপনার জন্য কীভাবে কাজ করে তা আমাকে জানান।

const obj1 = { a: { b: "c", x: "y" } }
const obj2 = { a: { b: "d", e: "f" } }
temp = Object.assign({}, obj1, obj2)
Object.keys(temp).forEach(key => {
    temp[key] = (typeof temp[key] === 'object') ? Object.assign(temp[key], obj1[key], obj2[key]) : temp[key])
}
console.log(temp)

টেমপ্লেট {a: {b: 'd', e: 'f', x: 'y' print print মুদ্রণ করবে


1
এটি প্রকৃত গভীর মার্জ করে না। এটা দিয়ে ব্যর্থ হবে merge({x:{y:{z:1}}}, {x:{y:{w:2}}})। ইল ওজেজ 2 এ বিদ্যমান মানগুলি আপডেট করতে ব্যর্থ হবে, উদাহরণস্বরূপ merge({x:{y:1}}, {x:{y:2}})
ওরিলিস

1

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

function AjaxConfig(config) {

  // Default values + config

  Object.assign(this, {
    method: 'POST',
    contentType: 'text/plain'
  }, config);

  // Default values in nested objects

  this.headers = Object.assign({}, this.headers, { 
    'X-Requested-With': 'custom'
  });
}

// Define your config

var config = {
  url: 'https://google.com',
  headers: {
    'x-client-data': 'CI22yQEI'
  }
};

// Extend the default values with your own
var fullMergedConfig = new AjaxConfig(config);

// View in DevTools
console.log(fullMergedConfig);

আপনি এটিকে কোনও ফাংশনে রূপান্তর করতে পারেন (কনস্ট্রাক্টর নয়)।


1

এটি একটি সস্তা গভীর সংশ্লেষ যা আমি ভাবতে পারি যতটা কম কোড ব্যবহার করে। প্রতিটি উত্স পূর্ববর্তী সম্পত্তি বিদ্যমান থাকলে তা ওভাররাইট করে।

const { keys } = Object;

const isObject = a => typeof a === "object" && !Array.isArray(a);
const merge = (a, b) =>
  isObject(a) && isObject(b)
    ? deepMerge(a, b)
    : isObject(a) && !isObject(b)
    ? a
    : b;

const coalesceByKey = source => (acc, key) =>
  (acc[key] && source[key]
    ? (acc[key] = merge(acc[key], source[key]))
    : (acc[key] = source[key])) && acc;

/**
 * Merge all sources into the target
 * overwriting primitive values in the the accumulated target as we go (if they already exist)
 * @param {*} target
 * @param  {...any} sources
 */
const deepMerge = (target, ...sources) =>
  sources.reduce(
    (acc, source) => keys(source).reduce(coalesceByKey(source), acc),
    target
  );

console.log(deepMerge({ a: 1 }, { a: 2 }));
console.log(deepMerge({ a: 1 }, { a: { b: 2 } }));
console.log(deepMerge({ a: { b: 2 } }, { a: 1 }));

1

আমি গভীর সংযোজনকারী বস্তুর জন্য নিম্নলিখিত সংক্ষিপ্ত ফাংশনটি ব্যবহার করছি।
এটি আমার জন্য খুব ভালো কাজ করছে।
লেখক এখানে এটি কীভাবে কাজ করে তা পুরোপুরি ব্যাখ্যা করে।

/*!
 * Merge two or more objects together.
 * (c) 2017 Chris Ferdinandi, MIT License, https://gomakethings.com
 * @param   {Boolean}  deep     If true, do a deep (or recursive) merge [optional]
 * @param   {Object}   objects  The objects to merge together
 * @returns {Object}            Merged values of defaults and options
 * 
 * Use the function as follows:
 * let shallowMerge = extend(obj1, obj2);
 * let deepMerge = extend(true, obj1, obj2)
 */

var extend = function () {

    // Variables
    var extended = {};
    var deep = false;
    var i = 0;

    // Check if a deep merge
    if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
        deep = arguments[0];
        i++;
    }

    // Merge the object into the extended object
    var merge = function (obj) {
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                // If property is an object, merge properties
                if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
                    extended[prop] = extend(extended[prop], obj[prop]);
                } else {
                    extended[prop] = obj[prop];
                }
            }
        }
    };

    // Loop through each object and conduct a merge
    for (; i < arguments.length; i++) {
        merge(arguments[i]);
    }

    return extended;

};

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

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

হাহ। হয় আমি এটি মিস করেছি বা কোডটি পর্যালোচনা করার সময় পর্যালোচক ইন্টারফেসে উপস্থিত হয়নি। আমি সম্মত এই মান একটি উত্তর। এটি অন্য পর্যালোচকগুলি আমার প্রাথমিক মূল্যায়নকে ছাড়িয়ে যাবে বলে আমি মনে করি আপনি ঠিক আছেন। অনুপ্রেরণা পতাকার জন্য দুঃখিত।
ক্রিস কামরাত্ত

গ্রেট! @ ক্রিসকমারাত্তা, আমাকে কী ঘটেছে তা বুঝতে সাহায্য করার জন্য ধন্যবাদ।
জন শিয়ারিং
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.