जावास्क्रिप्ट चर बाहर या पाश के अंदर घोषित करते हैं?


213

AS3 में मेरा मानना ​​है कि आपको बढ़े प्रदर्शन के लिए लूप के बाहर के सभी वेरिएबल्स को इनिशियलाइज़ करना चाहिए। क्या जावास्क्रिप्ट के साथ भी ऐसा ही है? कौन सा बेहतर / तेज / सर्वोत्तम-अभ्यास है?

var value = 0;

for (var i = 0; i < 100; i++)
{
    value = somearray[i];
}

या

for (var i = 0 ; i < 100; i++)
{
    var value = somearray[i];
}

7
बाहर! हमेशा बाहर।
BGerrissen

37
हम्म, वेरिएबल डिक्लेरेशन को जावास्क्रिप्ट और AS3 दोनों में वैसे भी फंक्शन स्कोप तक नहीं मिलता है? अगर मैं सही हूं, तो यह वास्तव में मायने नहीं रखता।
स्पेंडर

3
@ और - क्या आपने फंक्शन बॉडी में घोषित करने से पहले असाइन करने की कोशिश की थी? शायद आपकी पूर्व धारणाएं आपको भटका रही हैं। डब्ल्यूआरटी प्रदर्शन, पुश-अप स्कूपिंग के साथ, यदि जेएस की व्याख्या की जाती है, तो यह एक लूप ब्लॉक के भीतर अतिरिक्त चक्रों को चबाएगा। यदि संकलित (जो अधिकांश इंजन अब करते हैं) यह कोई फर्क नहीं पड़ता।
खर्चा करने

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

3
मुझे आश्चर्य है कि किसी ने प्रदर्शन को मापने की कोशिश नहीं की। मैंने एक jsperf बनाया । सफारी और फ़ायरफ़ॉक्स के लिए लूप के अंदर घोषित होने पर थोड़ी तेजी से देखा जाता है, क्रोम के लिए विपरीत ...
Buzut

जवाबों:


281

नहीं है बिल्कुल कोई फर्क अर्थ या प्रदर्शन में, जावास्क्रिप्ट या ActionScript में।

varपार्सर के लिए एक निर्देश है, और रन-टाइम पर निष्पादित कमांड नहीं है। यदि किसी varफ़ंक्शन बॉडी (*) में किसी विशेष पहचानकर्ता को एक या अधिक बार घोषित किया गया है , तो ब्लॉक में उस पहचानकर्ता का सभी उपयोग स्थानीय चर का जिक्र होगा। इससे कोई फ़र्क नहीं पड़ता कि लूप के अंदर, लूप के बाहर, या दोनों के रूप valueमें घोषित किया गया है varया नहीं।

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

विशेष रूप से:

for (var i; i<100; i++)
    do something;

for (var i; i<100; i++)
    do something else;

क्रॉकफोर्ड आपको दूसरे को हटाने var(या दोनों को हटाने varऔर var i;ऊपर करने के लिए) की सिफारिश करेगा, और jslint इसके लिए आप पर चिल्लाएगा। लेकिन IMO यह दोनों को बनाए रखने के लिए अधिक रखरखाव योग्य हैvar फ़ंक्शन के शीर्ष पर एक अतिरिक्त, आसानी से भूले हुए बिट के बजाय सभी संबंधित कोड को एक साथ ।

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

(*: नेस्टेड फ़ंक्शन बॉडी के अलावा)


4
मैं अभी भी तय नहीं कर सकता कि मैं क्रोकफोर्ड के साथ हूं या इस पर नहीं। ब्लॉक के अंदर चरों को घोषित करना सशर्त फ़ंक्शन स्टेटमेंट (जो कि शरारती है) का उपयोग करने जैसा थोड़ा महसूस होता है ... हालांकि, मैं आपकी बातों से भी सहमत हूं :) #confused
डैनियल

20
+1 मैं क्रॉकफोर्ड के तर्क (डैनियल के उत्तर में उद्धृत) से असहमत हूं, जावास्क्रिप्ट डेवलपर्स के रूप में हमें कोड नहीं लिखना चाहिए ताकि अन्य "सी परिवार" प्रोग्रामर इसे समझ सकें। मैं अक्सर अंदर var का उपयोग करता हूं अगर ब्लॉक और लूप्स क्योंकि यह मेरे लिए अधिक समझ में आता है।
एंडी ई

