जावास्क्रिप्ट jQuery के विस्तार विधि के बराबर है


92

पृष्ठभूमि

मेरे पास एक फ़ंक्शन है जो configऑब्जेक्ट को तर्क के रूप में लेता है । फ़ंक्शन के भीतर, मेरे पास भी defaultऑब्जेक्ट है। उन वस्तुओं में से प्रत्येक में ऐसे गुण होते हैं जो अनिवार्य रूप से फ़ंक्शन के भीतर बाकी कोड के लिए सेटिंग्स के रूप में काम करते हैं। configऑब्जेक्ट के भीतर सभी सेटिंग्स को निर्दिष्ट करने से रोकने के लिए , मैं extendऑब्जेक्ट में settingsकिसी भी डिफ़ॉल्ट मान के साथ एक नई वस्तु में भरने के लिए jQuery की विधि का उपयोग करता हूं, defaultयदि वे configऑब्जेक्ट में निर्दिष्ट नहीं थे :

var config = {key1: value1};
var default = {key1: default1, key2: default2, key 3: default 3};

var settings = $.extend(default, config);

//resulting properties of settings:
settings = {key1: value1, key2: default2, key 3: default 3};

संकट

यह बहुत अच्छा काम करता है, लेकिन मैं इस कार्यक्षमता को jQuery की आवश्यकता के बिना पुन: पेश करना चाहूंगा। वहाँ एक समान रूप से सुंदर है (या करीब) इसका मतलब सादे राजभाषा जावास्क्रिप्ट के साथ ऐसा करने के लिए?


संपादित करें: गैर-डुप्लिकेट औचित्य

यह प्रश्न " मैं कैसे दो जावास्क्रिप्ट वस्तुओं के गुणों को गतिशील रूप से विलय कर सकता हूं " की नकल नहीं है । जबकि यह प्रश्न बस एक ऐसी वस्तु बनाना चाहता है जिसमें दो अलग-अलग वस्तुओं से सभी कुंजियाँ और मान हों - मैं विशेष रूप से इस घटना में कैसे पता करना चाहता हूँ कि दोनों वस्तुएँ कुछ साझा करती हैं लेकिन सभी कुंजियाँ नहीं हैं और किस वस्तु को पूर्वता मिलेगी ( डिफ़ॉल्ट) घटना में परिणामी वस्तु के लिए कि डुप्लिकेट कुंजियाँ हैं। और इससे भी अधिक विशेष रूप से, मैं इसे प्राप्त करने के लिए jQuery की विधि के उपयोग को संबोधित करना चाहता था और jQuery के बिना ऐसा करने का एक वैकल्पिक तरीका ढूंढता था। जबकि दोनों प्रश्नों के कई उत्तर ओवरलैप करते हैं, इसका मतलब यह नहीं है कि प्रश्न स्वयं ही समान हैं।


8
जिस तरह से jQuery यह james.padolsey.com/jquery/#v=1.6.2&fn=jQuery.extend :-P
रॉकेट

अच्छा विचार @RocketHazmat, ध्यान दें कि अगर आप उस फ़ंक्शन को कॉपी करते हैं, जिसमें कुछ अन्य jQuery निर्भरताएँ हैं जैसे jQuery.isPlainObjectऔरjQuery.isFunction
एंडी रेडडजैट

जवाबों:


131

अपने कोड में परिणाम प्राप्त करने के लिए, आप करेंगे:

function extend(a, b){
    for(var key in b)
        if(b.hasOwnProperty(key))
            a[key] = b[key];
    return a;
}

ध्यान रखें कि आपने जिस तरह से विस्तार किया है, वह डिफ़ॉल्ट ऑब्जेक्ट को संशोधित करेगा। यदि आप ऐसा नहीं चाहते हैं, तो उपयोग करें

$.extend({}, default, config)

एक और अधिक मजबूत समाधान जो jQuery की कार्यक्षमता की नकल करता है वह इस प्रकार है:

function extend(){
    for(var i=1; i<arguments.length; i++)
        for(var key in arguments[i])
            if(arguments[i].hasOwnProperty(key))
                arguments[0][key] = arguments[i][key];
    return arguments[0];
}

1
मैं एक्शन में एक कोड उदाहरण देखना चाहूंगा, शायद फिडल, क्योंकि प्लेन js बहुत अधिक कूलर है, लेकिन इतना सार, एक मिलियन धन्यवाद।
thnnp

3
यह पुनर्खरीद नहीं करता, जैसे $ .extend करता है
ekkis

30

आप Object.assign का उपयोग कर सकते हैं।

var defaults = {key1: "default1", key2: "default2", key3: "defaults3"};
var config = {key1: "value1"};

