कई कंस्ट्रक्टरों के लिए जावास्क्रिप्ट पैटर्न


124

मुझे अपने उदाहरणों के लिए अलग-अलग निर्माणकर्ताओं की आवश्यकता है। उसके लिए एक सामान्य पैटर्न क्या है?


कृपया थोड़ा और विशिष्ट बनें। आप विभिन्न पैरामीटर सेट के साथ निर्माता चाहते हैं?
gblazex

क्या आप जावास्क्रिप्ट में एक से अधिक निर्माणकर्ता हो सकते हैं?
बजे डग Hauf

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

3
ये सभी उत्तर पुराने / आदर्श नहीं हैं। मैं भी जवाब टाइप करने के लिए बहुत आलसी हूं, लेकिन आप फ़ंक्शन और कंस्ट्रक्टर्स के आसपास एक ऑब्जेक्ट पास कर सकते हैं और फिर कुंजियों का उपयोग कर सकते हैं जैसे आप बहस करेंगे, जैसे function ({ oneThing = 7, otherThing = defaultValue } = {}) { }:। अतिरिक्त = {}मैं वहाँ में डाल एक और चाल मैं हाल ही में पता चला है, इस स्थिति में आप उपयोगकर्ता बिल्कुल में कोई वस्तु गुजर और चूक के सभी उपयोग करने की संभावना चाहते हैं।
एंड्रयू

1
अनुसरण करे:: यहाँ इस समस्या को हल करने के लिए कुछ अच्छे तरीके हैं stackoverflow.com/a/32626901/1599699 stackoverflow.com/a/41051984/1599699 stackoverflow.com/a/48287734/1599699 मैं सच के लिए पिछले एक की विशेष रूप से शौकीन हूँ बहु-निर्माता की तरह समर्थन, (कंस्ट्रक्टर्स के रूप में स्थिर कारखाने कार्यों का उपयोग कर return new this();, return new this.otherStaticFactoryFunction();आदि)!
एंड्रयू

जवाबों:


120

जावास्क्रिप्ट में फंक्शन ओवरलोडिंग नहीं है, जिसमें विधियों या कंस्ट्रक्टर शामिल हैं।

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

function foo(a, b) {
    if (b===undefined) // parameter was omitted in call
        b= 'some default value';

    if (typeof(a)==='string')
        this._constructInSomeWay(a, b);
    else if (a instanceof MyType)
        this._constructInSomeOtherWay(a, b);
}

आप argumentsकिसी भी आगे की दलील प्राप्त करने के लिए एक सरणी की तरह भी पहुंच सकते हैं ।

यदि आपको अधिक जटिल तर्क की आवश्यकता है, तो वस्तु खोज के अंदर कुछ या सभी को डालना एक अच्छा विचार हो सकता है:

function bar(argmap) {
    if ('optionalparam' in argmap)
        this._constructInSomeWay(argmap.param, argmap.optionalparam);
    ...
}

bar({param: 1, optionalparam: 2})

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


2
धन्यवाद, यह वास्तव में अच्छा है। मैं कहूंगा कि दूसरा विकल्प उपयोगी है जब आपके पास जटिल तर्क होते हैं, लेकिन सरल-अभी तक कठोर-से-भेद तर्क, जैसे समर्थन MyObj({foo: "foo"})प्लस MyObj({bar: "bar"})। MyObj के दो निर्माता हैं - लेकिन दोनों एक तर्क लेते हैं, जो एक स्ट्रिंग है :-)
एलेक्स डीन

1
क्या आप इस विशेष उदाहरण के लिए उदाहरण कोड में अधिक जोड़ सकते हैं।
डग Hauf

हाय @DougHauf, क्रॉकफोर्ड की पुस्तक 'जावास्क्रिप्ट: द गुड पार्ट्स' में इस 'ऑब्जेक्ट स्पेसिफायर' नाम का एक खंड है, बहुत सारे उदाहरण इसे ऑनलाइन संदर्भित करते हैं।
Moika

29

आप इसे कैसे खोजते हैं?

function Foobar(foobar) {
    this.foobar = foobar;
}

Foobar.prototype = {
    foobar: null
};

Foobar.fromComponents = function(foo, bar) {
    var foobar = foo + bar;
    return new this(foobar);
};

