जावास्क्रिप्ट ऑब्जेक्ट को जल्दी से कैसे साफ़ करें?


170

एक जावास्क्रिप्ट ऐरे के साथ, मैं इसे एक सिंगल असाइनमेंट के साथ एक खाली स्थिति में रीसेट कर सकता हूं:

array.length = 0;

यह एरे को "प्रकट" खाली और पुन: उपयोग करने के लिए तैयार करता है, और जहां तक ​​मैं समझता हूं कि एक एकल "ऑपरेशन" है - अर्थात, निरंतर समय।

क्या जेएस ऑब्जेक्ट को साफ़ करने का एक समान तरीका है? मुझे पता है कि मैं इसे हटाने वाले अपने खेतों को पुनरावृत्त कर सकता हूं:

for (var prop in obj) { if (obj.hasOwnProperty(prop)) { delete obj[prop]; } }

लेकिन इसमें रैखिक जटिलता है।

मैं भी सिर्फ वस्तु को फेंक सकता हूं और एक नया बना सकता हूं:

obj = {};

लेकिन नई वस्तुओं के "होनहार" निर्माण IE6 पर कचरा संग्रह के साथ समस्याओं की ओर जाता है। ( जैसा यहाँ वर्णित है )


2
"array.length == 0 ... एक एकल 'ऑपरेशन' है - अर्थात, निरंतर समय" - मुझे संदेह है कि।
माइल्स

1
मुझे विश्वास नहीं है कि यह किसी भी सामग्री को हटा देता है - बस चीजों को धक्का की तरह बनाता है () काम करता है, हालांकि सरणी खाली थी। क्या आपके पास विपरीत सच होने का संदर्भ है?
लेविक

2
@derobert: यह थोड़ा अनुमान है। IE6 कचरा संग्रह समस्या अच्छी तरह से प्रलेखित है।
लेविक

मूल पोस्ट में कोड गलत है। आंतरिक लूप होना चाहिए: ओब्ज [प्रोप्र] को हटा दें। मेरी पोस्ट देखें stackoverflow.com/questions/6780315/…
stackoverflowuser2010

6
उस स्निपेट का उपयोग करने वाले किसी भी व्यक्ति के लिएfor (var prop in obj)
bendytree

जवाबों:


54

आपके प्रश्न का संक्षिप्त उत्तर, मुझे लगता है, नहीं है (आप सिर्फ एक नई वस्तु बना सकते हैं)।

  1. इस उदाहरण में, मेरा मानना ​​है कि कचरा संग्रह के लिए सभी तत्वों को 0 पर सेट करना अभी भी बाकी है।

  2. आप इसे Object.prototype में जोड़ सकते हैं यदि यह ऐसा कुछ है जिसका आप अक्सर उपयोग करेंगे। हाँ यह जटिलता में रैखिक है, लेकिन बाद में कचरा संग्रह नहीं करने वाली कोई भी चीज़ होगी।

  3. यह सबसे अच्छा उपाय है। मुझे पता है कि यह आपके प्रश्न से संबंधित नहीं है - लेकिन कब तक हमें IE6 का समर्थन जारी रखने की आवश्यकता है? इसके उपयोग को रोकने के लिए कई अभियान हैं।

ऊपर कुछ भी गलत होने पर मुझे ठीक करने के लिए स्वतंत्र महसूस करें।


4
कुछ कंपनियों को IE6 को नीति के एक मामले के रूप में समर्थन करना होगा - और यह दोहरे अंकों की बाजार हिस्सेदारी का आनंद उठाएगा। IE GC मुद्दा यह नहीं है कि चीजें अनियंत्रित हो जाती हैं, यह है कि संग्रह हर एक्स आवंटन को चलाता है, और हर बार अधिक समय लेता है। इस प्रकार वस्तुओं का पुन: उपयोग करने की आवश्यकता है।
लेविक

हाँ, ऐसे कई मामले हैं जहाँ कंपनी की नीति / आदि के कारण इसका उपयोग अभी भी किया जाता है। मैं विषय से बाहर रैंकिंग के बावजूद था :) तो obj.prop को कैसे हटाता है; प्रदर्शन जब संपत्ति ही एक वस्तु है? मुझे नहीं पता कि तुम वहाँ बहुत दक्षता हासिल करते हो।
jthompson

2
खराब जीसी का मतलब है कि IE6 धीमी गति से चलेगा, जिसका अर्थ है कि उन्नयन के लिए और भी अधिक प्रोत्साहन है। आप अभी भी इसका समर्थन कर रहे हैं, यह सिर्फ इतना है कि यह धीमी गति से चलेगा।
निकफ