4
-1 ओपी पूछ रहा है कि क्या लूप शुरू होने से पहले लूप के शरीर में वेरिएशन घोषित किया जाना चाहिए। लूप का सूचकांक मूल्य स्पष्ट रूप से एक विशेष मामला है (और फहराया जाता है) और ओपी को बिल्कुल भी मदद नहीं करता है।
मोकेस्टिनन

21
लूप इंडेक्स एक विशेष मामला नहीं है, वे एक सामान्य असाइनमेंट की तरह ही संभाले और फहराए जाते हैं।
बॉब

31
+1 क्रॉकफोर्ड इस बारे में गलत है (और अन्य, लेकिन मैं पचाता हूं)। कि आवश्यकता होती है varकेवल एक समारोह के शीर्ष पर प्रयोग किया जाता है सिर्फ आकस्मिक वैश्विक चर निर्माण के लिए पूछ रहा है। और असंबंधित चरों का एक द्रव्यमान होने से सभी एक ही स्थान पर घोषित शब्दार्थ निरर्थक होते हैं, विशेषकर तब जब उन चरों में से कुछ अंत में कभी उपयोग नहीं किए जा सकते हैं।
मूगू

64

सिद्धांत रूप में इसे जावास्क्रिप्ट में कोई अंतर नहीं करना चाहिए, क्योंकि भाषा में ब्लॉक गुंजाइश नहीं है, लेकिन केवल कार्यक्षेत्र है।

मैं प्रदर्शन तर्क के बारे में निश्चित नहीं हूं, लेकिन डगलस क्रॉकफोर्ड अभी भी सिफारिश करता है कि varफ़ंक्शन बॉडी में पहले बयान होने चाहिए। जावास्क्रिप्ट प्रोग्रामिंग भाषा के लिए कोड सम्मेलनों से उद्धरण :

जावास्क्रिप्ट में ब्लॉक स्कोप नहीं है, इसलिए ब्लॉक में चर को परिभाषित करने से प्रोग्रामर को भ्रमित किया जा सकता है जो अन्य सी परिवार की भाषाओं के साथ अनुभवी हैं। फ़ंक्शन के शीर्ष पर सभी चर को परिभाषित करें।

मुझे लगता है कि उसके पास एक बिंदु है, जैसा कि आप निम्नलिखित उदाहरण में देख सकते हैं। फ़ंक्शन के शीर्ष पर चर की घोषणा करते हुए पाठकों को यह सोचने में भ्रमित नहीं करना चाहिए कि चर लूप ब्लॉक i के दायरे में है for:

function myFunction() {
  var i;    // the scope of the variables is very clear

  for (i = 0; i < 10; i++) {
    // ...
  }
}

8
जेएस दायरे के बारे में ओपी सत्य बताने के लिए +1। मैं सोच रहा हूँ कि क्या जवाब है कि अन्यथा कहना है!
स्पेंडर

1
@ कीरनमाइन: मैंने यह नहीं कहा कि यह प्रदर्शन को प्रभावित नहीं करता है। मैंने सिर्फ उन्हें छोरों के बाहर रखने के लिए एक तर्क दिया, प्रदर्शन के अप्रासंगिक .... मेरे पास प्रदर्शन के तर्कों के लिए कोई संदर्भ नहीं है, लेकिन आपने अपने उत्तर में किसी का भी हवाला नहीं दिया :)
डैनियल वासल्लो

1
@ कीरणमाईन: क्या आपके पास इसके लिए कोई स्रोत है?
एंडी ई

5
@ कीरनमाइन: AFAIK भले ही आप एक लूप के अंदर वेरिएबल की घोषणा ecma- / javascriptकरते हैं, रनटाइम पर उन्हें टक्कर देंगे। इसे "उत्थापन" कहा जाता है। इसलिए कोई अंतर नहीं होना चाहिए।
जॉन्डी

1
ES6 letइस उत्तर को कैसे प्रभावित करता है ?
19