var settings = Object.assign({}, defaults, config); // values in config override values in defaults
console.log(settings); // Object {key1: "value1", key2: "default2", key3: "defaults3"}

यह एक या एक से अधिक स्रोत वस्तुओं से लक्ष्य सामग्री के सभी गणना योग्य गुणों के मूल्यों को कॉपी करता है और लक्ष्य वस्तु को वापस करता है।

Object.assign(target, ...sources)

यह IE (लेकिन एज सहित) को छोड़कर सभी डेस्कटॉप ब्राउज़रों में काम करता है। इसने मोबाइल सपोर्ट को कम कर दिया है।

यहां अपने लिए देखें: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

गहरी नकल के बारे में

हालाँकि, Object.assign के पास गहरा विकल्प नहीं है जो jQuery की विस्तार विधि है।

नोट: आप आम तौर पर JSON का उपयोग एक समान प्रभाव के लिए कर सकते हैं, हालांकि

var config = {key1: "value1"};
    var defaults = {key1: "default1", key2: "default2", keyDeep: {
        kd1: "default3",
        kd2: "default4"
    }};
    var settings = JSON.parse(JSON.stringify(Object.assign({}, defaults, config))); 
    console.log(settings.keyDeep); // Object {kd1: "default3", kd2: "default4"}

हाँ, लेकिन यहाँ यह चूक से key1 पर कूदता है और इसे नई वस्तु में नहीं जोड़ता है।
आयनॉट नेचुला

@ अनाम वास्तव में यह इसे जोड़ता है, लेकिन यह कॉन्फ़िगरेशन सरणी से की 1 मान द्वारा ओवरराइड किया गया है।
07

मुझे लगा कि हो रहा है। इसलिए, इसे बाद में नहीं जोड़ा जा रहा है।
आयनॉट नेचुला

28

आप ईसीएमए 2018 प्रसार ऑपरेटर का उपयोग वस्तु शाब्दिक रूप में कर सकते हैं ...

var config = {key1: value1};
var default = {key1: default1, key2: default2, key 3: default 3};

var settings = {...default, ...config}

//resulting properties of settings:
settings = {key1: value1, key2: default2, key 3: default 3};

BabelJS पुराने ब्राउज़रों के लिए समर्थन करता है


1
यह करने का सबसे साफ और साफ तरीका!
वेलोजेट

4

यह गहरी प्रतिलिपि के साथ मेरा थोड़ा अलग दृष्टिकोण है जो मैं एक jQuery निर्भरता को खत्म करने की कोशिश करते हुए आया था। यह ज्यादातर छोटे होने के लिए डिज़ाइन किया गया है, इसलिए हो सकता है कि इसमें सभी फीचर एक होने की उम्मीद न हो। पूरी तरह से ES5- संगत होना चाहिए ( ऑब्जेक्ट के उपयोग के कारण IE9 से शुरू )

function extend(obj1, obj2) {
    var keys = Object.keys(obj2);
    for (var i = 0; i < keys.length; i += 1) {
      var val = obj2[keys[i]];
      obj1[keys[i]] = ['string', 'number', 'array', 'boolean'].indexOf(typeof val) === -1 ? extend(obj1[keys[i]] || {}, val) : val;
    }
    return obj1;
  }

आपको आश्चर्य हो सकता है कि पांचवीं पंक्ति वास्तव में क्या करती है ... अगर obj2.key एक ऑब्जेक्ट शाब्दिक है (अर्थात यदि यह कोई सामान्य प्रकार नहीं है) तो हम पुनरावर्ती रूप से कॉल का विस्तार करते हैं। यदि उस नाम वाली संपत्ति obj1 में अभी तक मौजूद नहीं है, तो हम इसे पहले किसी खाली वस्तु से आरंभ करते हैं। अन्यथा हम बस obj1.key को obj2.key पर सेट करते हैं।

यहाँ मेरे कुछ मोचा / चाई परीक्षण हैं जो यहाँ काम करने के लिए सामान्य मामलों को साबित करने चाहिए:

it('should extend a given flat object with another flat object', () => {
  const obj1 = {
    prop1: 'val1',
    prop2: 42,
    prop3: true,
    prop4: 20.16,
  };
  const obj2 = {
    prop4: 77.123,
    propNew1: 'newVal1',
    propNew2: 71,
  };
  assert.deepEqual(utils.extend(obj1, obj2), {
    prop1: 'val1',
    prop2: 42,
    prop3: true,
    prop4: 77.123,
    propNew1: 'newVal1',
    propNew2: 71,
  });
});