1
इसका मतलब है कि आपका ऐप आपके लक्षित दर्शकों के एक हिस्से के लिए खराब प्रदर्शन करता है। कुछ लोगों के पास अपग्रेड करने का विकल्प नहीं है क्योंकि वे एक नियंत्रित आईटी वातावरण में हैं। शायद उनकी कंपनी एक सक्रिय-एक्स नियंत्रण का उपयोग करती है जो केवल IE6 के साथ काम करती है।
लेविक

2
@ एलिविक सिर्फ एक कंपनी के लिए काम नहीं करता है जो आपको IE6 का समर्थन करने के लिए मजबूर करती है। यह वैसे भी एक अच्छी कंपनी नहीं हो सकती है।
low_rents

121

खैर, चीजों को बहुत आसान बनाने के जोखिम पर ...

for (var member in myObject) delete myObject[member];

... कम से कम डरावने कोष्ठक के साथ कोड की एक पंक्ति में ऑब्जेक्ट को साफ करने में बहुत प्रभावी प्रतीत होगा। सभी सदस्यों को कचरा के रूप में बाईं ओर के बजाय वास्तव में हटा दिया जाएगा।

जाहिर है कि यदि आप स्वयं ऑब्जेक्ट को हटाना चाहते हैं, तो आपको इसके लिए एक अलग से डिलीट () करना होगा।


2
विलोपन केवल संदर्भ को तोड़ता है, उदाहरण के लिए यह myObject बनाता है [सदस्य] अपरिभाषित का मूल्यांकन करता है, और तकनीकी रूप से ऑब्जेक्ट को कचरा के रूप में छोड़ देता है जब तक कि ऑब्जेक्ट का कोई अन्य संदर्भ मौजूद न हो।
जॉय कार्सन

यह जवाब बहुत जिम्मेदार है। यदि एक निपटान के चरण में सभी प्रबंधित वस्तुओं पर लागू किया जाता है, तो यह आमतौर पर आकस्मिक वस्तु श्रृंखलाओं में से कई का ध्यान रखेगा। रॉक ऑन विटज़
डीपेलमेंट

1
ओपी hasOwnPropertyइस लूप में उपयोग करने का सुझाव देता है । मैंने डॉक्स पढ़ा है, लेकिन मैं अभी भी अपने सिर को चारों ओर लपेटने की कोशिश कर रहा हूं, यदि कोई हो, तो क्या जोखिम है अगर हम hasOwnProperty()चेक को छोड़ देते हैं ?
Logidelic

2
मैंने सोचा था कि ऑब्जेक्ट पर पुनरावृत्ति करते समय गुणों को हटाना खतरनाक था - अधिकांश भाषाओं में यह इट्रेटर को अमान्य कर देगा और चीजों को तोड़ देगा, या तो सूक्ष्म रूप से या भयावह रूप से - लेकिन जाहिरा तौर पर यह प्रति एमडीएन जावास्क्रिप्ट में ठीक है: "एक संपत्ति जो पहले हटा दी गई है यह दौरा किया गया है बाद में दौरा नहीं किया जाएगा। ” developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Piotr

46

ES5

ES5 समाधान हो सकता है:

// for enumerable and non-enumerable properties
Object.getOwnPropertyNames(obj).forEach(function (prop) {
  delete obj[prop];
});

ES6

और ES6 समाधान हो सकता है:

// for enumerable and non-enumerable properties
for (const prop of Object.getOwnPropertyNames(obj)) {
  delete obj[prop];
}

प्रदर्शन

चश्मे के बावजूद, सबसे तेज समाधान आम तौर पर होगा:

// for enumerable and non-enumerable of an object with proto chain
var props = Object.getOwnPropertyNames(obj);
for (var i = 0; i < props.length; i++) {
  delete obj[props[i]];
}

// for enumerable properties of shallow/plain object
for (var key in obj) {
  // this check can be safely omitted in modern JS engines
  // if (obj.hasOwnProperty(key))
    delete obj[key];
}

for..inकेवल उथले या सादे वस्तु पर प्रदर्शन क्यों किया जाना चाहिए इसका कारण यह है कि यह उन गुणों का पता लगाता है जो केवल विरासत में मिला है, न कि केवल स्वयं के गुण जो हटाए जा सकते हैं। मामले में यह सुनिश्चित करें कि के लिए नहीं जाना जाता है कि एक वस्तु मैदान है और गुण, गणनीय हैं forके साथ Object.getOwnPropertyNamesएक बेहतर विकल्प है।


