ES6 वर्ग उदाहरण का वर्ग नाम प्राप्त करें


157

ES6 वर्ग उदाहरण से वर्ग नाम प्राप्त करने के लिए कोई 'सामंजस्यपूर्ण' तरीके हैं? के अलावा अन्य

someClassInstance.constructor.name

वर्तमान में मैं Traceur कार्यान्वयन पर भरोसा कर रहा हूं। और ऐसा लगता है कि बाबेल के पास एक पॉलीफिल है Function.nameजबकि ट्रेसुर नहीं है।

यह सब योग करने के लिए: ES6 / ES2015 / सद्भाव में कोई अन्य तरीका नहीं था, और ES.Next में कुछ भी अपेक्षित एटीएम नहीं है।

यह बिना सर्वर-साइड अनुप्रयोगों के लिए उपयोगी पैटर्न प्रदान कर सकता है, लेकिन ब्राउज़र / डेस्कटॉप / मोबाइल के लिए उपयोग किए जाने वाले अनुप्रयोगों में अवांछित है।

बाबेल पॉलीफिल का उपयोग करताcore-js है Function.name, इसे मैन्युअल रूप से ट्रेसेर और टाइपस्क्रिप्ट अनुप्रयोगों के लिए उपयुक्त रूप में लोड किया जाना चाहिए।


2
मैं एक ही मुद्दे पर आया था; ट्रेसुर के लिए एकमात्र समाधान वास्तविक वर्ग कोड को नाम निकालने के लिए पार्स करना था, जो मुझे नहीं लगता कि सामंजस्यपूर्ण रूप से योग्य है। मैंने सिर्फ गोली निगल ली और बाबेल में चला गया; ट्रेसुर का विकास कुछ हद तक स्थिर लगता है, और कई ईएस 6 सुविधाओं को खराब तरीके से लागू किया जाता है। जैसा कि आपने उल्लेख किया है, instance.constructor.nameऔर class.nameउचित ईएस 6 में वर्ग का नाम वापस करें।
एंड्रयू ओड्री

एक ही रास्ता लगता है।
फ्रेडरिक क्राउटवल्ड

क्या यह ES6 मानक में है?
ड्रुड्रू

12
यह उल्लेख के लायक है कि someClassInstance.constructor.nameअगर आप अपने कोड को कुरूप करते हैं, तो वह खराब हो जाएगा।
जेम्सबी

stackoverflow.com/questions/2648293/… इस पर ध्यान देना चाहिए, w / काम करना चाहिए .constructor
फ्लोरी सेप

जवाबों:


206

someClassInstance.constructor.nameऐसा करने का सही तरीका है। ट्रांसपॉयलर इसका समर्थन नहीं कर सकते हैं, लेकिन यह विनिर्देशन के अनुसार मानक तरीका है। ( nameClassDeclaration प्रोडक्शंस के माध्यम से घोषित कार्यों की संपत्ति 14.5.15 , चरण 6 में सेट है। )


2
यही मैं डरता था। क्या आप इसके लिए किसी उचित पॉलीफ़िल से अवगत हैं? मैंने यह पता लगाने की कोशिश की है कि बैबिल ऐसा कैसे करता है लेकिन उसे बहुत कम सफलता मिली थी।
एस्टुस फ्लास्क

मुझे वास्तव में नहीं पता है कि भाषा विशेषता (कक्षाओं) के लिए पॉलीफ़िल से आपका क्या मतलब है।
डोमनिक

मेरा मतलब है कि constructor.name के लिए पॉलीफ़िल। ऐसा लगता है कि बैबिल ने इसे लागू किया है, लेकिन मैं यह समझने में सफल नहीं हुआ कि यह कैसे होता है।
एस्टुस फ्लास्क

2
@estus someClassInstance.constructorएक फंक्शन है। सभी कार्यों में एक nameसंपत्ति है जो इसके नाम पर सेट है। यही कारण है कि कोलाहल कुछ भी करने की जरूरत नहीं है। कृपया डेवलपर.
mozilla.org/en-US/docs/Web/JavaScript/Reference/…

2
@Esteban ऐसा लगता है कि बैबल लगातार कोर-जेएस पॉलीफिल्स (फंक्शन के लिए एक पॉलीफ़िल सहित) को बढ़ावा देता है। यही कारण है कि कुछ बैबल बिल्ड सभी ब्राउज़र में बॉक्स से बाहर काम कर सकते हैं।
एस्टुस फ्लास्क