2
यह नया (फोबार) वापस करें; काम नहीं करता है। मैं वापसी पर नया फ़ॉबर (फोब्बर) बदलता हूं; और सब सही है।
isxaker

10
मुझे नहीं मिला। क्या आप उस कोड को जोड़ सकते हैं जहां आप वास्तव में इसका उपयोग कर रहे हैं? क्या आपको हर बार.कॉम से कॉल करना होगा? क्योंकि यह वास्तव में एक निर्माता नहीं है, बल्कि एक सहायक कार्य है। @ बॉबिन का जवाब तब और सटीक लगता है।
होफनरविले

1
@hofnarwillie एक सटीक रचनाकार नहीं है, लेकिन एक स्थिर विधि का उपयोग करके यह काफी समान है अर्थात var foobarObj = Foobar.fromCompords (foo, bar); आप सभी को वैकल्पिक तर्क के साथ एक नई वस्तु बनाने की आवश्यकता है।
नाथन विलियम्स

20

आप क्लास को स्टैटिक विधियों के साथ उपयोग कर सकते हैं जो उस क्लास का एक उदाहरण देता है

    class MyClass {
        constructor(a,b,c,d){
            this.a = a
            this.b = b
            this.c = c
            this.d = d
        }
        static BAndCInstance(b,c){
            return new MyClass(null,b,c)
        }
        static BAndDInstance(b,d){
            return new MyClass(null,b, null,d)
        }
    }

    //new Instance just with a and other is nul this can
    //use for other params that are first in constructor
    const myclass=new MyClass(a)

    //an Instance that has b and c params
    const instanceWithBAndC = MyClass.BAndCInstance(b,c)

    //another example for b and d
    const instanceWithBAndD = MyClass.BAndDInstance(b,d)

इस पैटर्न के साथ आप मल्टी कंस्ट्रक्टर बना सकते हैं


3
यह सबसे अच्छा जवाब है। दूसरों को ऐरेस को पार्स करने और अनावश्यक काम का एक गुच्छा करने का सहारा लेते हैं।
ब्लेन टाउनसेंड

13

बॉबी के जवाब में हाथ से ऐसा करने का मन नहीं था, इसलिए मैंने jQuery के प्लगइन विकल्प पैटर्न को पूरी तरह से बंद कर दिया।

यहाँ निर्माता है:

//default constructor for Preset 'class'
function Preset(params) {
    var properties = $.extend({
        //these are the defaults
        id: null,
        name: null,
        inItems: [],
        outItems: [],
    }, params);

    console.log('Preset instantiated');
    this.id = properties.id;
    this.name = properties.name;
    this.inItems = properties.inItems;
    this.outItems = properties.outItems;
}

यहाँ तात्कालिकता के विभिन्न तरीके हैं:

presetNoParams = new Preset(); 
presetEmptyParams = new Preset({});
presetSomeParams = new Preset({id: 666, inItems:['item_1', 'item_2']});
presetAllParams = new Preset({id: 666, name: 'SOpreset', inItems: ['item_1', 'item_2'], outItems: ['item_3', 'item_4']});

और यहाँ है कि क्या बनाया:

presetNoParams
Preset {id: null, name: null, inItems: Array[0], outItems: Array[0]}

presetEmptyParams
Preset {id: null, name: null, inItems: Array[0], outItems: Array[0]}

presetSomeParams
Preset {id: 666, name: null, inItems: Array[2], outItems: Array[0]}

presetAllParams
Preset {id: 666, name: "SOpreset", inItems: Array[2], outItems: Array[2]}

मैंने नोड.जेएस में भी अब इसी पैटर्न को रोल किया है: npmjs.com/package/extend
याकूब मैके

10

यूसीफॉर्म के जवाब के साथ आगे बढ़ते हुए, आप अपने newकॉल को अपने initतरीके से चेन कर सकते हैं ।

function Foo () {
    this.bar = 'baz';
}

Foo.prototype.init_1 = function (bar) {
    this.bar = bar;
    return this;
};

Foo.prototype.init_2 = function (baz) {
    this.bar = 'something to do with '+baz;
    return this;
};

var a = new Foo().init_1('constructor 1');
var b = new Foo().init_2('constructor 2');

