2010-06-17 7 views
9

प्रश्न: क्लोजर के लिए कई फायदे हैं, लेकिन नकारात्मक क्या हैं (मेमोरी रिसाव? Obfuscation समस्याएं? बैंडविड्थ increasage?)? इसके अतिरिक्त, क्लोजर्स की मेरी समझ सही है? आखिरकार, एक बार बंद होने के बाद, क्या वे नष्ट हो सकते हैं?जावास्क्रिप्ट क्लोजर - नकारात्मक क्या हैं?

मैं जावास्क्रिप्ट क्लोजर के बारे में थोड़ा पढ़ रहा है। मुझे उम्मीद है कि कोई और अधिक जानकार मेरे दावे को मार्गदर्शन करेगा, मुझे गलत कहां सुधार देगा।

क्लोजर के लाभ:

  1. , एक स्थानीय गुंजाइश के लिए चर समाहित एक आंतरिक कार्यप्रणाली का उपयोग कर। फ़ंक्शन की गुमनाम महत्वहीन है।

    <script type="text/javascript"> 
    
        var global_text = ""; 
        var global_count = 0; 
        var global_num1 = 10; 
        var global_num2 = 20; 
        var global_num3 = 30; 
    
        function outerFunc() { 
    
         var local_count = local_count || 0; 
    
         alert("global_num1: " + global_num1); // global_num1: undefined 
         var global_num1 = global_num1 || 0; 
         alert("global_num1: " + global_num1); // global_num1: 0 
    
         alert("global_num2: " + global_num2); // global_num2: 20 
         global_num2 = global_num2 || 0;   // (notice) no definition with 'var' 
         alert("global_num2: " + global_num2); // global_num2: 20 
         global_num2 = 0; 
    
         alert("local_count: " + local_count); // local_count: 0 
    
         function output() { 
         global_num3++; 
    
         alert("local_count: " + local_count + "\n" + 
           "global_count: " + global_count + "\n" + 
           "global_text: " + global_text 
          ); 
    
         local_count++; 
         } 
    
         local_count++; 
         global_count++; 
    
         return output; 
        } 
    
        var myFunc = outerFunc(); 
    
        myFunc(); 
         /* Outputs: 
         ********************** 
         * local_count: 1 
         * global_count: 1 
         * global_text: 
         **********************/ 
    
        global_text = "global"; 
        myFunc(); 
         /* Outputs: 
         ********************** 
         * local_count: 2 
         * global_count: 1 
         * global_text: global 
         **********************/ 
    
        var local_count = 100; 
        myFunc(); 
         /* Outputs: 
         ********************** 
         * local_count: 3 
         * global_count: 1 
         * global_text: global 
         **********************/ 
    
    
        alert("global_num1: " + global_num1);  // global_num1: 10 
        alert("global_num2: " + global_num2);  // global_num2: 0 
        alert("global_num3: " + global_num3);  // global_num3: 33 
    
    </script> 
    

    दिलचस्प बातें मैं इसके बारे में बाहर ले:

क्या मैं उपयोगी पाया है स्थानीय/वैश्विक विस्तार के बारे में कुछ बुनियादी परीक्षण करना है

  1. outerFunc में अलर्ट केवल एक बार बुलाए जाते हैं, जो तब होता है जब बाहरी फ़नक कॉल myFunc (myFunc = outerFunc()) को असाइन किया जाता है। यह असाइनमेंट बाहरी फनक को खोलने लगता है, जिसमें मैं एक सतत स्थिति को कॉल करना चाहता हूं।

  2. हर myFunc, कहा जाता है वापसी निष्पादित किया जाता है। इस मामले में, वापसी आंतरिक कार्य है।

  3. वास्तव में कुछ दिलचस्प स्थानीयकरण जब स्थानीय चर को परिभाषित होता है। सूचना global_num1 और global_num2 के बीच पहली चेतावनी में अंतर, पहले भी चर बनाया जा करने की कोशिश कर रहा है, global_num1 अपरिभाषित माना जाता है क्योंकि 'var' कि कार्य करने के लिए एक स्थानीय चर सूचित करने के लिए इस्तेमाल किया गया था। - जावास्क्रिप्ट इंजन के संचालन के क्रम में यह पहले से बात की गई है, यह काम करने के लिए यह देखना अच्छा लगता है।

  4. वैश्विक अभी भी इस्तेमाल किया जा सकता है, लेकिन स्थानीय चर उन्हें पार कर जाएगी। तीसरे myFunc कॉल से पहले नोटिस, स्थानीय_count नामक एक वैश्विक चर बनाया गया है, लेकिन यह आंतरिक फ़ंक्शन पर कोई प्रभाव नहीं है, जिसमें एक वैरिएबल है जो एक ही नाम से जाता है। इसके विपरीत, प्रत्येक फ़ंक्शन कॉल में वैश्विक चर को संशोधित करने की क्षमता होती है, जैसा वैश्विक_var3 द्वारा देखा गया है।

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