53

जैसा कि @ डॉमिक कहते हैं, उपयोग करें someClassInstance.constructor.name। @Esteban ने टिप्पणियों में उल्लेख किया है कि

someClassInstance.constructorएक समारोह है। सभी कार्यों में एक nameसंपत्ति है ...

इस प्रकार, वर्ग नाम को सांख्यिकीय रूप से एक्सेस करने के लिए, निम्नलिखित करें (यह मेरे बबल संस्करण BTW के साथ काम करता है। @Domenic पर टिप्पणियों के अनुसार आपका माइलेज भिन्न हो सकता है)।

class SomeClass {
  constructor() {}
}

var someClassInstance = new SomeClass();
someClassInstance.constructor.name;      // === 'SomeClass'
SomeClass.name                           // === 'SomeClass'

अपडेट करें

बैबल ठीक था, लेकिन बदसूरत / मिनिफिकेशन ने मुझे परेशान किया। मैं एक खेल बना रहा हूं, और पूलित स्प्राइट संसाधनों का एक हैश बना रहा हूं (जहां कुंजी फ़ंक्शन का नाम है)। लघुकरण के बाद, प्रत्येक फ़ंक्शन / वर्ग का नाम दिया गया था t। यह हैश को मारता है। मैं Gulpइस परियोजना में उपयोग कर रहा हूं , और मैंने जो gulp-uglify डॉक्स पढ़े उसके बाद इस स्थानीय चर / फ़ंक्शन नाम को होने से रोकने के लिए एक पैरामीटर है। तो, मेरे gulpfile में मैं बदल गया

.pipe($.uglify()) सेवा .pipe($.uglify({ mangle: false }))

यहां प्रदर्शन बनाम पठनीयता का व्यापार बंद है। नामों को प्रबंधित न करने से (थोड़ी) बड़ी बिल्ड फ़ाइल (अधिक नेटवर्क संसाधन) और संभावित धीमी कोड निष्पादन (आवश्यक उद्धरण - बीएस हो सकता है) हो जाएगा। दूसरी ओर, अगर मैंने इसे वही रखा तो मुझे getClassNameप्रत्येक ES6 वर्ग पर मैन्युअल रूप से परिभाषित करना होगा - एक स्थिर और उदाहरण के स्तर पर। जी नहीं, धन्यवाद!

अपडेट करें

टिप्पणियों में चर्चा के बाद, ऐसा लगता है कि .nameउन कार्यों को परिभाषित करने के पक्ष में सम्मेलन को टालना एक अच्छा प्रतिमान है। यह केवल कोड की कुछ पंक्तियां लेता है, और आपके कोड की पूर्णता और सामान्यता (यदि किसी पुस्तकालय में उपयोग की जाती है) की अनुमति देगा। इसलिए मुझे लगता है कि मैं अपना दिमाग बदल देता हूं और मैन्युअल रूप से getClassNameअपनी कक्षाओं में परिभाषित करूंगा। शुक्रिया @estus! । गेट्टर / सेटर्स आमतौर पर डायरेक्ट वैरिएबल एक्सेस वैसे भी, खासकर क्लाइंट आधारित एप्लिकेशन की तुलना में एक अच्छा विचार है।

class SomeClass {
  constructor() {}
  static getClassName(){ return 'SomeClass'; }
  getClassName(){ return SomeClass.getClassName(); }
}
var someClassInstance = new SomeClass();
someClassInstance.constructor.getClassName();      // === 'SomeClass' (static fn)
someClassInstance.getClassName();                  // === 'SomeClass' (instance fn)
SomeClass.getClassName()                           // === 'SomeClass' (static fn)

3
पूरी तरह से मैनबलिंग को अक्षम करना बहुत अच्छा विचार नहीं है क्योंकि मैनिंजिंग में बहुत अधिक योगदान होता है। क्लाइंट-साइड कोड में पहली जगह में विषय का उपयोग करना बहुत अच्छा विचार नहीं है, लेकिन वर्गों को reservedUglify विकल्प (वर्ग की सूची regexp या जो भी प्राप्त किया जा सकता है) के साथ प्रबंधित करने से बचाया जा सकता है ।
एस्टुस फ्लास्क

