Birden çok kurucu için JavaScript modeli


124

Örneklerim için farklı kuruculara ihtiyacım var. Bunun ortak bir modeli nedir?


biraz daha spesifik olun lütfen. farklı parametre setlerine sahip kurucular mı istiyorsunuz?
gblazex

Javascript'te birden fazla kurucunuz olabilir mi?
Doug Hauf

Evet ve hayır @DougHauf. Evet, çünkü bobince tarafından sağlanan cevap, eşdeğer davranış sergilemenin bir yolunu sağlıyor. Hayır, çünkü birden çok farklı yapıcı işlevi istiyorsanız (her biri aynı prototip nesnesini paylaşıyor) prototip nesnesinin yapıcı özelliği nasıl ayarlanır (yapıcı özelliği yalnızca bir yapıcı işlevine işaret edebileceğinden).
Moika

3
Tüm bu cevaplar eski / ideal değil. Bir cevap daktilo kadar tembelim, ancak işlevleri ve tesis sahiplerine etrafında bir nesne geçmek ve sonra sadece olurdu argümanlar, örneğin gibi tuşları kullanabilirsiniz: function ({ oneThing = 7, otherThing = defaultValue } = {}) { }. = {}Oraya koyduğum fazladan , son zamanlarda öğrendiğim başka bir numara, kullanıcının hiçbir nesneyi içeri geçirme ve tüm varsayılanları kullanma olasılığını istemeniz durumunda.
Andrew

1
Takip: İşte bu sorunu çözmenin bazı iyi yolları: stackoverflow.com/a/32626901/1599699 stackoverflow.com/a/41051984/1599699 stackoverflow.com/a/48287734/1599699 Özellikle sonuncusuna gerçekten düşkünüm destek benzeri çoklu-yapıcı, (yapıcıları gibi statik fabrika işlevlerini kullanarak return new this();, return new this.otherStaticFactoryFunction();vb)!
Andrew

Yanıtlar:


120

JavaScript, yöntemler veya yapıcılar dahil olmak üzere işlev aşırı yüklemesine sahip değildir.

Bir işlevin kendisine ilettiğiniz parametrelerin sayısına ve türüne bağlı olarak farklı davranmasını istiyorsanız, bunları manuel olarak koklamanız gerekir. JavaScript, beyan edilen bağımsız değişken sayısından daha fazla veya daha azına sahip bir işlevi mutlu bir şekilde çağıracaktır.

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);
}

Ayrıca, argumentsaktarılan diğer argümanları almak için dizi benzeri olarak da erişebilirsiniz .

Daha karmaşık argümanlara ihtiyacınız varsa, bunların bir kısmını veya tamamını bir nesne aramasına koymak iyi bir fikir olabilir:

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

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

Python, varsayılan ve adlandırılmış bağımsız değişkenlerin, çoğu kullanım durumunu, işlev aşırı yüklemesinden daha pratik ve zarif bir şekilde kapsayacak şekilde nasıl kullanılabileceğini gösterir. JavaScript, o kadar değil.


2
Teşekkürler, bu gerçekten çok güzel. İkinci seçeneğin sadece karmaşık argümanlarınız olduğunda değil, aynı zamanda basit ama ayırt etmesi zor argümanlarınız olduğunda da yararlı olduğunu söyleyebilirim, örneğin destekleyici MyObj({foo: "foo"})artı MyObj({bar: "bar"}). MyObj'un iki kurucusu vardır - ancak her ikisi de bir dizge olan bir argüman alır :-)
Alex Dean

1
Bu özel örnek için örnek koda daha fazlasını ekleyebilir misiniz?
Doug Hauf

Merhaba @DougHauf, Crockford'un 'JavaScript: The Good Parts' adlı kitabında bu 'Object Specifiers' adlı bir bölüm var, birçok örnek çevrimiçi olarak buna atıfta bulunuyor.
Moika

29

Bunu nasıl buluyorsunuz?

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

Foobar.prototype = {
    foobar: null
};

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

2
bunu (foobar) yeni döndür; çalışmıyor. Dönüşte yeni Foobar (foobar) değiştiririm; ve hepsi doğru çalışıyor.
isxaker

10
Ben anlamadım Kodu gerçekten kullandığınız yere ekleyebilir misiniz? Her seferinde Bileşenlerden aramanız gerekecek mi? Çünkü bu gerçek bir kurucu değil, yardımcı bir işlevdir. @ bobince'nin cevabı o zaman daha doğru görünüyor.
hofnarwillie

