[Javascript] ES6 वर्ग परिवर्तनीय विकल्प


Answers

बेंजामिन के उत्तर में जोड़ने के लिए - कक्षा चर संभव है, लेकिन आप उन्हें सेट करने के लिए prototype का उपयोग नहीं करेंगे।

एक सच्चे वर्ग चर के लिए आप निम्न की तरह कुछ करना चाहते हैं:

class MyClass {}
MyClass.foo = 'bar';

क्लास विधि के भीतर से वैरिएबल को इस this.constructor.foo (या this.constructor.foo ) के रूप में एक्सेस किया जा सकता है।

ये वर्ग गुण आमतौर पर कक्षा के उदाहरण से सुलभ नहीं होंगे। यानी MyClass.foo 'bar' देता है लेकिन new MyClass().foo undefined

यदि आप किसी उदाहरण से अपने क्लास वैरिएबल तक पहुंच प्राप्त करना चाहते हैं, तो आपको अतिरिक्त रूप से गेटटर को परिभाषित करना होगा:

class MyClass {
    get foo() {
        return this.constructor.foo;
    }
}

MyClass.foo = 'bar';

मैंने केवल ट्रेसेर के साथ इसका परीक्षण किया है, लेकिन मुझे विश्वास है कि यह एक मानक कार्यान्वयन में भी काम करेगा।

जावास्क्रिप्ट में वास्तव में कक्षाएं नहीं हैं । ईएस 6 के साथ भी हम एक वर्ग-आधारित भाषा की बजाय किसी ऑब्जेक्ट- या प्रोटोटाइप-आधारित भाषा को देख रहे हैं। किसी भी function X () {} , X.prototype.constructor X को वापस इंगित करता है। जब X पर new ऑपरेटर उपयोग किया जाता है, तो एक नई वस्तु X.prototype विरासत में बनाई X.prototype । उस नई वस्तु ( constructor समेत) में किसी भी अपरिभाषित गुणों को वहां से देखा जाता है। हम इस बारे में वस्तु और वर्ग गुणों के निर्माण के रूप में सोच सकते हैं।

Question

वर्तमान में ईएस 5 में हम में से कई कक्षाओं और वर्ग चर बनाने के लिए ढांचे में निम्नलिखित पैटर्न का उपयोग कर रहे हैं, जो आरामदायक है:

// ES 5
FrameWork.Class({

    variable: 'string',
    variable2: true,

    init: function(){

    },

    addItem: function(){

    }

});

ईएस 6 में आप कक्षाएं मूल रूप से बना सकते हैं, लेकिन वर्ग चर के लिए कोई विकल्प नहीं है:

// ES6
class MyClass {
    const MY_CONST = 'string'; // <-- this is not possible in ES6
    constructor(){
        this.MY_CONST;
    }
}

अफसोस की बात है, उपर्युक्त काम नहीं करेगा, क्योंकि कक्षाओं में केवल विधियां हो सकती हैं।

मैं समझता हूं कि मैं यह कर सकता this.myVar = true मेरा this.myVar = true constructor में this.myVar = true है ... लेकिन मैं अपने कन्स्ट्रक्टर को 'जंक' नहीं करना चाहता, खासकर जब मेरे पास एक बड़ी कक्षा के लिए 20-30 + पैरा हैं।

मैं इस मुद्दे को संभालने के कई तरीकों के बारे में सोच रहा था, लेकिन अभी तक कोई अच्छा नहीं मिला है। (उदाहरण के लिए: ClassConfig हैंडलर बनाएं, और एक parameter ऑब्जेक्ट पास करें, जिसे कक्षा से अलग से घोषित किया जाता है। फिर हैंडलर कक्षा से जुड़ा होगा। मैं WeakMaps को किसी भी तरह एकीकृत करने के बारे में सोच रहा था।)

इस स्थिति को संभालने के लिए आपको किस तरह के विचारों को रखना होगा?




चूंकि आपकी समस्या ज्यादातर स्टाइलिस्ट है (घोषणाओं के समूह के साथ कन्स्ट्रक्टर को भरना नहीं चाहते हैं) इसे स्टाइलिस्टिक रूप से भी हल किया जा सकता है।

