कॉफ़ीस्क्रिप्ट में एक क्लास बनाते समय, सभी =>
("वसा तीर") ऑपरेटर का उपयोग करके सभी इंस्टेंस विधि को परिभाषित किया जाना चाहिए और ऑपरेटर का उपयोग करते हुए सभी स्थिर तरीकों को परिभाषित किया जाना चाहिए ->
?
कॉफ़ीस्क्रिप्ट में एक क्लास बनाते समय, सभी =>
("वसा तीर") ऑपरेटर का उपयोग करके सभी इंस्टेंस विधि को परिभाषित किया जाना चाहिए और ऑपरेटर का उपयोग करते हुए सभी स्थिर तरीकों को परिभाषित किया जाना चाहिए ->
?
जवाबों:
नहीं, यह वह नियम नहीं है जिसका मैं उपयोग करूंगा।
परिभाषित करने के तरीकों में वसा-तीर के लिए मुझे जो प्रमुख उपयोग-मामला मिला है, वह है जब आप कॉलबैक के रूप में एक विधि का उपयोग करना चाहते हैं और यह विधि उदाहरण के क्षेत्रों को संदर्भित करती है:
class A
constructor: (@msg) ->
thin: -> alert @msg
fat: => alert @msg
x = new A("yo")
x.thin() #alerts "yo"
x.fat() #alerts "yo"
fn = (callback) -> callback()
fn(x.thin) #alerts "undefined"
fn(x.fat) #alerts "yo"
fn(-> x.thin()) #alerts "yo"
जैसा कि आप देखते हैं, यदि आप वसा-तीर का उपयोग नहीं करते हैं, तो आप कॉलबैक के रूप में एक इंस्टेंस विधि के संदर्भ में गुजरने वाली समस्याओं में भाग सकते हैं। इसका कारण यह है कि वसा-तीर वस्तु के उदाहरण को बांधता है this
जबकि पतली-तीर नहीं है, इसलिए पतले-तीर तरीकों को कॉलबैक कहा जाता है, जो ऊपर दिए गए इंस्टेंस के क्षेत्रों को एक्सेस नहीं कर सकता है @msg
या अन्य इंस्टेंस विधियों को कॉल नहीं कर सकता है । अंतिम पंक्ति उन मामलों के लिए एक समाधान है जहां पतले-तीर का उपयोग किया गया है।
this
पतले तीर से बुलाया जाएगा, लेकिन उदाहरण चर भी जो आपको वसा तीर के साथ मिलेगा?
this
एक चर पर सेट है जिसे मैं उपयोग करना चाहता हूं। हालाँकि, मैं एक क्लास विधि का संदर्भ भी लेना चाहता हूं, इसलिए मैं this
कक्षा को भी संदर्भित करना चाहता हूं । मैं केवल एक असाइनमेंट के बीच चयन कर सकता हूं this
, इसलिए दोनों चर का उपयोग करने में सक्षम होने का सबसे अच्छा तरीका क्या है?
अन्य बिंदुओं में उल्लेख नहीं किया गया एक बिंदु जो नोट करना महत्वपूर्ण है कि वसा तीर के साथ बाध्यकारी कार्य जब आवश्यक नहीं है तो अनपेक्षित परिणाम हो सकते हैं जैसे कि इस उदाहरण के साथ एक वर्ग जिसे हम सिर्फ डमीक्लास कहेंगे।
class DummyClass
constructor : () ->
some_function : () ->
return "some_function"
other_function : () =>
return "other_function"
dummy = new DummyClass()
dummy.some_function() == "some_function" # true
dummy.other_function() == "other_function" # true
इस मामले में फ़ंक्शन ठीक वही करते हैं जो कोई उम्मीद कर सकता है और वसा तीर का उपयोग करने के लिए कोई नुकसान नहीं होता है, लेकिन तब क्या होता है जब हम पहले से परिभाषित होने के बाद डमीक्लास प्रोटोटाइप को संशोधित करते हैं (उदाहरण के लिए कुछ चेतावनी बदलते हैं या लॉग का आउटपुट बदलते हैं) :
DummyClass::some_function = ->
return "some_new_function"
DummyClass::other_function = ->
return "other_new_function"
dummy.some_function() == "some_new_function" # true
dummy.other_function() == "other_new_function" # false
dummy.other_function() == "other_function" # true
जैसा कि हम प्रोटोटाइप के हमारे पहले से परिभाषित फ़ंक्शन को ओवरराइड करते हुए देख सकते हैं कि कुछ_फंक्शन ठीक से अधिलेखित होने का कारण बनता है, लेकिन अन्य_फंक्शन उदाहरणों पर समान होते हैं क्योंकि वसा तीर ने वर्ग से अन्य_फंक्शन को सभी उदाहरणों से बंधे होने के कारण उत्पन्न किया है। एक समारोह खोजने के लिए
DummyClass::other_function = =>
return "new_other_new_function"
dummy.other_function() == "new_other_new_function" # false
second_dummy = new DummyClass()
second_dummy.other_function() == "new_other_new_function" # true
यहां तक कि वसा तीर भी काम नहीं करेगा क्योंकि वसा तीर केवल नए उदाहरणों के लिए बाध्य होता है (जो नए कार्यों को प्राप्त करता है जैसा कि कोई अपेक्षा करता है)।
हालाँकि, यह कुछ समस्याओं की ओर जाता है, क्या होगा अगर हमें एक फ़ंक्शन की आवश्यकता होती है (उदाहरण के लिए लॉगिंग फ़ंक्शन को आउटपुट बॉक्स या कुछ पर स्विच करने के मामले में) जो सभी मौजूदा उदाहरणों (इवेंट हैंडलर सहित) पर काम करेगा [जैसे कि हम उपयोग नहीं कर सकते मूल परिभाषा में वसा तीर] लेकिन हमें अभी भी एक घटना हैंडलर में आंतरिक विशेषताओं तक पहुंच की आवश्यकता है [सटीक कारण है कि हमने वसा तीर का उपयोग किया था पतले तीर नहीं]।
वैसे इसे पूरा करने का सबसे सरल तरीका केवल मूल वर्ग परिभाषा में दो कार्य शामिल हैं, एक एक पतली तीर के साथ परिभाषित किया गया है जो उन कार्यों को करता है जिन्हें आप निष्पादित करना चाहते हैं, और दूसरा एक वसा तीर के साथ परिभाषित किया गया है जो पहले कार्य को कॉल करने के अलावा कुछ भी नहीं करता है। उदाहरण के लिए:
class SomeClass
constructor : () ->
@data = 0
_do_something : () ->
return @data
do_something : () =>
@_do_something()
something = new SomeClass()
something.do_something() == 0 # true
event_handler = something.do_something
event_handler() == 0 # true
SomeClass::_do_something = -> return @data + 1
something.do_something() == 1 # true
event_handler() == 1 # true
तो पतले / वसा वाले तीरों का उपयोग कब किया जा सकता है, इसे चार तरीकों से आसान तरीके से अभिव्यक्त किया जा सकता है:
जब दोनों स्थितियां पूरी हो जाएं तो पतले तीर का उपयोग किया जाना चाहिए:
निम्न स्थिति पूरी होने पर, अकेले तीर का उपयोग किया जाना चाहिए:
फैट एरो फंक्शन जिसे सीधे तौर पर एक पतला एरो फंक्शन कहा जाता है, का उपयोग तब किया जाना चाहिए जब निम्न स्थितियां पूरी हों:
पतले तीर फ़ंक्शन जो सीधे एक वसा तीर कहते हैं (प्रदर्शन नहीं किया गया) फ़ंक्शन का उपयोग तब किया जाना चाहिए जब निम्न स्थितियां मिलें:
सभी दृष्टिकोणों में इस मामले में विचार किया जाना चाहिए जहां प्रोटोटाइप कार्यों को बदला जा सकता है या नहीं, विशिष्ट उदाहरणों के लिए व्यवहार सही तरीके से व्यवहार करेगा उदाहरण के लिए हालांकि एक फ़ंक्शन को एक वसा तीर के साथ परिभाषित किया गया है, इसका व्यवहार उदाहरण के अनुरूप नहीं हो सकता है अगर यह कॉल करता है एक तरीका जिसे प्रोटोटाइप के भीतर बदल दिया जाता है
आमतौर पर, ->
ठीक है।
class Foo
@static: -> this
instance: -> this
alert Foo.static() == Foo # true
obj = new Foo()
alert obj.instance() == obj # true
ध्यान दें कि स्थैतिक विधि किस प्रकार क्लास ऑब्जेक्ट को this
लौटाती है और उदाहरण के लिए इंस्टेंस ऑब्जेक्ट लौटाता है this
।
क्या हो रहा है कि मंगलाचरण वाक्यविन्यास मूल्य प्रदान कर रहा है this
। इस कोड में:
foo.bar()
foo
bar()
डिफ़ॉल्ट रूप से फ़ंक्शन का संदर्भ होगा । तो यह सिर्फ काम करता है कि आप कैसे चाहते हैं। जब आप इन फ़ंक्शन को किसी अन्य तरीके से कॉल करते हैं, तो आपको वसा तीर की आवश्यकता होती है जो कि आह्वान के लिए डॉट सिंटैक्स का उपयोग नहीं करता है।
# Pass in a function reference to be called later
# Then later, its called without the dot syntax, causing `this` to be lost
setTimeout foo.bar, 1000
# Breaking off a function reference will lose it's `this` too.
fn = foo.bar
fn()
उन दोनों मामलों में, उस फ़ंक्शन को घोषित करने के लिए वसा तीर का उपयोग करने से उन लोगों को काम करने की अनुमति मिलेगी। लेकिन जब तक आप कुछ अजीब नहीं कर रहे हैं, आपको आमतौर पर करने की आवश्यकता नहीं है।
इसलिए ->
तब तक उपयोग करें जब तक आपको वास्तव में जरूरत न हो =>
और कभी भी =>
डिफ़ॉल्ट रूप से उपयोग न करें ।
x = obj.instance; alert x() == obj # false!
=>
कि किसी वर्ग के स्थिर / उदाहरण के तरीकों की आवश्यकता कब होगी।
// is not a CoffeeScript comment
जबकि # is a CoffeeScript comment
।
setTimeout foo.bar, 1000
"यह गलत कैसे हो रहा है"? setTimeout (-> foo.bar()), 1000
IMHO का उपयोग करने की तुलना में वसा-तीर का उपयोग करना बहुत अच्छा है ।
setTimeout
निश्चित रूप से उस वाक्य रचना के लिए एक मामला है । लेकिन आपकी पहली टिप्पणी कुछ विवादित है और एक वैध उपयोग के मामले को उजागर नहीं करती है, लेकिन केवल यह बताती है कि यह कैसे टूट सकता है। मैं बस कह रहा हूं कि आपको =>
तब तक उपयोग नहीं करना चाहिए जब तक कि आपको एक अच्छे कारण के लिए इसकी आवश्यकता न हो, विशेष रूप से वर्ग उदाहरण के तरीकों पर जहां एक नया फ़ंक्शन बनाने की एक प्रदर्शन लागत होती है जो तात्कालिकता पर बाध्य होने की आवश्यकता होती है।
वसा तीर को समझने के लिए सिर्फ एक उदाहरण
काम नहीं करता है: (@canvas undefined)
class Test
constructor: ->
@canvas = document.createElement 'canvas'
window.addEventListener 'resize', ->
@canvas.width = window.innerWidth
@canvas.height = window.innerHeight
काम करता है: (@canvas परिभाषित)
class Test
constructor: ->
@canvas = document.createElement 'canvas'
window.addEventListener 'resize', =>
@canvas.width = window.innerWidth
@canvas.height = window.innerHeight