58

ECMA-/Javascriptभाषा hoistsकोई भी चर जो एक समारोह के शीर्ष करने के लिए कहीं भी घोषित किया जाता है। ऐसा इसलिए है क्योंकि इस भाषा है करता है function scopeऔर करता नहीं है block scopeकई अन्य भाषाओं सी की तरह की तरह।
इस रूप में भी जाना जाता है lexical scope

अगर आप कुछ घोषित करते हैं

var foo = function(){
    for(var i = 0; i < 10; i++){
    }
};

यह हो जाता hoistedहै:

var foo = function(){
    var i;
    for(i = 0; i < 10; i++){
    }
}

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


एक ही स्वीकार किए जाते हैं, लेकिन IMO के रूप में एक ही मूल उत्तर, अधिक पठनीय और सिर्फ जानकारीपूर्ण के रूप में। अच्छी नौकरी।
ऐनी गुन

5
ES6 letइस उत्तर को कैसे प्रभावित करता है ?
19

13

अगले साल, सभी ब्राउज़रों के पास जेएस इंजन होंगे जो कोड को रोकते हैं इसलिए प्रदर्शन अंतर (जो बार-बार कोड के समान ब्लॉक को पार्स करने से आता है और साथ ही असाइनमेंट को निष्पादित करने से) नगण्य हो जाना चाहिए।

इसके अलावा, प्रदर्शन के लिए कभी भी ऑप्टिमाइज़ न करें जब तक आपको करना न पड़े। चर को उस स्थान के पास रखना जहाँ आपको उनकी पहली आवश्यकता होती है, आपके कोड को साफ रखता है। नकारात्मक पक्ष पर, ब्लॉक स्कोप वाली भाषाओं के लिए उपयोग किए जाने वाले लोग भ्रमित हो सकते हैं।


6

एक और विचार, अब जो हमारे पास है letऔर constES2015 में है, वह यह है कि अब आप विशेष रूप से लूप ब्लॉक में वेरिएबल को स्कोप कर सकते हैं। इसलिए जब तक आपको लूप के बाहर एक ही चर की आवश्यकता नहीं होगी (या यदि प्रत्येक पुनरावृत्ति पिछले चर में उस चर के लिए किए गए एक ऑपरेशन पर निर्भर करता है), तो शायद ऐसा करना बेहतर होगा:

for (let i = 0; i < 100; i++) {
    let value = somearray[i];
    //do something with `value`
}

4

मैंने अभी क्रोम में एक साधारण परीक्षण किया था। अपने ब्राउज़र में फ़िडेल आज़माएं और परिणाम देखें

  var count = 100000000;
    var a = 0;
    console.log(new Date());

    for (var i=0; i<count; i++) {
      a = a + 1
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
      a = a + 1;
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
        var x;
        x = x + 1;
    }

    console.log(new Date());

परिणाम यह है कि अंतिम परीक्षा में ~ 8 सेकंड लगते हैं और पिछले 2 केवल ~ 2 सेकंड हैं। बहुत बार-बार और आदेश की परवाह किए बिना।

तो, यह मेरे लिए साबित होता है, कि व्यक्ति को हमेशा लूप के बाहर के संस्करण की घोषणा करनी चाहिए। मेरे लिए जिज्ञासु मामला पहला है जहां मैं i() बयान में घोषणा करता हूं । यह दूसरा परीक्षण जैसा ही तेज प्रतीत होता है जहां मैं सूचकांक को पूर्व घोषित करता हूं।


14
@KP: परिणाम केवल तभी साबित होते हैं यदि आप उन्हें स्वयं परखते हैं या यदि बड़ी संख्या में लोग उन्हें सत्यापित करते हैं। @ मकोइस्टिन: मैंने एक निष्पक्ष परीक्षण का निर्माण किया, jsfiddle.net/GM8nk । Chrome 5 में कई बार स्क्रिप्ट चलाने के बाद, मैं देख सकता था कि कोई लगातार विजेता नहीं था। तीनों विविधताओं ने कुछ ताजगी के बाद दूसरों की तुलना में बेहतर प्रदर्शन किया। -1 से, मुझे डर है। ध्यान दें, आप को चलाने के लिए चाहते हो सकता है यह एक अन्य ब्राउज़र में। IE और Fx 100 मिलियन पुनरावृत्तियों को पसंद नहीं करता था।
एंडी ई।