तो मूल रूप से आप जो यहां कर रहे हैं वह ऑब्जेक्ट फू ले रहा है और फिर प्रोटोटाइप कार्यों के साथ init_1 और init_2 मापदंडों को कॉल कर रहा है। क्या आपके init_1 और init_2 में उनके साथ शब्द समारोह है।
डग हफ

वहाँ पहले फू () में} के बाद एक अर्ध-उपनिवेश होना चाहिए।
डग Hauf

धन्यवाद डौग, मैंने बदलाव किया।
laughingbovine

क्या आपको यकीन है कि यह काम करता है? मैं चेन new Foo()और कॉल को initएक साथ करने में सक्षम नहीं था क्योंकि मैं वस्तुओं पर गुणों तक पहुंचने में सक्षम नहीं था। मुझे दौड़ना थाvar a = new Foo(); a.init_1('constructor 1');
मिल्ली स्मिथ

@MillieSmith मैं मानता हूँ कि मैंने अभी थोड़ी देर में JS नहीं लिखा है ... लेकिन मैंने अभी इस कोड को Chrome JS कंसोल में पेस्ट किया है और नए init से चेन काम किया है।
laughingbovine

3

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

http://en.wikipedia.org/w/index.php?title=Factory_method_pattern&oldid=363482142#Javascript


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

1
वह लिंक कहीं नहीं जाता है। उस पेज पर कोई जावास्क्रिप्ट एंकर नहीं है।
रोब

3

उत्तर देना क्योंकि यह प्रश्न पहले Google में वापस आ गया है लेकिन उत्तर अब पुराने हो चुके हैं।

आप ES6 में निर्माता पैरामीटर के रूप में विनाशकारी वस्तुओं का उपयोग कर सकते हैं

यहाँ पैटर्न है:

आपके पास एक से अधिक निर्माता नहीं हो सकते हैं, लेकिन आप जो चाहते हैं उसे करने के लिए विनाशकारी और डिफ़ॉल्ट मानों का उपयोग कर सकते हैं।

export class myClass {

  constructor({ myArray = [1, 2, 3], myString = 'Hello World' }) {

    // ..
  }
}

और आप ऐसा कर सकते हैं यदि आप 'पैरामीटर रहित' कंस्ट्रक्टर का समर्थन करना चाहते हैं।

export class myClass {

      constructor({myArray = [1, 2, 3], myString = 'Hello World'} = {}) {

        // ..
      }
}

2
export default class Order {

    static fromCart(cart) {
        var newOrder = new Order();
        newOrder.items = cart.items;
        newOrder.sum = cart.sum;

        return newOrder;
    }

    static fromOrder(id, order) {
        var newOrder = new Order();
        newOrder.id = id;
        newOrder.items = order.items;
        newOrder.sum = order.sum;

        return newOrder;
    }
}

Useges:

  var newOrder = Order.fromCart(cart)
  var newOrder = Order.fromOrder(id, oldOrder)

0

यह जावास्क्रिप्ट और CSS3 - परीक्षा रेफरी के साथ HTML5 में प्रोग्रामिंग में कई निर्माणकर्ताओं के लिए दिया गया उदाहरण है ।

function Book() {
    //just creates an empty book.
}


function Book(title, length, author) {
    this.title = title;
    this.Length = length;
    this.author = author;
}

Book.prototype = {
    ISBN: "",
    Length: -1,
    genre: "",
    covering: "",
    author: "",
    currentPage: 0,
    title: "",

    flipTo: function FlipToAPage(pNum) {
        this.currentPage = pNum;
    },

    turnPageForward: function turnForward() {
        this.flipTo(this.currentPage++);
    },

    turnPageBackward: function turnBackward() {
        this.flipTo(this.currentPage--);
    }
};

var books = new Array(new Book(), new Book("First Edition", 350, "Random"));

और अपरिवर्तनशीलता? प्रोटोटाइप का उपयोग गुणों को सार्वजनिक करता है, है ना?
गेब्रियल सिमास

6
यह गलत है। आपकी दूसरी रचनाकार परिभाषा पहले एक को ओवरराइड करती है, इसलिए जब आप नई पुस्तक () को बाद में कॉल कर रहे हैं, तो आप दूसरे निर्माणकर्ता को सभी मापदंडों के मानों के साथ अपरिभाषित करने के लिए सेट कर रहे हैं।
ErroneousFatality
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.