AngularJS नियंत्रकों में 'यह' बनाम $ गुंजाइश


1026

में AngularJS के मुखपृष्ठ के "बनाएँ घटक" खंड , इस उदाहरण है:

controller: function($scope, $element) {
  var panes = $scope.panes = [];
  $scope.select = function(pane) {
    angular.forEach(panes, function(pane) {
      pane.selected = false;
    });
    pane.selected = true;
  }
  this.addPane = function(pane) {
    if (panes.length == 0) $scope.select(pane);
    panes.push(pane);
  }
}

ध्यान दें कि selectविधि को कैसे जोड़ा जाता है $scope, लेकिन addPaneविधि को जोड़ा जाता है this। यदि मैं इसे बदल देता हूं $scope.addPane, तो कोड टूट जाता है।

प्रलेखन कहता है कि वास्तव में एक अंतर है, लेकिन यह उल्लेख नहीं करता है कि अंतर क्या है:

एंगुलर (पूर्व 1.0 आरसी) के पिछले संस्करणों ने आपको विधि के thisसाथ परस्पर उपयोग करने की अनुमति दी थी $scope, लेकिन अब ऐसा नहीं है। तरीकों में से अंदर गुंजाइश पर परिभाषित thisऔर $scopeपरस्पर विनिमय (कोणीय सेट हैं thisकरने के लिए $scope), लेकिन अन्यथा अपने नियंत्रक निर्माता के अंदर नहीं।

कैसे काम करता है thisऔर $scopeAngularJS नियंत्रकों में काम करता है?


मुझे यह भ्रामक भी लगता है। जब कोई दृश्य नियंत्रक (जैसे, एनजी-नियंत्रक = '...') निर्दिष्ट करता है, तो उस नियंत्रक के साथ जुड़ा हुआ $ स्कोप इसके साथ आने लगता है, क्योंकि दृश्य $ स्कोप गुण तक पहुँच सकता है। लेकिन जब एक निर्देश 'के लिए किसी अन्य नियंत्रक की आवश्यकता होती है (और इसके लिंकिंग फ़ंक्शन में इसका उपयोग होता है), तो उस अन्य नियंत्रक से जुड़े $ गुंजाइश इसके साथ नहीं आते हैं?
मार्क राजकोक

क्या "पिछले संस्करणों ..." के बारे में भ्रामक उद्धरण अब तक हटा दिया गया है? तब शायद अद्यतन जगह में होगा?
दिमित्री जैतसेव

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

जवाबों:


999

"कैसे करता है thisऔर $scopeAngularJS नियंत्रकों में काम करता है?"

संक्षिप्त उत्तर :

  • this
    • जब नियंत्रक कंस्ट्रक्टर फ़ंक्शन को कहा जाता है, thisतो नियंत्रक है।
    • जब किसी $scopeऑब्जेक्ट पर परिभाषित फ़ंक्शन को कहा जाता है, thisतो "प्रभाव में गुंजाइश तब होती है जब फ़ंक्शन कहा जाता था"। यह हो सकता है (या नहीं!) हो सकता है $scopeकि फ़ंक्शन को परिभाषित किया गया है। तो, समारोह के अंदर, thisऔर $scopeहो सकता है नहीं ही होना।
  • $scope
    • हर कंट्रोलर के पास एक संबद्ध $scopeऑब्जेक्ट होता है।
    • एक नियंत्रक (कंस्ट्रक्टर) फ़ंक्शन मॉडल की संपत्तियों और कार्यों / व्यवहार को इसके संबद्ध पर सेट करने के लिए जिम्मेदार है $scope
    • इस $scopeऑब्जेक्ट (और पैरेंट स्कोप ऑब्जेक्ट्स, यदि प्रोटॉपिकल इनहेरिटेंस प्ले में हैं) पर परिभाषित केवल विधियाँ HTML / दृश्य से सुलभ हैं। जैसे, ng-clickफिल्टर, आदि से।

लंबे उत्तर :

एक नियंत्रक फ़ंक्शन एक जावास्क्रिप्ट निर्माता फ़ंक्शन है। जब कंस्ट्रक्टर फ़ंक्शन निष्पादित होता है (उदाहरण के लिए, जब एक लोड होता है), this(यानी, "फ़ंक्शन संदर्भ") नियंत्रक ऑब्जेक्ट पर सेट होता है। इसलिए "टैब" कंट्रोलर कंस्ट्रक्टर फंक्शन में, जब ऐडपैन फंक्शन बनता है

this.addPane = function(pane) { ... }

इसे नियंत्रक वस्तु पर बनाया गया है, $ स्कोप पर नहीं। AddPane फ़ंक्शन को दृश्य नहीं देख सकते हैं - उनके पास केवल $ गुंजाइश पर परिभाषित फ़ंक्शन तक पहुंच है। दूसरे शब्दों में, HTML में, यह काम नहीं करेगा:

<a ng-click="addPane(newPane)">won't work</a>

"टैब" नियंत्रक निर्माता फ़ंक्शन निष्पादित करने के बाद, हमारे पास निम्नलिखित हैं:

टैब कंट्रोलर कंस्ट्रक्टर फंक्शन के बाद

धराशायी काली रेखा, प्रोटोटाइप विरासत को इंगित करती है - स्कोप से एक अलग गुंजाइश प्रोटोटाइपिक विरासत । (यह HTML में निर्देश का सामना करने वाले प्रभाव के दायरे से प्रोटोटाइप के वारिस नहीं है।)

अब, फलक निर्देश का लिंक फ़ंक्शन टैब निर्देश के साथ संवाद करना चाहता है (जिसका वास्तव में मतलब है कि यह टैब को किसी तरह से अलग करने की गुंजाइश को प्रभावित करने की आवश्यकता है)। घटनाओं का इस्तेमाल किया जा सकता है, लेकिन एक अन्य तंत्र के लिए requireटैब नियंत्रक को फलक निर्देशन करना है। ( requireटैब के $ दायरे में फलक निर्देश के लिए कोई तंत्र प्रतीत नहीं होता है ।)

तो, यह सवाल भी पैदा करता है: यदि हमारे पास केवल टैब नियंत्रक तक पहुंच है, तो हम टैब की पहुंच को $ गुंजाइश को अलग कैसे करते हैं (जो कि हम वास्तव में चाहते हैं)?

खैर, लाल बिंदीदार रेखा इसका जवाब है। AddPane () फंक्शन का "स्कोप" (मैं जावास्क्रिप्ट फंक्शन स्कोप / यहाँ क्लोजर की बात कर रहा हूँ) फंक्शन एक्सेस को टैब में अलग-अलग $ स्कोप देता है। यानी, addPane () में एक क्लोजर के कारण ऊपर दिए गए आरेख में "टैब IsolateScope" तक पहुंच है, जो कि addPane () को परिभाषित करते समय बनाया गया था। (यदि हम इसके बजाय टैब $ स्कोप ऑब्जेक्ट पर addPane () को परिभाषित करते हैं, तो फलक निर्देश इस फ़ंक्शन तक पहुंच नहीं होगा, और इसलिए इसका टैब $ स्कोप के साथ संवाद करने का कोई तरीका नहीं होगा।)

अपने प्रश्न के अन्य भाग का उत्तर देने के लिए how does $scope work in controllers?:

$ स्कोप पर परिभाषित कार्यों के भीतर, this"फ़ंक्शन में / जब कॉल किया गया था, तब प्रभाव में $ स्कोप" पर सेट है। मान लें कि हमारे पास निम्नलिखित HTML हैं:

<div ng-controller="ParentCtrl">
   <a ng-click="logThisAndScope()">log "this" and $scope</a> - parent scope
   <div ng-controller="ChildCtrl">
      <a ng-click="logThisAndScope()">log "this" and $scope</a> - child scope
   </div>
</div>

और ParentCtrl(एकमात्र) है

$scope.logThisAndScope = function() {
    console.log(this, $scope)
}

पहली लिंक पर क्लिक करने कि दिखाएगा thisऔर $scopeएक ही हैं, क्योंकि " प्रभाव में गुंजाइश जब समारोह कहा जाता था " के साथ जुड़े गुंजाइश है ParentCtrl

दूसरे लिंक पर क्लिक करने से पता चलेगा thisऔर $scopeये समान नहीं हैं , क्योंकि " प्रभाव में स्कोप जब फंक्शन को कहा जाता है " से संबंधित स्कोप है ChildCtrl। तो यहाँ, thisपर सेट किया जाता ChildCtrlहै $scope। विधि के अंदर, $scopeअभी भी ParentCtrl$ गुंजाइश है।

बेला

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


6
@tamakisquare, मेरा मानना ​​है कि आपके द्वारा उद्धृत बोल्ड टेक्स्ट तब लागू होता है जब नियंत्रक कंस्ट्रक्टर फ़ंक्शन को कहा जाता है - यानी, जब नियंत्रक बनाया जाता है = एक $ गुंजाइश के साथ जुड़ा हुआ है। यह बाद में लागू नहीं होता है, जब मनमाने ढंग से जावास्क्रिप्ट कोड $ स्कोप ऑब्जेक्ट पर परिभाषित विधि को कॉल करता है।
मार्क राजकॉक

79
ध्यान दें कि अब नियंत्रक को नाम देकर टेम्पलेट में सीधे addPane () फ़ंक्शन को कॉल करना संभव है: "MyController as myctrl" और फिर myctrl.addPane ()। Docs.angularjs.org/guide/concepts#controller
Christophe Augier