1
@AndyE। वाह, तो यह बस परीक्षण के आधार पर, IE 100X अधिक बेकार है? =)
मोकिस्टीनन

2
परिणाम मेरे लिए सभी जगह हैं, कोई स्पष्ट क्रॉस-ब्राउज़र विजेता नहीं है, हालांकि कभी-कभी महत्वपूर्ण गति अंतर होते हैं। अजीब। मुझे लगता है कि एंडी की फिडल एक बेहतर परीक्षा है, हालांकि प्रत्येक उम्मीदवार को अपने कार्य में लगा रहा है ... निश्चित रूप से यदि मूल स्क्रिप्ट को किसी फ़ंक्शन के बाहर चलाया जाता है, तो यह वास्तव में कुछ भी परीक्षण नहीं करना चाहिए क्योंकि यह varवैश्विक रूप से एक चर के रूप में घोषित कर रहा है वैसे भी वैश्विक हो।
बोबिन्स

4
तथ्य के एक साल बाद, लेकिन SHAPOW
sdleihssirhc

2
यह मेरा नहीं है, लेकिन मुझे लगा कि आप में से कुछ को दिलचस्पी होगी: jsperf.com/var-in-for-loop
m1।

1

जावास्क्रिप्ट C या C ++ द्वारा सबसे नीचे लिखी गई भाषा है, मुझे यकीन नहीं है कि यह कौन सी है। और इसका एक उद्देश्य आंतरिक मेमोरी को संभालने के लवर को सहेजना है। यहां तक ​​कि सी या सी ++ में, आपको इस बारे में चिंता करने की ज़रूरत नहीं होगी कि क्या यह बहुत सारे संसाधनों का उपभोग करेगा जब चर एक लूप के अंदर घोषित किए जाते हैं। आपको जावास्क्रिप्ट में इसकी चिंता क्यों करनी चाहिए?


1
C या C ++ जावास्क्रिप्ट के नीचे हो सकता है। लेकिन हमें यह नहीं भूलना चाहिए कि, ब्राउज़र जावास्क्रिप्ट को अंतर्निहित भाषा (C, C ++) में परिवर्तित करता है। इसलिए प्रदर्शन ब्राउज़र पर निर्भर करता है
किरा

3
@ किरा वास्तव में C / C ++ में परिवर्तित नहीं होता है। जावास्क्रिप्ट निर्देश के एक सेट में संकलित हो जाता है जिसे जेएस रनटाइम (ब्राउज़र में चलने वाली एक आभासी मशीन) द्वारा निष्पादित किया जाता है। यही सिद्धांत अन्य गतिशील भाषाओं जैसे कि पायथन और रूबी पर भी लागू होता है।
एंथनी ई

@AnthonyE, जानकारी के लिए धन्यवाद। मुझे यकीन नहीं था कि जेएस सी या सी ++ में परिवर्तित हो सकता है। मैं प्रयोग किया जाता है तो हो सकता है मेरी टिप्पणी में
Kira

0

ठीक है, यह इस बात पर निर्भर करता है कि आप क्या हासिल करने की कोशिश कर रहे हैं ... अगर valueमान लें कि लूप ब्लॉक के अंदर केवल एक अस्थायी चर है तो दूसरे रूप का उपयोग करना बहुत स्पष्ट है। यह अधिक तार्किक और क्रियात्मक भी है।


मैंने पाया है कि सभी परिवर्तनीय घोषणाओं को शीर्ष तक ले जाना - जिसमें अस्थायी चर भी शामिल हैं - वास्तव में भ्रम पैदा कर सकता है क्योंकि यह सिर्फ 'शोर' हो जाता है।
डैनियल सोकोलोव्स्की

0

यदि आप लूप के अंदर या बाहर चर घोषित करते हैं तो इससे कोई फर्क नहीं पड़ता। नीचे परीक्षण करने के लिए नमूना कोड है।