it('should deep-extend a given flat object with a nested object', () => {
  const obj1 = {
    prop1: 'val1',
    prop2: 'val2',
  };
  const obj2 = {
    propNew1: 'newVal1',
    propNew2: {
      propNewDeep1: 'newDeepVal1',
      propNewDeep2: 42,
      propNewDeep3: true,
      propNewDeep4: 20.16,
    },
  };
  assert.deepEqual(utils.extend(obj1, obj2), {
    prop1: 'val1',
    prop2: 'val2',
    propNew1: 'newVal1',
    propNew2: {
      propNewDeep1: 'newDeepVal1',
      propNewDeep2: 42,
      propNewDeep3: true,
      propNewDeep4: 20.16,
    },
  });
});

it('should deep-extend a given nested object with another nested object and deep-overwrite members', () => {
  const obj1 = {
    prop1: 'val1',
    prop2: {
      propDeep1: 'deepVal1',
      propDeep2: 42,
      propDeep3: true,
      propDeep4: {
        propDeeper1: 'deeperVal1',
        propDeeper2: 777,
        propDeeper3: 'I will survive',
      },
    },
    prop3: 'lone survivor',
  };
  const obj2 = {
    prop1: 'newVal1',
    prop2: {
      propDeep1: 'newDeepVal1',
      propDeep2: 84,
      propDeep3: false,
      propDeep4: {
        propDeeper1: 'newDeeperVal1',
        propDeeper2: 888,
      },
    },
  };
  assert.deepEqual(utils.extend(obj1, obj2), {
    prop1: 'newVal1',
    prop2: {
      propDeep1: 'newDeepVal1',
      propDeep2: 84,
      propDeep3: false,
      propDeep4: {
        propDeeper1: 'newDeeperVal1',
        propDeeper2: 888,
        propDeeper3: 'I will survive',
      },
    },
    prop3: 'lone survivor',
  });
});

मुझे इस कार्यान्वयन पर प्रतिक्रिया या टिप्पणियों के बारे में खुशी होगी। अग्रिम में धन्यवाद!


2

आप forस्टेटमेंट का उपयोग करके ऑब्जेक्ट के गुणों के माध्यम से लूप कर सकते हैं ।

var settings = extend(default, config);

function extend(a, b){
    var c = {};
    for(var p in a)
        c[p] = (b[p] == null) ? a[p] : b[p];
    return c;
}

2
यह उन संपत्तियों को ध्यान में नहीं रखेगा जो मौजूद नहीं हैं a। हालांकि यह उदाहरण में नहीं है, $.extendवास्तव में उस तरह से काम करता है, जो सभी वस्तुओं के सभी गुणों को मिलाता है।
फेलिक्स क्लिंग

1
जैसा कि मैंने jquery आधार कोड पढ़ा है, यह वास्तव में मूल्य को कॉपी या क्लोन करने के लिए एक पुनरावर्ती कार्य करता है। तो यह गहराई से क्लोन / कॉपी करना है, न कि उपरोक्त कोड के रूप में पहले स्तर पर कॉपी करना।
अलादिन

2

मैं इस कोड को पसंद करता हूं जो मेरे जेनेरिक forEachIn का उपयोग करता है, और पहली वस्तु को मैनगल नहीं करता है:

function forEachIn(obj, fn) {
    var index = 0;
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            fn(obj[key], key, index++);
        }
    }
}

function extend() {
    var result = {};
    for (var i = 0; i < arguments.length; i++) {
        forEachIn(arguments[i],
            function(obj, key) {
                result[key] = obj;
            });
    }
    return result;
}

यदि आप वास्तव में पहली वस्तु में सामान का विलय करना चाहते हैं, तो आप कर सकते हैं:

obj1 = extend(obj1, obj2);

यह अब तक का सबसे अच्छा जवाब है। यह गहरी कॉपी करता है, पहली वस्तु को मेनगेट नहीं करता है, अनंत वस्तुओं का समर्थन करता है, और विस्तार करते समय प्रकार बदल सकता है (यानी यहां कई उत्तर किसी ऑब्जेक्ट को स्ट्रिंग का विस्तार नहीं करेंगे, यह उत्तर होगा)। इससे मेरी पुस्तक में हर चेक मार्क मिलता है। पूर्ण विस्तार प्रतिस्थापन, और समझने में बेहद आसान है।
निक स्टीले

0

शुद्ध जावास्क्रिप्ट के साथ विकसित होने पर यह मुझे बहुत मदद करता है।

function extends(defaults, selfConfig){
     selfConfig = JSON.parse(JSON.stringify(defaults));
     for (var item in config) {
         if (config.hasOwnProperty(item)) {
             selfConfig[item] = config[item];
         }
     }
     return selfConfig;
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.