मुझे पता है कि बंद होने के अन्य उदाहरण हैं, जिनमें से कई लूपिंग संरचनाओं के साथ संयोजन में अज्ञात कार्यों का उपयोग करते हैं, लेकिन मुझे लगता है कि यह प्रभाव देखने के लिए 101-स्टार्टर कोर्स के लिए अच्छा है।

एक बात मैं के साथ चिंतित हूँ नकारात्मक प्रभाव बंद स्मृति पर होगा। चूंकि यह फ़ंक्शन वातावरण को खुला रखता है, यह स्मृति में संग्रहीत उन चर को भी रखता है, जो विशेष रूप से डोम ट्रैवर्सल और कचरा संग्रह के संबंध में प्रदर्शन प्रभाव नहीं हो सकता है। मुझे यह भी यकीन नहीं है कि स्मृति रिसाव के मामले में यह किस तरह की भूमिका निभाएगा और मुझे यकीन नहीं है कि अगर बंद को स्मृति से हटाया जा सकता है तो "मेरे myfunc को हटाएं;"

आशा इस मदद करता है किसी को,

vol7ron

+3

मैं इस के लिए कुछ पॉपकॉर्न पॉपिंग कर रहा हूं। – Pointy

उत्तर

6

आप अच्छा जवाब का एक बेड़ा मिल सकता है। एक निश्चित नकारात्मक इंटरनेट एक्सप्लोरर वृत्तीय संदर्भ स्मृति रिसाव। असल में, कि" परिपत्र "डोम वस्तुओं के लिए संदर्भ JScript द्वारा संग्रहणीय रूप में मान्यता प्राप्त नहीं है। यह बनाने के लिए क्या आईई एक परिपत्र संदर्भ बंद का उपयोग कर समझता है आसान है। कई उदाहरण दूसरी कड़ी में प्रदान की जाती हैं।

IE6 में, स्मृति को पुनः प्राप्त करने का एकमात्र तरीका पूरी प्रक्रिया समाप्त करने के लिए है। आईई 7 में उन्होंने इसे बेहतर किया ताकि जब आप प्रश्न में पृष्ठ से दूर नेविगेट करें (या इसे बंद करें), स्मृति पुनः प्राप्त की जाती है। आईई 8 में, डीओएम ऑब्जेक्ट्स जेस्क्रिप्ट द्वारा बेहतर समझ में आते हैं और एकत्रित होते हैं क्योंकि आप उम्मीद करते हैं कि वे होना चाहिए।

आईई 6 के लिए सुझाए गए कामकाज (प्रक्रिया को समाप्त करने के अलावा!) बंद करने का उपयोग नहीं करना है।

+1

