2013-01-01 17 views
6

Here's an example ऐसी स्थिति का जहां एक साधारण जेएस लूप अपेक्षित व्यवहार नहीं करता है, क्योंकि लूप वैरिएबल एक अलग दायरे में नहीं है।लूप के लिए जावास्क्रिप्ट फ़ंक्शन स्कोप्ड

for (var i in obj) { 
    (function() { 
     ... obj[i] ... 
     // this new shadowed i here is now no longer getting changed by for loop 
    })(i); 
} 

मेरा प्रश्न है, इस पर सुधार किया जा सकता है:

अक्सर प्रस्तुत समाधान है कि इस तरह दिखता है पाश कोड की एक अप्रिय दिखने बिट के निर्माण के लिए है? क्या मैं इसका उपयोग कर सकता हूं:

Object.prototype.each = function (f) { 
    for (var i in this) { 
     f(i,this[i]); 
    } 
}; 

// leading to this somewhat more straightforward invocation 
obj.each(
    function(i,v) { 
     ... v ... 
     // alternatively, v is identical to 
     ... obj[i] ... 
    } 
); 

जब मुझे पता चलता है कि मुझे "स्कॉप्ड लूप" की आवश्यकता है? यह कुछ हद तक साफ दिख रहा है और नियमित रूप से लूप के समान प्रदर्शन होना चाहिए (क्योंकि यह इसे उसी तरह उपयोग करता है)।

अद्यतन: ऐसा लगता है कि Object.prototype के साथ चीजें करना बहुत बड़ा नहीं है क्योंकि यह सब कुछ तोड़ता है।

यहाँ एक कम दखल दिया गया है:

function each (obj,f) { 
    for (var i in obj) { 
     f(i,obj[i]); 
    } 
} 

मंगलाचरण बहुत

each(obj, 
    function(i,v) { 
     ... v ... 
    } 
); 

तो मुझे लगता है कि मैं अपने ही सवाल का जवाब दे दिया है, अगर jQuery यह इस तरह से करता है करने के लिए थोड़ा परिवर्तन, कर सकते हैं वास्तव में गलत नहीं है। किसी भी मुद्दे को मैंने अनदेखा किया है हालांकि एक जवाब वारंट होगा।

+1