81
बहुत अधिक अंतर्निहित जटिलता।
इनक गमूस

11
यह एक बहुत ही जानकारीपूर्ण उत्तर है, लेकिन जब मैं एक व्यावहारिक समस्या के साथ वापस आया ( $ स्कोप कैसे लागू किया जाए। $ लागू करें) एक नियंत्रक विधि में 'इस' का उपयोग करके परिभाषित किया गया था ) मैं इसे काम नहीं कर सका। इसलिए जबकि यह अभी भी एक उपयोगी उत्तर है, मैं "अंतर्निहित जटिलता" को चकित कर रहा हूं।
dumbledad

11
जावास्क्रिप्ट - बहुत सारी रस्सी [अपने आप को लटकाने के लिए]।
एलिकएल्ज़िन-किलाका

55

निर्देश के कारण 'addPane' को इसका कारण दिया गया है <pane>

paneनिर्देश करता है require: '^tabs', जो माता-पिता के निर्देश से टैब नियंत्रक वस्तु डालता है, लिंक समारोह में।

addPaneको सौंपा गया है thisताकि paneलिंक फ़ंक्शन इसे देख सके। फिर paneलिंक फ़ंक्शन में, नियंत्रक addPaneकी एक संपत्ति है tabs, और यह सिर्फ tabsControllerObject.addPane है। तो फलक निर्देशन का लिंकिंग फ़ंक्शन टैब कंट्रोलर ऑब्जेक्ट तक पहुंच सकता है और इसलिए ऐडपैन विधि का उपयोग कर सकता है।

मुझे आशा है कि मेरी व्याख्या पर्याप्त स्पष्ट है .. यह व्याख्या करना कठिन है।


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

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

1
अरे निशान, यह वास्तव में निर्देश के दायरे को संशोधित करने के लिए आसान है। आप बस लिंक फ़ंक्शन का उपयोग कर सकते हैं jsfiddle.net/TuNyj
एंड्रयू जोसलिन

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

27

मैं सिर्फ दोनों के बीच अंतर पर एक बहुत ही रोचक व्याख्या पढ़ता हूं, और नियंत्रक को मॉडल संलग्न करने की बढ़ती प्राथमिकता और मॉडल को देखने के लिए मॉडल को बांधने के लिए नियंत्रक है। http://toddmotto.com/digging-into-angulars-controller-as-syntax/ लेख है।
वह इसका उल्लेख नहीं करता है, लेकिन निर्देशों को परिभाषित करते समय, यदि आपको कई निर्देशों के बीच कुछ साझा करने की आवश्यकता है और एक सेवा नहीं चाहते हैं (ऐसे वैध मामले हैं जहां सेवाएं एक परेशानी हैं) तो माता-पिता के निर्देशक के नियंत्रक को डेटा संलग्न करें।

$scopeसेवा उपयोगी चीजें के बहुत सारे प्रदान करता है, $watchसबसे स्पष्ट किया जा रहा है, लेकिन अगर तुम सब, देखने के लिए बाँध डेटा की जरूरत है टेम्पलेट में सादे नियंत्रक और 'के रूप में नियंत्रक' का उपयोग ठीक है और यकीनन बेहतर है।


20

मैं आपको निम्नलिखित पोस्ट पढ़ने की सलाह देता हूं: AngularJS: "नियंत्रक के रूप में" या "$ गुंजाइश"?

यह "$ गुंजाइश" पर चर को बेनकाब करने के लिए "नियंत्रक के रूप में" का उपयोग करने के बहुत अच्छी तरह से फायदे का वर्णन करता है।

मुझे पता है कि आपने विशेष रूप से तरीकों और चर के बारे में नहीं पूछा है, लेकिन मुझे लगता है कि एक तकनीक से चिपके रहना और उसके अनुरूप होना बेहतर है।

इसलिए मेरी राय के लिए, पोस्ट में चर्चित चर मुद्दे के कारण, "नियंत्रक के रूप में" तकनीक का उपयोग करना बेहतर है और इसे विधियों पर भी लागू करें।


16