कई जवाब नहीं थे, इसलिए आपको वोट मिलता है। हालांकि मैं आईई 6 के बारे में ज्यादा चिंतित नहीं हूं। (Http://www.w3schools.com/browsers/browsers_stats.asp) के मुताबिक, यह अभी भी 7% तक उपयोग किया जाता है, लेकिन मुझे लगता है कि आने वाले महीनों में नाटकीय रूप से मर जाएगा। आईई के पुराने संस्करणों में सरकार एक बड़ा योगदानकर्ता है, एक बार जब वे नए संस्करण का उपयोग कर लेते हैं, तो बहुत सारे निजी ठेकेदार शायद इसका समर्थन/बंद भी बंद कर देंगे। मुझे लगता है कि पिछले कुछ महीनों में बहुत से सरकारी एजेंसियों ने एक नए, अधिक सुरक्षित ब्राउज़र पर स्विच किया है, खासकर एडोब/आईई 6 खतरे के बाद। – vol7ron

+0

मैं जवाबों की कमी पर भी आश्चर्यचकित हूं। मैं आईई 6 पर अपना मुद्दा लेता हूं; लेकिन अफसोस की बात है, मैं अभी भी कॉर्पोरेट केंद्रित केंद्रित वेब अनुप्रयोगों के आगंतुकों के बीच लगभग 25% आईई 6 देखता हूं। इनमें से कुछ बड़े व्यवसाय इतने रूढ़िवादी हैं कि वे अभी भी अपने विंडोज एक्सपी निवेश से "सनकी लागत" और इसके साथ आईई 6 को दूध डाल रहे हैं। और वे विभिन्न डिग्री, वेब-आधारित विक्रेताओं के प्रगतिशील प्रयासों का वजन कर रहे हैं, फिर भी वे अभी भी अपना व्यवसाय चाहते हैं। मुझे उम्मीद है कि आने वाले महीनों में यह मर जाएगा, लेकिन अगर 2015 में बड़े व्यवसाय अभी भी आईई 6 चला रहे हैं तो मुझे आश्चर्य नहीं होगा। –

0

क्लोजर मेमोरी लीक का कारण बन सकता है, हालांकि मोज़िला ने इसे रोकने के लिए अपने कचरा संग्रहण इंजन को अनुकूलित करने का प्रयास किया है।

मुझे यकीन नहीं है कि क्रोम बंद कैसे करता है। मुझे लगता है कि वे मोज़िला के बराबर हैं, लेकिन मैं निश्चित रूप से कहना नहीं चाहता हूं। आईई 8 निश्चित रूप से आईई के पिछले संस्करणों में सुधार हुआ है - यह लगभग एक नया ब्राउज़र है, अभी भी कुछ बारीकियां हैं।

आपको गति में कोई सुधार होने के लिए कोड को बेंचमार्क करना चाहिए।

6

क्लोजर बहुत सारे लाभ लाते हैं ... लेकिन कई गॉथस भी लाते हैं। वही चीज जो उन्हें शक्तिशाली बनाता है, अगर आप सावधान नहीं हैं तो उन्हें भी गड़बड़ करने में काफी सक्षम बनाता है।

सर्कुलर संदर्भों के साथ इस मुद्दे के अलावा (जो वास्तव में अब तक कोई समस्या नहीं है, क्योंकि आईई 6 चीन के बाहर भी मुश्किल से उपयोग नहीं किया जाता है), कम से कम एक अन्य विशाल संभावित नकारात्मक है: वे दायरे को जटिल बना सकते हैं। जब अच्छी तरह से उपयोग किया जाता है, तो वे बिना किसी एक्सपोज़र के डेटा को साझा करने की अनुमति देकर मॉड्यूलरिटी और संगतता में सुधार करते हैं ... लेकिन जब बुरी तरह से उपयोग किया जाता है, तो यह मुश्किल हो सकता है कि एक चर सेट या बदला गया है, जहां यह पता लगाना असंभव नहीं है।

बंद किए बिना जावास्क्रिप्ट में तीन * चर के लिए स्कॉप्स: ब्लॉक-स्तर, फ़ंक्शन-स्तर और वैश्विक। कोई ऑब्जेक्ट-स्तरीय दायरा नहीं है। बंद होने के बिना, आप जानते हैं कि एक चर या तो वर्तमान फ़ंक्शन में या वैश्विक ऑब्जेक्ट में घोषित किया गया है (क्योंकि वह वैश्विक चर रहता है)।

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

बंद ठीक से उपयोग करना आवश्यक है कि आप (क) कैसे बंद और var गुंजाइश को प्रभावित के बारे में पता हो सकता है, और (ख) ट्रैक जो दायरे से अपने चर में। अन्यथा, चर गलती से साझा किया जा सकता कर रहे हैं रखने के (या छद्म चर खो दिया !), और सभी प्रकार की निराशा हो सकती है।


इस उदाहरण पर विचार:

function ScopeIssues(count) { 
    var funcs = []; 
    for (var i = 0; i < count; ++i) { 
     funcs[i] = function() { console.log(i); } 
    } 
    return funcs; 
} 

, लघु सीधा ... और लगभग निश्चित रूप से टूट। देखें:

x = ScopeIssues(100); 

x[0](); // outputs 100 
x[1](); // does too 
x[2](); // same here 
x[3](); // guess 

सरणी में प्रत्येक फ़ंक्शन count आउटपुट करता है। यहाँ क्या चल रहा है? आप बंद-ओवर चर और दायरे की गलतफहमी के साथ बंद करने के प्रभाव को देख रहे हैं।

जब बंद हो जाते हैं, तो वे आउटपुट को निर्धारित करने के लिए बनाए गए समय पर i के मान का उपयोग नहीं कर रहे हैं। वे परिवर्तनीयi का उपयोग कर रहे हैं, जो बाहरी कार्य के साथ साझा किया जाता है और अभी भी बदल रहा है। जब वे इसे आउटपुट करते हैं, तो वे नामक मान के रूप में मूल्य को आउटपुट कर रहे हैं। यह count के बराबर होगा, वह मान जिसने लूप को रोक दिया था।

इसे ठीक करने के लिए, आपको एक और बंद करने की आवश्यकता होगी।

function Corrected(count) { 
    var funcs = []; 
    for (var i = 0; i < count; ++i) { 
     (function(which) { 
      funcs[i] = function() { console.log(which); }; 
     })(i); 
    } 
} 

x = Corrected(100); 

x[0](); // outputs 0 
x[1](); // outputs 1 
x[2](); // outputs 2 
x[3](); // outputs 3 

एक और उदाहरण:

value = 'global variable'; 

function A() { 
    var value = 'local variable'; 
    this.value = 'instance variable'; 
    (function() { console.log(this.value); })(); 
} 

a = new A(); // outputs 'global variable' 

this और arguments भिन्न हैं; लगभग हर चीज के विपरीत, वे बंद सीमाओं पर साझा किए गए हैं?। हर समारोह कॉल उन्हें पुनर्परिभाषित - और जब तक आप

  • obj.func(...) की तरह समारोह,
  • func.call(obj, ...),
  • func.apply(obj, [...]), या
  • फोन
  • var obj_func = func.bind(obj); obj_func(...)

आप एक this निर्दिष्ट करने के लिए, तो this के लिए डिफ़ॉल्ट मान प्राप्त होगा: वैश्विक वस्तु। ^

सबसे आम मुहावरा this समस्या के समाधान प्राप्त करने के लिए एक चर घोषित करने और this लिए अपने मूल्य निर्धारित करने के लिए है। मैंने देखा है कि सबसे आम नाम that और self हैं।

function A() { 
    var self = this; 
    this.value = 'some value'; 
    (function() { console.log(self.value); })(); 
} 

लेकिन उस self बनाता है सभी संभावित विचित्रता कि जरूरत पर जोर देता के साथ एक वास्तविक चर,। सौभाग्य से, परिवर्तनीय को फिर से परिभाषित किए बिना self के मान को बदलना दुर्लभ है ... लेकिन एक नेस्टेड फ़ंक्शन के भीतर, self को फिर से परिभाषित करने के लिए इसे फिर से निहित सभी कार्यों के लिए फिर से परिभाषित करता है। और अगर आप की तरह

function X() { 
    var self = this; 
    var Y = function() { 
     var outer = self; 
     var self = this; 
    }; 
} 

की वजह से उत्थापन कुछ नहीं कर सकते। जावास्क्रिप्ट प्रभावी रूप से फ़ंक्शन के शीर्ष पर सभी परिवर्तनीय घोषणाओं को स्थानांतरित करता है।यही कारण है कि

function X() { 
    var self, Y; 
    self = this; 
    Y = function() { 
     var outer, self; 
     outer = self; 
     self = this; 
    }; 
} 

self करने के लिए उपरोक्त कोड बराबर बनाता है पहले से ही एक स्थानीय चर outer = self रन से पहले है, इसलिए outer स्थानीय मूल्य हो जाता है - जो इस बिंदु पर, undefined है। आपने अभी बाहरी संदर्भ self पर अपना संदर्भ खो दिया है।


* ES7 के रूप में। पहले, केवल दो थे, और चर को ट्रैक करने के लिए चर भी आसान थे। : पी

? लैम्ब्डा सिंटैक्स (ईएस 7 के लिए नया) का उपयोग करके घोषित कार्य this और arguments को फिर से परिभाषित नहीं करते हैं। जो इस मामले को और भी जटिल रूप से जटिल बनाता है।

^नए दुभाषिया एक तथाकथित "सख्त मोड" का समर्थन करते हैं: एक ऑप्ट-इन सुविधा जिसका उद्देश्य कुछ iffy कोड पैटर्न या तो पूरी तरह विफल हो जाते हैं या कम नुकसान का कारण बनते हैं। सख्त मोड में, this वैश्विक ऑब्जेक्ट की बजाय undefined पर डिफ़ॉल्ट है। लेकिन यह अभी भी आपके साथ गड़बड़ करने के इरादे से कुछ अन्य मूल्य है।

+1

बहुत अच्छा है, लेकिन मुझे लगता है कि आपके पास आखिरी बिट में एक छोटा टाइपो है। "बाहरी 'पहले से ही एक स्थानीय चर है ..." मुझे लगता है कि' बाहरी 'होना चाहिए' स्वयं '? –

+0

@ जेककिंग: ओह ... तय। धन्यवाद :) – cHao

+0

उछाल के स्पष्ट उदाहरण के लिए अप्रत्याशित व्यवहार के लिए अपवोट। –

संबंधित मुद्दे