7

आप यह कोशिश कर सकते हैं। नीचे दिया गया कार्य वस्तु के गुणों के सभी मूल्यों को अपरिभाषित करता है। नेस्टेड ऑब्जेक्ट्स के साथ भी काम करता है।

var clearObjectValues = (objToClear) => {
    Object.keys(objToClear).forEach((param) => {
        if ( (objToClear[param]).toString() === "[object Object]" ) {
            clearObjectValues(objToClear[param]);
        } else {
            objToClear[param] = undefined;
        }
    })
    return objToClear;
};

ध्यान दें कि फ़ील्ड केवल अपरिभाषित के रूप में सेट की जा रही हैं, इससे समय के साथ मेमोरी लीक हो जाएगी क्योंकि कचरा कलेक्टर द्वारा फ़ील्ड को साफ़ नहीं किया जाएगा।
एलेक्सिस टायलर

7

तो अपने प्रश्न को पुनरावृत्ति करने के लिए: आप जितना संभव हो उतना बचना चाहते हैं, IE6 जीसी बग के साथ परेशानी। उस बग के दो कारण हैं:

  1. कचरा संग्रहण हर एक बार कई आवंटन के बाद होता है ; इसलिए, आपके द्वारा किए गए अधिक आवंटन, thetener GC चलेंगे;
  2. जितनी अधिक वस्तुएँ आपको 'हवा में' मिली हैं, उतने ही अधिक समय तक प्रत्येक कचरा संग्रह चलता है (क्योंकि यह उन वस्तुओं की पूरी सूची के माध्यम से क्रॉल करेगा जो देखने के लिए कचरा के रूप में चिह्नित हैं)।

1 होने का कारण प्रतीत होता है: आवंटन की संख्या नीचे रखें; यथासंभव नई वस्तुओं और तारों को असाइन करें।

2 के कारण होने वाला समाधान ऐसा प्रतीत होता है: 'जीवित' वस्तुओं की संख्या को नीचे रखें; जैसे ही आप उन्हें जरूरत नहीं है अपने तार और वस्तुओं को हटा दें, और आवश्यक होने पर उन्हें नए सिरे से बनाएं।

एक निश्चित सीमा तक, ये समाधान विरोधाभासी हैं: स्मृति में वस्तुओं की संख्या कम रखने के लिए अधिक आवंटन और डी-आवंटन की आवश्यकता होगी। इसके विपरीत, लगातार एक ही वस्तु का पुन: उपयोग करने का मतलब हो सकता है कि सख्ती से आवश्यक से अधिक वस्तुओं को स्मृति में रखना।


अब आपके प्रश्न के लिए। चाहे आप एक नया निर्माण करके या उसके सभी गुणों को हटाकर एक वस्तु को रीसेट करेंगे: यह इस बात पर निर्भर करेगा कि आप इसके साथ क्या करना चाहते हैं।

आप शायद इसके लिए नए गुण निर्दिष्ट करना चाहेंगे:

  • यदि आप ऐसा तुरंत करते हैं, तो मेरा सुझाव है कि नई संपत्तियों को सीधे असाइन करें, और पहले हटाने या साफ़ करना छोड़ दें। (सुनिश्चित करें कि सभी संपत्तियां या तो ओवरराइट या हटा दी गई हैं, हालांकि!)
  • यदि ऑब्जेक्ट का तुरंत उपयोग नहीं किया जाएगा, लेकिन बाद में किसी चरण में इसे फिर से खोल दिया जाएगा, तो मैं इसे हटाने या इसे अशक्त करने का सुझाव देता हूं, और बाद में एक नया बनाता हूं।

पुन: उपयोग के लिए एक JScript ऑब्जेक्ट को साफ़ करने के तरीके का उपयोग करने के लिए कोई तेज़, आसान नहीं है जैसे कि यह एक नई वस्तु थी - एक नया बनाने के बिना। जिसका अर्थ है कि आपके प्रश्न का संक्षिप्त उत्तर 'नहीं ’है, जैसा कि जेथम्पसन कहते हैं।


4

ES7 में Object.observe की प्रतीक्षा करने और सामान्य रूप से डेटा-बाइंडिंग के साथ सोचने के लिए कुछ नया। विचार करें:

var foo={
   name: "hello"
};

Object.observe(foo, function(){alert('modified');}); // bind to foo

foo={}; // You are no longer bound to foo but to an orphaned version of it
foo.name="there"; // This change will be missed by Object.observe()