इस पाठ्यक्रम में ( https://www.codeschool.com/courses/shaping-up-with-angular-js ) वे बताते हैं कि "यह" और कई अन्य सामान का उपयोग कैसे करें।

यदि आप "इस" विधि के माध्यम से नियंत्रक में विधि जोड़ते हैं, तो आपको इसे नियंत्रक के नाम "डॉट" के साथ अपनी संपत्ति या विधि में देखना होगा।

उदाहरण के लिए अपने नियंत्रक को देखने के लिए आपके पास इस तरह कोड हो सकता है:

    <div data-ng-controller="YourController as aliasOfYourController">

       Your first pane is {{aliasOfYourController.panes[0]}}

    </div>

6
पाठ्यक्रम से गुजरने के बाद, मैं तुरंत कोड का उपयोग करके भ्रमित हो गया था $scope, इसलिए इसका उल्लेख करने के लिए धन्यवाद।
मैट मोंटाग

16
उस कोर्स में $ गुंजाइश का उल्लेख नहीं है, वे सिर्फ उपयोग करते हैं asऔर thisइसलिए यह अंतर समझाने में कैसे मदद कर सकता है?
dumbledad

10
कोणीय के साथ मेरा पहला स्पर्श उल्लेखित पाठ्यक्रम से था, और जैसा $scopeकि कभी भी संदर्भित नहीं किया गया था, मैंने केवल thisनियंत्रकों में उपयोग करना सीखा । समस्या यह है कि जब आप अपने नियंत्रक में वादे करना शुरू करते हैं, तो आपके पास वादे वापसी फ़ंक्शन के भीतर से संदर्भ को मॉडल करने के लिए बहुत सारी संदर्भ समस्याएँ होती हैं thisऔर उन्हें करना शुरू करना पड़ता है । इस वजह से, मैं अभी भी बहुत उलझन में हूं कि मुझे किस विधि का उपयोग करना चाहिए, या । var me = thisthis$scopethis
ब्रूनो फिंगर

@BrunoFinger दुर्भाग्य से, आपको आवश्यकता होगी var me = thisया .bind(this)जब भी आप वादे करेंगे, या अन्य बंद-भारी सामान। इसका एंगुलर से कोई लेना-देना नहीं है।
द्ज़मिट्री लेज़रका

1
महत्वपूर्ण बात यह जानना है कि नियंत्रक में ng-controller="MyCtrl as MC"डालने के बराबर $scope.MC = thisहै - यह टेम्पलेट में उपयोग के लिए गुंजाइश पर MyCtrl की एक आवृत्ति (इस) को परिभाषित करता है{{ MC.foo }}
विलियम बी

3

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

इस व्यवहार को वापस लाने के लिए (क्या कोई जानता है कि इसे क्यों बदला गया था?) आप जोड़ सकते हैं:

return angular.extend($scope, this);

आपके नियंत्रक फ़ंक्शन के अंत में (बशर्ते कि $ गुंजाइश इस नियंत्रक फ़ंक्शन को इंजेक्ट की गई थी)।

यह नियंत्रक वस्तु के माध्यम से माता-पिता के दायरे तक पहुंच का एक अच्छा प्रभाव है जिसे आप बच्चे के साथ प्राप्त कर सकते हैं require: '^myParentDirective'


7
यह आलेख इस और $ गुंजाइश अलग क्यों हैं की एक अच्छी व्याख्या प्रदान करता है।
रॉबर्ट मार्टिन

1

$ स्कोप का एक अलग 'यह' है तो कंट्रोलर 'दिस'। यदि आप कंसोल लगाते हैं। तो (यह) कंट्रोलर के अंदर यह आपको ऑब्जेक्ट (कंट्रोलर) देता है और इस.डीडीपेन () कंट्रोलर ऑब्जेक्ट में ऐडपैन मेथड जोड़ता है। लेकिन $ स्कोप का अलग-अलग स्कोप होता है और इसके स्कोप में सभी तरीके को $ स् स् स्.प्र.मिथोडनाम () द्वारा एक्सेप्ट करना पड़ता है। this.methodName()कंट्रोलर का मतलब कंट्रोलर ऑब्जेक्ट के अंदर मेथोज जोड़ना है। $scope.functionName()HTML और अंदर है

$scope.functionName(){
    this.name="Name";
    //or
    $scope.myname="myname"//are same}

इस कोड को अपने संपादक में पेस्ट करें और देखने के लिए ओपन कंसोल ...

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>this $sope vs controller</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
    <script>
        var app=angular.module("myApp",[]);
app.controller("ctrlExample",function($scope){
          console.log("ctrl 'this'",this);
          //this(object) of controller different then $scope
          $scope.firstName="Andy";
          $scope.lastName="Bot";
          this.nickName="ABot";
          this.controllerMethod=function(){

            console.log("controllerMethod ",this);
          }
          $scope.show=function(){
              console.log("$scope 'this",this);
              //this of $scope
              $scope.message="Welcome User";
          }

        });
</script>
</head>
<body ng-app="myApp" >
<div ng-controller="ctrlExample">
       Comming From $SCOPE :{{firstName}}
       <br><br>
       Comming from $SCOPE:{{lastName}}
       <br><br>
       Should Come From Controller:{{nickName}}
       <p>
            Blank nickName is because nickName is attached to 
           'this' of controller.
       </p>

       <br><br>
       <button ng-click="controllerMethod()">Controller Method</button>

       <br><br>
       <button ng-click="show()">Show</button>
       <p>{{message}}</p>

   </div>

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