Шаблон JavaScript для декількох конструкторів


124

Мені потрібні різні конструктори для моїх примірників. Яка загальна модель для цього?


будьте трохи конкретнішими, будь ласка. Ви хочете конструктори з різними наборами параметрів?
gblazex

Ви можете мати декілька конструкторів у Javascript?
Дуг Хауф

Так і ні @DougHauf. Так, тому що відповідь, надана bobince, забезпечує спосіб надати еквівалентну поведінку. Ні, тому що якби ви хотіли декілька різних конструкторських функцій (кожна з яких використовує один і той же об'єкт прототипу), як би встановити властивість конструктора об'єкта прототипу (оскільки властивість конструктора може вказувати лише на одну функцію конструктора).
Мойка виходить

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

У JavaScript немає перевантаження функцій, у тому числі для методів чи конструкторів.

Якщо ви хочете, щоб функція поводилася по-різному в залежності від кількості та типів параметрів, які ви передаєте їй, вам доведеться нюхати їх вручну. JavaScript буде радісно викликати функцію з більшою або меншою кількістю заявленої кількості аргументів.

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

Python демонструє, як аргументи за замовчуванням та іменовані аргументи можуть використовуватися для покриття більшості випадків використання більш практичним та витонченим способом, ніж перевантаження функцій. JavaScript, не так багато.


2
Дякую, це дійсно приємно. Я б сказав, що другий варіант корисний не лише тоді, коли у вас є складні аргументи, але й прості, але важко розрізнені аргументи, наприклад, підтримка MyObj({foo: "foo"})плюс MyObj({bar: "bar"}). У MyObj є два конструктори - але обидва беруть один аргумент, який є рядком :-)
Алекс Дін

1
Чи можете ви додати більше до прикладу коду для цього конкретного прикладу.
Дуг Хауф

Привіт @DougHauf, у книзі Крокфорда "JavaScript: хороші частини" є розділ цього розділу під назвою "Специфікатори об'єктів", багато прикладів посилаються на це в Інтернеті.
Мойка виходить

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
повернути нове це (foobar); не працює. Міняю по поверненню новий Foobar (foobar); і все правильно.
isxaker

10
Я не розумію. Чи можете ви додати код там, де ви його фактично використовуєте? Вам доведеться щоразу телефонувати зкомпонентів? Тому що це не справді конструктор, а скоріше допоміжна функція. @ відповідь bobince здається точнішою.
hofnarwillie

1
@hofnarwillie Хоча не зовсім точний конструктор, використовуючи статичний метод, він виконує досить подібні, тобто var foobarObj = Foobar.fromComponents (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
Це найкраща відповідь. Інші вдаються до розбору масивів та проведення непотрібної роботи.
Blane Townsend

13

Мені не здалося, що це робити вручну, як у відповіді bobince, тому я просто повністю зірвав схему параметрів плагінів 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]}


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

Тому в основному те, що ви робите тут, - це взяти об'єкт Foo, а потім викликати параметри init_1 та init_2 за допомогою функцій прототипу. Якщо ваші init_1 та init_2 мають функцію слова разом із ними.
Дуг Хауф

чи має бути після двокрапки двокрапка після першого} Foo ().
Дуг Хауф

Дякую Дугу, я змінив.
laughingbovine

Ви впевнені, що це працює? Мені не вдалося з'єднатись new Foo()і зателефонувати initразом, тому що я не мав доступу до властивостей об’єктів. Мені довелося бігатиvar a = new Foo(); a.init_1('constructor 1');
Міллі Сміт

@MillieSmith Я визнаю, що вже не писав JS вже давно ... але я просто вставив цей код у консоль Chrome JS і ланцюг від нового до init працював.
laughingbovine

3

Іноді значень за замовчуванням параметрів вистачає для декількох конструкторів. І коли цього недостатньо, я намагаюся ввімкнути більшість функціональних можливостей конструктора в функцію init (other-params), яка викликається згодом. Також розглянути можливість використання заводської концепції для виготовлення об'єкта, який може ефективно створювати інші об'єкти, які ви хочете.

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


1
Фабричний метод відчуває себе гарним рішенням - просто не забудьте переплутати його з використанням окремого фабричного класу, що, мабуть, абсолютно не має значення в цьому випадку використання.
Simon Groenewolt

1
Це посилання нікуди не йде. На цій сторінці немає якоря Javascript.
Роб

3

Відповідь, оскільки це питання повертається спочатку в google, але зараз відповіді застаріли.

Ви можете використовувати об'єкти Destructuring як параметри конструктора в 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;
    }
}

Використання:

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

0

Це приклад для кількох конструкторів у програмуванні в HTML5 за допомогою JavaScript та CSS3 - іспит № .

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
Це неправильно. Ваше друге визначення конструктора переосмислює перше, тому, коли ви викликаєте нову Book () пізніше, ви викликаєте другий конструктор із усіма значеннями параметрів, встановленими на невизначені.
Помилкова
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.