1
@hofnarwillie Tam olarak tam bir kurucu olmasa da, statik bir yöntem kullanarak oldukça benzer bir performans sergiliyor yani var foobarObj = Foobar.fromComponents (foo, bar); alternatif argümanlarla yeni bir nesne oluşturmak için ihtiyacınız olan tek şey.
Nathan Williams

21

sınıfı, bu sınıfın bir örneğini döndüren statik yöntemlerle kullanabilirsiniz.

    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)

bu modelle çoklu yapıcı oluşturabilirsiniz


3
Bu en iyi cevap. Diğerleri dizileri ayrıştırmaya ve bir sürü gereksiz iş yapmaya başvurur.
Blane Townsend

13

Bobince'nin cevabında olduğu gibi elle yapmak istemedim, bu yüzden jQuery'nin eklenti seçenekleri modelini tamamen söktüm.

İşte kurucu:

//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;
}

İşte örneklemenin farklı yolları:

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']});

Ve işte bunun yarattığı şey:

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]}

Aynı modeli node.js'de de şu şekilde kullandım: npmjs.com/package/extend
Jacob McKay

10

Eruciform yanıt ile ileri giderek, size zincirlemek edebilirsiniz newsenin içine çağrı inityöntemiyle.

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');

Yani temelde burada yaptığınız şey Foo nesnesini alıp prototip fonksiyonlarıyla init_1 ve init_2 parametrelerini çağırmaktır. İnit_1 ve init_2 dosyalarınızda işlev kelimesi bulunmalı.
Doug Hauf

İlk Foo () 'da}' den sonra noktalı virgül olmak zorunda mı?
Doug Hauf

Teşekkürler Doug, değişikliği ben yaptım.
laughingbovine

Bunun çalıştığından emin misin? Nesnelerdeki özelliklere erişemediğim new Foo()için aramayı zincirleme ve initbirlikte yapamadım. var a = new Foo(); a.init_1('constructor 1');
Koşmam

@MillieSmith Bir süredir JS yazmadığımı kabul ediyorum ... ama bu kodu Chrome JS konsoluna yapıştırdım ve yeniden init'e kadar olan zincir çalıştı.
Laughbovine

3

Bazen parametreler için varsayılan değerler birden çok kurucu için yeterlidir. Ve bu yeterli olmadığında, yapıcı işlevlerinin çoğunu daha sonra çağrılan bir init (diğer parametreler) işlevine sarmaya çalışıyorum. Ayrıca, istediğiniz diğer nesneleri etkili bir şekilde yaratabilecek bir nesne yapmak için fabrika konseptini kullanmayı düşünün.

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


1
Fabrika yöntemi iyi bir çözüm gibi geliyor - bunu, muhtemelen bu kullanım durumunda tamamen alakasız olan ayrı bir fabrika sınıfının kullanımıyla karıştırmadığınızdan emin olun.
Simon Groenewolt

1
Bu bağlantı hiçbir yere gitmiyor. Bu sayfada Javascript bağlantısı yok.
Rob

3

Bu soru google'da ilk olarak döndürüldüğü için cevaplanıyor, ancak cevaplar artık güncel değil.

Sen kullanabilirsiniz ES6 içinde yapıcı parametreleri olarak yapı bozma nesneleri

İşte model:

Birden fazla kurucunuz olamaz, ancak istediğinizi yapmak için yok etme ve varsayılan değerleri kullanabilirsiniz.

export class myClass {

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

    // ..
  }
}

Ve 'parametresiz' bir kurucuyu desteklemek istiyorsanız bunu yapabilirsiniz.

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

Bu, HTML5'te JavaScript ve CSS3 ile Programlama'da birden çok kurucu için verilen örnektir - Sınav Ref .

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"));

Ve Değişmezlik? prototip kullanmak mülkleri herkese açık hale getirir, değil mi?
Gabriel Simas

6
Bu yanlış. İkinci yapıcı tanımınız ilkini geçersiz kılar, bu nedenle daha sonra new Book () 'u çağırdığınızda, ikinci yapıcıyı tüm parametrelerin değerleri undefined olarak ayarlanmış şekilde çağırırsınız.
ErroneousFatality
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.