जिस तरह से मैं इसे देखता हूं, कई वर्ग आधारित भाषाओं में रचनाकार वर्ग नाम के नाम पर एक फ़ंक्शन होता है। स्टाइलिस्टिक रूप से हम इसका उपयोग कर सकते हैं कि ईएस 6 कक्षा बनाने के लिए जो स्टाइलिस्टिक रूप से अभी भी समझ में आता है लेकिन हम सभी संपत्ति घोषणाओं के साथ कन्स्ट्रक्टर में होने वाली सामान्य कार्रवाइयों को समूहित नहीं करते हैं। हम वास्तविक जेएस कन्स्ट्रक्टर का उपयोग "घोषणा क्षेत्र" के रूप में करते हैं, फिर एक वर्ग नामक फ़ंक्शन बनाएं जिसे हम अन्यथा "अन्य कन्स्ट्रक्टर सामग्री" क्षेत्र के रूप में देखते हैं, इसे सच्चे कन्स्ट्रक्टर के अंत में बुलाते हैं।

"use strict";

class MyClass
{
    // only declare your properties and then call this.ClassName(); from here
    constructor(){
        this.prop1 = 'blah 1';
        this.prop2 = 'blah 2';
        this.prop3 = 'blah 3';
        this.MyClass();
    }

    // all sorts of other "constructor" stuff, no longer jumbled with declarations
    MyClass() {
        doWhatever();
    }
}

दोनों को नए उदाहरण के रूप में बुलाया जाएगा।

सॉर्टा को 2 कन्स्ट्रक्टर होने की तरह, जहां आप घोषणाओं और अन्य कन्स्ट्रक्टर कार्यों को अलग करते हैं जिन्हें आप लेना चाहते हैं, और स्टाइलिस्टिक रूप से समझना मुश्किल नहीं है कि यह भी हो रहा है।

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

नोट : मैं बहुत उद्देश्य से "प्रारंभिक" (जैसे एक init() या initialize() विधि के सामान्य बेवकूफ विचारों का उपयोग नहीं करता) क्योंकि अक्सर उन्हें अलग-अलग उपयोग किया जाता है। निर्माण और प्रारंभ करने के विचार के बीच एक तरह का अनुमानित अंतर है। रचनाकारों के साथ काम करना लोगों को पता है कि उन्हें तात्कालिकता के हिस्से के रूप में स्वचालित रूप से बुलाया जाता है। एक init विधि को देखते हुए कई लोग एक दूसरे नज़र के बिना मानने जा रहे हैं कि उन्हें var mc = MyClass(); mc.init(); के रूप में कुछ करने की आवश्यकता है var mc = MyClass(); mc.init(); var mc = MyClass(); mc.init(); , क्योंकि इस तरह आप आमतौर पर प्रारंभ करते हैं। मैं कक्षा के उपयोगकर्ता के लिए प्रारंभिक प्रक्रिया जोड़ने की कोशिश नहीं कर रहा हूं, मैं कक्षा की निर्माण प्रक्रिया में जोड़ने की कोशिश कर रहा हूं।

जबकि कुछ लोग एक पल के लिए दो बार ले सकते हैं, यह वास्तव में बिंदु का थोड़ा सा है: यह उनसे संवाद करता है कि इरादा निर्माण का हिस्सा है, भले ही इससे उन्हें थोड़ा सा लेना पड़े और "यह नहीं है ईएस 6 कन्स्ट्रक्टर कैसे काम करते हैं "और एक दूसरे को वास्तविक कन्स्ट्रक्टर को देखने के लिए लेते हैं" ओह, वे इसे नीचे कहते हैं, मैं देखता हूं ", यह उस इरादे को संचारित करने से कहीं बेहतर नहीं है (या गलत तरीके से संचार कर रहा है) और शायद बहुत कुछ लोग इसका इस्तेमाल गलत और जंक से शुरू करने की कोशिश कर रहे हैं। मेरे द्वारा सुझाए गए पैटर्न के लिए यह बहुत जानबूझकर है।

उन लोगों के लिए जो उस पैटर्न का पालन नहीं करना चाहते हैं, सटीक विपरीत भी काम कर सकता है। शुरुआत में किसी अन्य समारोह में घोषणाओं को फार्म करें। शायद इसे "गुण" या "सार्वजनिक प्रॉपर्टीज" या कुछ नाम दें। फिर बाकी सामग्री को सामान्य कन्स्ट्रक्टर में रखें।

"use strict";

class MyClass
{
    properties() {
        this.prop1 = 'blah 1';
        this.prop2 = 'blah 2';
        this.prop3 = 'blah 3';
    }

    constructor() {
        this.properties();
        doWhatever();
    }
}