सच सच। एक बड़ा फ़ाइल आकार होने का व्यापार बंद है। इस तरह दिखता है कि आप केवल चुनिंदा वस्तुओं के लिए मैनबलिंग को रोकने के लिए RegEx का उपयोग कैसे कर सकते हैं । आपका क्या मतलब है "क्लाइंट-साइड कोड में विषय का उपयोग करने के लिए यह बहुत अच्छा विचार नहीं है"? क्या यह कुछ परिदृश्यों में सुरक्षा जोखिम पेश करेगा?
जेम्स एल।

1
नहीं, बस जो पहले ही कहा गया था। क्लाइंट-साइड जेएस का खनन किया जाना सामान्य है, इसलिए यह पहले से ही ज्ञात है कि यह पैटर्न ऐप के लिए समस्याएं पैदा करेगा। नीट nameपैटर्न के बजाय क्लास स्ट्रिंग आइडेंटिफायर के लिए कोड की अतिरिक्त एक लाइन सिर्फ एक जीत हो सकती है। एक ही चीज़ को नोड पर लागू किया जा सकता है, लेकिन कुछ हद तक (उदाहरण के लिए इलेक्ट्रो ऐप को बाधित)। अंगूठे के एक नियम के रूप में, मैं nameसर्वर कोड पर भरोसा करूंगा , लेकिन ब्राउज़र कोड में नहीं और सामान्य पुस्तकालय में नहीं।
एस्टुस फ्लास्क

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

1
हाँ, मैंने शुरू में nameDRYer कोड का उपयोग उस संस्था के नाम को निकालने के लिए किया है जो वर्ग के नाम से वर्ग (सेवा, प्लगइन, आदि) का उपयोग करता है, लेकिन अंत में मैंने पाया है कि यह स्पष्ट रूप से स्थैतिक प्रोप ( id, _name) के साथ नकल कर रहा है सबसे ठोस दृष्टिकोण है एक अच्छा विकल्प वर्ग के नाम की परवाह नहीं करना है, एक वर्ग के लिए एक पहचानकर्ता के रूप में स्वयं एक वर्ग (फ़ंक्शन ऑब्जेक्ट) का उपयोग करें जो इस वर्ग के लिए मैप किया गया है और importजहां भी जरूरत है (एक दृष्टिकोण जो कि कोणीय 2 डीआई द्वारा उपयोग किया गया था)।
एस्टुस फ्लास्क

8

क्लास से सीधे क्लास का नाम लेना

पिछले उत्तर में समझाया गया है कि यह someClassInstance.constructor.nameठीक काम करता है, लेकिन अगर आपको प्रोग्राम को कक्षा के नाम को एक स्ट्रिंग में बदलने की आवश्यकता है और इसके लिए केवल एक उदाहरण नहीं बनाना चाहते हैं, तो याद रखें:

typeof YourClass === "function"

और, चूंकि प्रत्येक फ़ंक्शन के पास एक nameसंपत्ति होती है, इसलिए आपके वर्ग नाम के साथ एक स्ट्रिंग प्राप्त करने का एक और अच्छा तरीका है:

YourClass.name

क्या इस प्रकार का एक अच्छा उदाहरण है क्यों यह उपयोगी है।

वेब घटक लोड हो रहे हैं

के रूप में MDN दस्तावेजीकरण हमें सिखाता है, यह कैसे आप एक वेब घटक लोड है:

customElements.define("your-component", YourComponent);

YourComponentएक वर्ग कहां से कहां तक फैल रहा है HTMLElement। चूँकि घटक टैग के बाद अपने घटक की कक्षा का नाम रखने के लिए अच्छा अभ्यास माना जाता है, इसलिए सहायक फ़ंक्शन लिखना अच्छा होगा जिसे आपके सभी घटक स्वयं को पंजीकृत करने के लिए उपयोग कर सकते हैं। तो यहाँ वह कार्य है:

function registerComponent(componentClass) {
    const componentName = upperCamelCaseToSnakeCase(componentClass.name);
    customElements.define(componentName, componentClass);
}

तो आपको बस इतना करना है:

registerComponent(YourComponent);

यह अच्छा है क्योंकि यह घटक टैग को लिखने की तुलना में कम त्रुटि वाला है। इसे लपेटने के लिए, यह upperCamelCaseToSnakeCase()कार्य है:

// converts `YourString` into `your-string`
function upperCamelCaseToSnakeCase(value) {
    return value
        // first char to lower case
        .replace(/^([A-Z])/, $1 => $1.toLowerCase())
        // following upper chars get preceded with a dash
        .replace(/([A-Z])/g, $1 => "-" + $1.toLowerCase());
}