जेएस पुस्तकालयों को देखें कि वे 'ऑब्जेक्ट.एच()' शिम को कैसे कार्यान्वित करते हैं। प्रदर्शन और अनुकूलन के लिए, [JSPerf] (http://jsperf.com) का उपयोग करके अपने कोड का परीक्षण करें और आप [CodeReview] (http://codereview.stackexchange.com/) पर पूछ सकते हैं – Joseph

+0

हां मैंने एक नज़र डाली 'jQuery.each() 'अभी अभी और ऐसा लगता है कि मेरा कार्यान्वयन बस उनके तर्क आदेश को फिसलता है और कम करता है (वास्तव में, वास्तव में) चेक करता है। –

उत्तर

1

आपका उत्तर काफी इसमें शामिल है, लेकिन मुझे लगता है कि आपके मूल लूप में बदलाव ध्यान देने योग्य है क्योंकि यह each() फ़ंक्शन किसी भी कारण से आसान नहीं है, जब यह लूप के लिए सामान्य का उपयोग करना उचित बनाता है।

अद्यतन: विभिन्न दृष्टिकोणों की तुलना करने के लिए example referenced by the question के समान उदाहरण का उपयोग करने के लिए बदला गया। उदाहरण को समायोजित किया जाना था क्योंकि each() फ़ंक्शन को एक पॉप्युलेटेड सरणी को फिर से चालू करने की आवश्यकता होती है। निम्नलिखित सेटअप मान लिया जाये कि

:

var vals = ['a', 'b', 'c', 'd'], 
    max = vals.length, 
    closures = [], 
    i; 

सवाल से उदाहरण का उपयोग, मूल पाश 2n कार्यों बनाने (जहां n पुनरावृत्तियों की संख्या है), क्योंकि दो कार्य प्रत्येक यात्रा के दौरान बनाई गई हैं समाप्त होता है:

for (i = 0; i < max; i++) { 
    closures[i] = (function(idx, val) { // 1st - factoryFn - captures the values as arguments 
     return function() {    // 2nd - alertFn - uses the arguments instead 
      alert(idx + ' -> ' + val); //     of the variables 
     }; 
    })(i, vals[i]); 
} 

यह केवल बनाने के लिए कम किया जा सकता n + 1 कार्यों एक बार कारखाने समारोह बनाने, इससे पहले कि पाश शुरू कर दिया है, और फिर से इसे पुन: उपयोग:

var factoryFn = function(idx, val) { 
    return function() { 
     alert(idx + ' -> ' + val); 
    }; 
}; 

for (i = 0; i < max; i++) { 
    closures[i] = factoryFn(i, vals[i]); 
} 

यह इस स्थिति में लगभग each() फ़ंक्शन का उपयोग कैसे किया जा सकता है, जिसके परिणामस्वरूप कुल एन + 1 फ़ंक्शंस भी बनाए जाएंगे। फैक्टरी फ़ंक्शन एक बार बनाया जाता है और each() पर तर्क के रूप में तुरंत पास किया जाता है।

each(vals, function(idx, val) { 
    closures[idx] = function() { 
     alert(idx + ' -> ' + val); 
    }; 
}); 

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

+0

मुझे लगता है कि यह लूप अनावश्यक रूप से असीमित बनाता है। यह जाति की स्थिति जैसे नास्टियों का कारण बनने के लिए उत्तरदायी है जब इसे स्पष्ट रूप से टाला जा सकता है। –

+0

'setTimeout() 'के उपयोग के कारण? मैं इसे एक उदाहरण के रूप में उपयोग कर रहा हूँ; मैंने आपके द्वारा लिंक किए गए उदाहरण को नहीं देखा ... कोई विचार नहीं कि मैं इसे कैसे याद करता हूं। मैंने कुछ और उपयोग करने के लिए उत्तर को संशोधित किया है जैसा आपने प्रश्न में संदर्भित किया है। या, 'setTimeout() 'के अलावा किसी चीज़ के संदर्भ में आपकी टिप्पणी है? – tiffon

+0

हाँ। टीबीएच मुझे नहीं लगता कि मैंने वास्तव में देखा कि आप इसका उपयोग क्यों कर रहे थे, मैं वास्तव में बहुत सी अच्छी चीजें करने के लिए 'सेटटाइमआउट()' का उपयोग करता हूं लेकिन यह भी सच है कि अगर यह नहीं है तो इसे टालना अच्छा विचार है। टी जरूरी नहीं है और यही कारण है कि मैंने टिप्पणी लिखी लेकिन मुझे शायद आपके उत्तर को और अधिक अच्छी तरह से पढ़ना चाहिए था। –

1

वैश्विक स्कोप

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

var बंदर = "गोरिल्ला";

function greetVisitor() { 

return alert("Hello dear blog reader!"); 
} 

कि कोड एक वेब ब्राउज़र में चलाया जा रहा था, तो समारोह गुंजाइश खिड़की होगा, इस प्रकार यह

कि वेब ब्राउज़र विंडो में चल रहा सब कुछ करने के लिए उपलब्ध हो जाता है।

स्थानीय स्कोप

के रूप में वैश्विक क्षेत्र के लिए विरोध किया, स्थानीय गुंजाइश है जब कुछ बस कोड की

खास हिस्से में परिभाषित किया गया है और सुलभ, एक समारोह की तरह है। उदाहरण के लिए;

समारोह talkDirty() {

var saying = "Oh, you little VB lover, you"; 
return alert(saying); 
} 

alert(saying); // Throws an error 

आप उपरोक्त कोड पर एक नज़र डालें, तो चर कहावत talkDirty

समारोह के भीतर ही उपलब्ध है। इसके बाहर यह बिल्कुल परिभाषित नहीं है। सावधानी बरतें: यदि आप बिना

के बिना यह कहने की घोषणा कर रहे थे, तो यह स्वचालित रूप से वैश्विक चर बन जाएगा।

समारोह saveName (firstName) {

समारोह capitalizeName:

क्या यह भी मतलब है कि अगर आप नेस्ट कार्यों, भीतरी समारोह

युक्त कार्यों चर और कार्यों के लिए उपयोग होगा है() {

return firstName.toUpperCase(); 

} वर पूंजीकृत = capitalizeName();

return capitalized; 

}

alert(saveName("Robert")); // Returns "ROBERT" 

तुम सिर्फ देखा था, भीतरी समारोह capitalizeName में भेजे गए किसी भी पैरामीटर जरूरत नहीं थी, लेकिन बाहरी saveName समारोह में पैरामीटर firstName को पूरा

जाने की अनुमति थी ।स्पष्टता के लिए, चलो एक और

उदाहरण लेते हैं:

समारोह भाई बहन() {

var siblings = ["John", "Liza", "Peter"]; 

समारोह siblingCount() {

var siblingsLength = siblings.length; 

return siblingsLength; 

}

समारोह joinSiblingNames() {

return "I have " + siblingCount() + " siblings:\n\n" + siblings.join("\n"); 

}

return joinSiblingNames(); 

}

alert(siblings()); // Outputs "I have 3 siblings: John Liza Peter" 

तुम सिर्फ देखा था, दोनों आंतरिक कार्यों युक्त समारोह में भाई बहन सरणी के लिए उपयोग किया है, और

प्रत्येक भीतरी समारोह उपयोग कर सकते है एक ही स्तर पर अन्य आंतरिक कार्यों के लिए (इस मामले में,

joinSiblingNames siblingCount तक पहुंच सकते हैं)। हालांकि, siblingCount में परिवर्तनीय भाई बहनें

केवल उस फ़ंक्शन के भीतर उपलब्ध है, यानी वह दायरा।

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