ध्यान दें कि यह दूसरी विधि क्लीनर को देख सकती है लेकिन इसमें एक अंतर्निहित समस्या भी है जहां properties को ओवरराइड किया जाता है क्योंकि इस विधि का उपयोग करके एक वर्ग दूसरे को फैलाता है। इससे बचने के लिए आपको properties लिए और अधिक अद्वितीय नाम देना होगा। मेरी पहली विधि में यह समस्या नहीं है क्योंकि कन्स्ट्रक्टर का नकली आधा वर्ग के नाम पर विशिष्ट रूप से नामित है।




जिस तरह से मैंने इसे हल किया, जो एक और विकल्प है (यदि आपके पास jQuery उपलब्ध है), पुराने स्कूल ऑब्जेक्ट में फ़ील्ड को परिभाषित करना था और फिर उस ऑब्जेक्ट के साथ कक्षा का विस्तार करना था। मैं कन्स्ट्रक्टर को असाइनमेंट के साथ मिर्च नहीं करना चाहता था, यह एक साफ समाधान प्रतीत होता था।

function MyClassFields(){
    this.createdAt = new Date();
}

MyClassFields.prototype = {
    id : '',
    type : '',
    title : '',
    createdAt : null,
};

class MyClass {
    constructor() {
        $.extend(this,new MyClassFields());
    }
};

- बर्गी की टिप्पणी के बाद अद्यतन करें।

कोई JQuery संस्करण नहीं:

class SavedSearch  {
    constructor() {
        Object.assign(this,{
            id : '',
            type : '',
            title : '',
            createdAt: new Date(),
        });

    }
}

आप अभी भी 'वसा' कन्स्ट्रक्टर के साथ खत्म हो जाते हैं, लेकिन कम से कम यह सब एक वर्ग में और एक हिट में असाइन किया गया है।

संपादित करें # 2: अब मैं पूर्ण सर्कल चला गया हूं और अब कन्स्ट्रक्टर में मान निर्दिष्ट कर रहा हूं, उदाहरण के लिए

class SavedSearch  {
    constructor() {
        this.id = '';
        this.type = '';
        this.title = '';
        this.createdAt = new Date();
    }
}

क्यूं कर? वास्तव में, उपरोक्त प्लस कुछ JSdoc टिप्पणियों का उपयोग करके, PHPStorm गुणों पर कोड पूर्ण करने में सक्षम था। एक हिट में सभी वर्रों को असाइन करना अच्छा था, लेकिन गुणों को पूरा करने में असमर्थता, इमो, (लगभग निश्चित रूप से कमजोर) प्रदर्शन लाभ के लायक नहीं है।




Babel ESNext में कक्षा चर का समर्थन करता है, इस example जांचें:

class Foo {
  bar = 2
  static iha = 'string'
}

const foo = new Foo();
console.log(foo.bar, foo.iha, Foo.bar, Foo.iha);
// 2, undefined, undefined, 'string'



यह स्थैतिक का थोड़ा हैकिश कॉम्बो है और मेरे लिए काम करता है

class ConstantThingy{
        static get NO_REENTER__INIT() {
            if(ConstantThingy._NO_REENTER__INIT== null){
                ConstantThingy._NO_REENTER__INIT = new ConstantThingy(false,true);
            }
            return ConstantThingy._NO_REENTER__INIT;
        }
}

कहीं और इस्तेमाल किया

var conf = ConstantThingy.NO_REENTER__INIT;
if(conf.init)...



आप es6 कक्षा व्यवहार की नकल कर सकते हैं ... और अपने वर्ग चर का उपयोग करें :)

माँ देखो ... कोई कक्षा नहीं!

// Helper
const $constructor = Symbol();
const $extends = (parent, child) =>
  Object.assign(Object.create(parent), child);
const $new = (object, ...args) => {
  let instance = Object.create(object);
  instance[$constructor].call(instance, ...args);
  return instance;
}
const $super = (parent, context, ...args) => {
  parent[$constructor].call(context, ...args)
}
// class
var Foo = {
  classVariable: true,

  // constructor
  [$constructor](who){
    this.me = who;
    this.species = 'fufel';
  },

  // methods
  identify(){
    return 'I am ' + this.me;
  }
}

// class extends Foo
var Bar = $extends(Foo, {

  // constructor
  [$constructor](who){
    $super(Foo, this, who);
    this.subtype = 'barashek';
  },

  // methods
  speak(){
    console.log('Hello, ' + this.identify());
  },
  bark(num){
    console.log('Woof');
  }
});

var a1 = $new(Foo, 'a1');
var b1 = $new(Bar, 'b1');
console.log(a1, b1);
console.log('b1.classVariable', b1.classVariable);

मैंने इसे GitHub पर रखा




Links