मैं जावास्क्रिप्ट में एक विस्तार विधि कैसे लिखूं?


85

मुझे JS में कुछ विस्तार विधियाँ लिखने की आवश्यकता है। मुझे पता है कि C # में यह कैसे करना है। उदाहरण:

public static string SayHi(this Object name)
{
    return "Hi " + name + "!";
}

और फिर द्वारा बुलाया:

string firstName = "Bob";
string hi = firstName.SayHi();

मैं जावास्क्रिप्ट में ऐसा कुछ कैसे करूंगा?

जवाबों:


155

जावास्क्रिप्ट में C # एक्सटेंशन विधियों के लिए सटीक एनालॉग नहीं है। जावास्क्रिप्ट और सी # काफी अलग भाषाएं हैं।

निकटतम समान वस्तु सभी स्ट्रिंग ऑब्जेक्ट के प्रोटोटाइप ऑब्जेक्ट को संशोधित करना है String.prototype:। सामान्य तौर पर, सबसे अच्छा अभ्यास पुस्तकालय कोड में निर्मित वस्तुओं के प्रोटोटाइप को संशोधित करने के लिए नहीं है, जिसका अर्थ है अन्य कोड जिन्हें आप नियंत्रित नहीं करते हैं, के साथ जोड़ा जाना है। (आवेदन में ऐसा करना जहां आप नियंत्रित करते हैं कि आवेदन में अन्य कोड क्या शामिल है, ठीक है।)

यदि आप करते हैं एक अंतर्निहित है, यह सबसे अच्छा है (अब तक) है कि एक बनाने के लिए के प्रोटोटाइप को संशोधित गैर गणनीय का उपयोग करके संपत्ति Object.defineProperty(पहले किसी भी आधुनिक जावास्क्रिप्ट पर्यावरण, ES5 + तो बुनियादी तौर पर, और नहीं IE8¹ या)। अन्य स्ट्रिंग विधियों की गणना, लेखन क्षमता और विन्यास की तुलना करने के लिए, यह इस तरह दिखेगा:

Object.defineProperty(String.prototype, "SayHi", {
    value: function SayHi() {
        return "Hi " + this + "!";
    },
    writable: true,
    configurable: true
});

(के लिए डिफ़ॉल्ट enumerableहै false)

यदि आपको अप्रचलित वातावरण का समर्थन करने की आवश्यकता है, तो String.prototype, विशेष रूप से, आप संभवत: एक अलग संपत्ति बनाने के साथ दूर हो सकते हैं:

// Don't do this if you can use `Object.defineProperty`
String.prototype.SayHi = function SayHi() {
    return "Hi " + this + "!";
};

यह एक अच्छा विचार नहीं है, लेकिन आप इससे दूर हो सकते हैं। के साथ Array.prototypeया कभी नहीं Object.prototype; उन पर अनगिनत गुण पैदा करना एक बुरी बात है। ™

विवरण:

जावास्क्रिप्ट एक प्रोटोटाइप भाषा है। इसका मतलब है कि हर वस्तु एक प्रोटोटाइप ऑब्जेक्ट द्वारा समर्थित है । जावास्क्रिप्ट में, उस प्रोटोटाइप को चार तरीकों में से एक में सौंपा गया है:

  • ऑब्जेक्ट के लिए निर्माता फ़ंक्शन द्वारा (जैसे, अपने प्रोटोटाइप के new Fooसाथ ऑब्जेक्ट बनाता है Foo.prototype)
  • Object.createES5 (2009) में जोड़े गए फ़ंक्शन द्वारा
  • द्वारा __proto__एक्सेसर गुण (ES2015 +, केवल वेब ब्राउज़र पर, कुछ वातावरणों से पहले यह मानकीकरण किया गया था में ही अस्तित्व में) या Object.setPrototypeOf(ES2015 +)
  • किसी आदिम के लिए ऑब्जेक्ट बनाते समय जावास्क्रिप्ट इंजन द्वारा क्योंकि आप इस पर एक विधि कह रहे हैं (इसे कभी-कभी "पदोन्नति" कहा जाता है)

इसलिए आपके उदाहरण में, चूंकि firstNameएक स्ट्रिंग आदिम है, यह एक Stringउदाहरण के लिए प्रचारित हो जाता है जब भी आप इस पर एक विधि कहते हैं, और उस Stringउदाहरण का प्रोटोटाइप है String.prototype। तो एक संपत्ति को String.prototypeउस संदर्भ में जोड़ने से आपका SayHiकार्य उस फ़ंक्शन को सभी Stringउदाहरणों पर उपलब्ध होता है (और प्रभावी रूप से स्ट्रिंग प्राइमेटिव पर, क्योंकि वे पदोन्नत हो जाते हैं)।

उदाहरण:

इस और C # विस्तार विधियों के बीच कुछ प्रमुख अंतर हैं:

  • (जैसा कि डगआर ने एक टिप्पणी में कहा है) सी # के विस्तार के तरीकों को nullसंदर्भों पर बुलाया जा सकता है । यदि आपके पास stringएक्सटेंशन विधि है, तो यह कोड:

    string s = null;
    s.YourExtensionMethod();
    

    काम करता है। यह जावास्क्रिप्ट के साथ सच नहीं है; nullइसका अपना प्रकार है, और nullत्रुटि पर कोई भी संपत्ति संदर्भ । (और यहां तक ​​कि अगर यह नहीं था, तो नल प्रकार के लिए कोई प्रोटोटाइप नहीं है।)

  • (जैसा कि क्रिस ने एक टिप्पणी में बताया है) C # की एक्सटेंशन विधियाँ वैश्विक नहीं हैं। वे केवल तभी सुलभ होते हैं जब उनके द्वारा परिभाषित नाम स्थान एक्सटेंशन विधि का उपयोग करके कोड द्वारा उपयोग किया जाता है। (वे वास्तव में स्टैटिक कॉल के लिए सिंटैक्टिक शुगर हैं, यही वजह है कि वे काम करते हैं null।) यह जावास्क्रिप्ट में सच नहीं है: यदि आप एक बिल्ट-इन के प्रोटोटाइप को बदलते हैं, तो यह परिवर्तन पूरे दायरे में सभी कोड द्वारा देखा जाता है। ऐसा करें कि (एक क्षेत्र वैश्विक वातावरण और उससे जुड़ी आंतरिक वस्तुएं हैं, आदि)। इसलिए यदि आप एक वेब पेज में ऐसा करते हैं, तो उस पेज पर आपके द्वारा लोड किए गए सभी कोड परिवर्तन को देखते हैं। यदि आप Node.js मॉड्यूल में ऐसा करते हैं, तो सभीकोड को उसी दायरे में लोड किया जाता है, क्योंकि मॉड्यूल में परिवर्तन दिखाई देगा। दोनों मामलों में, यही कारण है कि आप लाइब्रेरी कोड में ऐसा नहीं करते हैं। (वेब वर्कर्स और Node.js वर्कर थ्रेड्स अपने दायरे में लोड किए जाते हैं, इसलिए उनके पास एक अलग वैश्विक वातावरण और मुख्य थ्रेड की तुलना में अलग-अलग इंट्रिंसिक्स होते हैं। लेकिन वह दायरे अभी भी किसी भी मॉड्यूल के साथ साझा किया जाता है जिसे वे लोड करते हैं।)


Object.definePropertyDOM IE8 में है , लेकिन यह केवल DOM ऑब्जेक्ट्स पर काम करता है, जावास्क्रिप्ट ऑब्जेक्ट्स पर नहीं। String.prototypeएक जावास्क्रिप्ट ऑब्जेक्ट है।


@DougR: क्षमा करें, मानक टिप्पणी सफाई। जब कोई टिप्पणी पुरानी हो जाती है, तो mods या पावर उपयोगकर्ता इसे हटा सकते हैं (mods इसे सीधे कर सकते हैं, पावर उपयोगकर्ताओं को समीक्षा कतार में टीम बनाना होगा)। मैंने जवाब देने के लिए अपडेट किया है कि आपने इसे चिह्नित किया है। :-)
टीजे क्राउडर

1
@Grundy: धन्यवाद, हाँ, String s = null;भाग के पूरे बिंदु का उपयोग करना था s.YourExtensionMethod()! कैच को सराहें। :-)
टीजे क्राउडर

उस विस्तार विधि को उजागर करने के लिए धन्यवाद अशक्त संस्थाओं के लिए काम करता है।
राम

1
यदि आप उदाहरण के लिए Node.js में ऐसा करते हैं, तो मुझे लगता है कि कार्यक्रम में हर स्ट्रिंग को प्रभावित करेगा (नई संपत्ति जोड़ें) - अन्य मॉड्यूल के साथ? यदि वे दोनों "SayHi" संपत्ति को परिभाषित करते हैं तो क्या दो मॉड्यूल संघर्ष होगा?
क्रिस डब्ल्यूडब्ल्यू

1
@ क्रिस - काफी। :-) आप इसके बजाय क्या कर सकते हैं एक ऐरे सबक्लास ( class MyArray extends Array { singleOrDefault() { ... }}) बनाएं, लेकिन इसका मतलब है कि MyArray.from(originalArray)अगर आपको originalArrayउबाऊ एरे का उपयोग करना है तो आपको इसे इस्तेमाल करने से पहले करना होगा । जावास्क्रिप्ट के लिए LINQ- जैसे पुस्तकालय भी हैं ( यहाँ एक राउंडअप ), जिसमें इसी तरह चीजों को करने से पहले सरणी से एक Linq ऑब्जेक्ट बनाना शामिल है (अच्छी तरह से, LINQ ने जावास्क्रिप्ट किया, मैंने दूसरों का उपयोग नहीं किया है] और इसका उपयोग नहीं किया है सालों में])। (BTW, उत्तर को अद्यतन, thx।)
TJ Crowder

0

वैश्विक वृद्धि का उपयोग करना

declare global {
    interface DOMRect {
        contains(x:number,y:number): boolean;
    }
}
/* Adds contain method to class DOMRect */
DOMRect.prototype.contains = function (x:number, y:number) {                    
    if (x >= this.left && x <= this.right &&
        y >= this.top && y <= this.bottom) {
        return true
    }
    return false
};

यह शुद्ध / वेनिला जावास्क्रिप्ट के साथ काम करता है या क्या यह कुछ है जो मुझे पता लगाना है कि टाइपस्क्रिप्ट का उपयोग कैसे करें? मैं पूछ रहा हूँ चूंकि आप
typecriptlang.org
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.