function a() {
   console.log('Function a() starts');
   console.log(new Date());
    var j;
    for (j=0; j<100000000; j++) {
        var x;
        x = x + 1;
    }
    console.log(new Date());
    console.log('Function a() Ends');
}
a()
function b() {
console.log('Function B() starts');
   console.log(new Date());
    var a;
    var j;
    for (j=0; j<100000000; j++) {
      a = a + 1;
    }
    console.log(new Date());
    console.log('Function B() Ends');
}
b()

मेरे मामले में परिणाम दिखाई दिए

Function a() starts
VM121:3 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:9 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:10 Function a() Ends
VM121:14 Function B() starts
VM121:15 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:21 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:22 Function B() Ends

साभार - MyFavs.in


दोनों मामलों में आप लूप के बाहर j घोषित करते हैं! X_x
जॉन ktejik

मैंने इसे क्रोमियम 81 letमें देखा varऔर इसके बजाय a()थोड़ा धीमा होने की कोशिश की (जैसे 120 बनाम 115 एमएस = ~ 6% = आईएमओ नगण्य)
mikiqex

-1

यहां सवाल मूल रूप से लूप के अंदर एक संस्करण घोषित करने का है। जरा सोचिए अगर आप ऐसा करते हैं तो क्या होगा:

var a = 30;
var a = 50;
var a = 60;

क्या आपको लगता है कि यह सही है? नहीं ... क्योंकि आप एक चर को इतनी बार घोषित नहीं करना चाहते हैं। जब आप लूप के अंदर एक वैरिएबल की घोषणा करते हैं तो क्या यह ऐलान नहीं होता है कि लूप कितनी बार चलता है? स्पष्ट रूप से यह आपको थप्पड़ मार देगा जब आप 'सख्त उपयोग' मोड में होंगे। लोग मूल प्रश्न के बारे में सोचे बिना क्रॉकफोर्ड से असहमत थे।

इसलिए शीर्ष पर चर घोषित करना हमेशा अच्छा होता है - 1. पठनीयता के लिए, 2. अच्छी आदतें बनाना।


1
"जब आप लूप के अंदर एक वैरिएबल की घोषणा करते हैं तो क्या यह ऐलान नहीं होता है कि लूप कितनी बार चलता है?" <- नहीं, यह सही नहीं है। परिवर्तनशील घोषणा फहरा दी जाती है, इसलिए आप सभी को असाइनमेंट के साथ छोड़ दिया जाता है।
मथियास

-2

Linux OS पर Chrome, Firefox, और jsperf पर परीक्षण चलाने के बाद प्रदर्शन के संबंध में, लूप में चर की घोषणा और लूप से बाहर के बीच एक प्रदर्शन अंतर प्रतीत होता है। यह एक छोटा सा अंतर है लेकिन यह पुनरावृत्तियों की मात्रा और चर घोषणाओं की मात्रा से भी जटिल है।

इसलिए सर्वश्रेष्ठ प्रदर्शन के लिए मुझे लूप के बाहर चर घोषित करने का सुझाव देना होगा। या बेहतर अभी तक अपने चर को लाइन में घोषित करें। उदाहरण देखें।

// inline
for (var ai = 0, al = 100000000, av; ai < al; ai++) {
    av = av + 1;
}

// outside
var bv;
var bl = 100000000;
for (var bi = 0; bi < bl; bi++) {
    bv = bv + 1;
}

गौर करें कि लूप डिक्लेरेशन लाइन में वेरिएबल 'अल' और 'एवी' कैसे हैं। इस इनलाइन घोषणा ने मुझे लगातार बेहतर प्रदर्शन प्रदान किया है। लूप के बाहर चरों की घोषणा पर भी। फिर से प्रदर्शन अंतर वास्तव में छोटा है।

https://jsperf.com/outside-inline-for-loop-ase/1


मेरे लिए आपका परीक्षण पाश के अंदर दिया गया। और हालाँकि यह नहीं था, यह निष्कर्ष निकालने के लिए अंतर बहुत छोटा है, और स्वीकृत उत्तर स्पष्ट रूप से समझाता है कि कोई अंतर नहीं है
उलिनेस बीएन

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