तो उस परिस्थिति में # 2 सबसे अच्छा विकल्प हो सकता है।


अगर एंगुलरजेएस जैसे फ्रेमवर्क का उपयोग करते हैं, जो वस्तुओं को विचारों (एक या दो तरह से बाध्यकारी) से बांध सकता है, तो ऑब्जेक्ट को साफ़ करने से ऑब्जेक्ट obj = {}में किसी भी अन्य परिवर्तन से अनजान हो जाएगा, इसलिए आपके टेम्पलेट ठीक से प्रदान नहीं किए जाएंगे। विकल्प # 2 हालांकि, ठीक से काम करेगा।
इवान हुस्नजक

अच्छी बात। मुझे उसी हीप ऑब्जेक्ट को रखने की आवश्यकता है, और यह एक और कारण दर्शाता है जो आप एक ही संदर्भ रखना चाहते हैं।
कोडी

1

आप रंगमंच की सामग्री को हटा सकते हैं, लेकिन चर नहीं हटा सकते। delete abc;ईएस 5 में अमान्य है (और उपयोग के साथ फेंकता है)।

आप इसे जीसी को हटाने के लिए इसे सेट करने के लिए नल कर सकते हैं (यदि आपके पास संपत्तियों के अन्य संदर्भ हैं तो यह नहीं होगा)

lengthएक वस्तु पर संपत्ति सेट करने से कुछ भी नहीं बदलता है। (यह केवल, ठीक है, संपत्ति सेट करता है)


स्पष्ट होने के लिए, lengthकिसी सरणी पर 0 पर सेट करते समय (जो एक विशिष्ट प्रकार की वस्तु है - यदि आप मुझ पर विश्वास नहीं करते हैं, तो दौड़ने का प्रयास करें typeof []), यह न केवल संपत्ति सेट करेगा, यह वास्तव में सरणी की सामग्री को स्पष्ट करेगा। । देखें stackoverflow.com/questions/1232040/…
सेम बीन

ठीक है, आप हटा सकते हैं window.abcक्योंकि यह उस मामले में एक प्रोप है।
शैडरिच

0

इसने मुझे उम्र भर के लिए रोक दिया, इसलिए यहां मेरा संस्करण है क्योंकि मैं एक खाली वस्तु नहीं चाहता था, मैं सभी गुणों के साथ एक चाहता था लेकिन कुछ डिफ़ॉल्ट मान पर रीसेट करता हूं। एक वर्ग की नई तात्कालिकता की तरह।

let object1 = {
  a: 'somestring',
  b: 42,
  c: true,
  d:{
    e:1,
    f:2,
    g:true,
    h:{
      i:"hello"
    }
  },
  j: [1,2,3],
  k: ["foo", "bar"],
  l:["foo",1,true],
  m:[{n:10, o:"food", p:true }, {n:11, o:"foog", p:true }],
  q:null,
  r:undefined
};

let boolDefault = false;
let stringDefault = "";
let numberDefault = 0;

console.log(object1);
//document.write("<pre>");
//document.write(JSON.stringify(object1))
//document.write("<hr />");
cleanObject(object1);
console.log(object1);
//document.write(JSON.stringify(object1));
//document.write("</pre>");

function cleanObject(o) {
  for (let [key, value] of Object.entries(o)) {
    let propType = typeof(o[key]);

    //console.log(key, value, propType);

    switch (propType) {
      case "number" :
        o[key] = numberDefault;
        break;

      case "string":
        o[key] = stringDefault;
        break;

      case "boolean":
        o[key] = boolDefault;    
        break;

      case "undefined":
        o[key] = undefined;   
        break;

      default:
        if(value === null) {
            continue;
        }

        cleanObject(o[key]);
        break;
    }
  }
}

// EXPECTED OUTPUT
// Object { a: "somestring", b: 42, c: true, d: Object { e: 1, f: 2, g: true, h: Object { i: "hello" } }, j: Array [1, 2, 3], k: Array ["foo", "bar"], l: Array ["foo", 1, true], m: Array [Object { n: 10, o: "food", p: true }, Object { n: 11, o: "foog", p: true }], q: null, r: undefined }
// Object { a: "", b: 0, c: undefined, d: Object { e: 0, f: 0, g: undefined, h: Object { i: "" } }, j: Array [0, 0, 0], k: Array ["", ""], l: Array ["", 0, undefined], m: Array [Object { n: 0, o: "", p: undefined }, Object { n: 0, o: "", p: undefined }], q: null, r: undefined }

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