धन्यवाद। इसका उदाहरण क्लाइंट-साइड है। जैसा कि पहले ही उल्लेख किया गया था, ब्राउज़रों में फ़ंक्शन नाम का उपयोग करने में कुछ समस्याएं हैं। लगभग हर ब्राउज़र कोड के खनन होने की उम्मीद है, लेकिन यह उस कोड को बर्बाद कर देगा जो फ़ंक्शन नाम पर निर्भर करता है।
एस्टुस फ्लास्क

हां, आप बिलकुल सही हैं। काम करने के लिए इस दृष्टिकोण के लिए वर्ग नामों को न छूने के लिए मिनिफ़र को कॉन्फ़िगर करना होगा।
लुसियो पाइवा

1

बैबेल ट्रांसप्लिकेशन के लिए (minification से पहले)

यदि आप बाबेल का उपयोग कर रहे हैं @babel/preset-env, तो वर्गों की परिभाषाओं को कार्यों में परिवर्तित किए बिना रखना संभव है (जो constructorसंपत्ति को हटाता है )

आप इस कॉन्फ़िगरेशन में अपने साथ कुछ पुराने ब्राउज़र संगतता छोड़ सकते हैं babel.config / babelrc:

{
  "presets": [
    ["@babel/preset-env", {"targets": {"browsers": ["> 2%"]}}]
  ]
}

के बारे में अधिक जानकारी targets: https://babeljs.io/docs/en/babel-preset-env#targets

बेबल मिनिफिकेशन के लिए (ट्रांसप्लिकेशन के बाद)

ऐसा लग रहा है कि अभी कोई आसान समाधान नहीं है ... हमें युद्धाभ्यास के बहिष्कार को देखने की जरूरत है।


क्या आप आगे बता सकते हैं कि इसे किस तरह से मिनिमाइज़ेशन में मदद करना चाहिए? किसी भी लक्ष्य के साथ class Foo {}कुछ करने के लिए छोटा किया जाएगा class a{}Fooमिनिफाईड सोर्स कोड में कोई शब्द नहीं होगा ।
एस्टस फ्लास्क

ईमानदारी से, मैं इस विन्यास का उपयोग करने में मदद करने वाले दस्तावेज़ों और तथ्य से अधिक नहीं खोली ... मैं ईसीएसवाई को बेबिल ट्रांसप्लेड प्रोजेक्ट में उपयोग कर रहा हूं और इसे वैध वर्ग नाम प्राप्त करने के लिए इस पैराम की आवश्यकता है: github.com/MozillaReality-ecsy/issues/ 119
यदि

समझा। यह आपके द्वारा निपटाए गए कोड के लिए बहुत विशिष्ट है। ईएस नामों को ईएस मॉड्यूल और ईएस 6 के लिए संरक्षित किया जा सकता है क्योंकि export class Foo{}आगे कुशलता से इसे कुरूप नहीं किया जा सकता है, लेकिन यह अन्य स्थानों में भिन्न हो सकता है, हम यह नहीं जान सकते हैं कि एक अच्छा विचार के बिना वास्तव में निर्माण समय पर विशिष्ट कोड टुकड़ों के साथ क्या होता है। किसी भी तरह से, यह 2015 के बाद से नहीं बदला है। यह हमेशा कुछ संकलन कॉन्फ़िगरेशन और कोड के लिए संभव था। और मैं कहूंगा कि यह संभावना अभी भी ऐप लॉजिक के लिए वर्ग नामों का उपयोग करने के लिए बहुत नाजुक है। स्रोत कोड में एक आकस्मिक परिवर्तन के बाद आप जिस क्लास के नाम पर भरोसा करते हैं वह कचरा बन सकता है
एस्टस फ्लास्क

1
ठीक है मैंने पाया कि कोड को देखकर क्या है। मेरा समाधान कार्यों के लिए कक्षाओं के हस्तांतरण को ठीक करता है। तो यह मिनिमाइज़ेशन से पहले मदद करता है। लेकिन नाबालिग समस्या के साथ नहीं। मुझे खुदाई जारी रखनी है क्योंकि, मुझे समझ में नहीं आ रहा है कि कैसे मेरे सभी कोड constructor.nameअभी भी
मिनीफाइड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.