Mẫu JavaScript cho nhiều hàm tạo


124

Tôi cần các hàm tạo khác nhau cho các trường hợp của mình. Mô hình chung cho điều đó là gì?


xin vui lòng cụ thể hơn một chút. bạn muốn các hàm tạo với các bộ tham số khác nhau?
gblazex

Bạn có thể có nhiều hơn một hàm tạo trong Javascript không?
Doug Hauf

Có và không @DougHauf. Có bởi vì câu trả lời được cung cấp bởi bobince cung cấp một cách để cung cấp hành vi tương đương. Không bởi vì nếu bạn muốn có nhiều hàm tạo riêng biệt (mỗi hàm chia sẻ cùng một đối tượng nguyên mẫu) thì thuộc tính hàm tạo của đối tượng nguyên mẫu sẽ được đặt như thế nào (vì thuộc tính hàm tạo chỉ có thể trỏ đến một hàm tạo).
Moika biến

3
Tất cả những câu trả lời này đều cũ / không lý tưởng. Tôi quá lười biếng để gõ lên một câu trả lời, nhưng bạn có thể vượt qua một đối tượng xung quanh để chức năng và nhà thầu và sau đó sử dụng các phím giống như bạn làm đối số, ví dụ: function ({ oneThing = 7, otherThing = defaultValue } = {}) { }. = {}Tôi thêm vào đó là một thủ thuật khác mà tôi đã học được gần đây, trong trường hợp bạn muốn khả năng người dùng không chuyển đối tượng nào vào và sử dụng tất cả các giá trị mặc định.
Andrew

1
Theo dõi: Dưới đây là một số cách hay để giải quyết vấn đề này: stackoverflow.com/a/32626901/1599699 stackoverflow.com/a/41051984/1599699 stackoverflow.com/a/48287734/1599699 Tôi đặc biệt thích cái cuối cùng là true nhiều nhà xây dựng giống như hỗ trợ, sử dụng các chức năng nhà máy tĩnh như nhà xây dựng ( return new this();, return new this.otherStaticFactoryFunction();, vv)!
Andrew

Câu trả lời:


120

JavaScript không có tính năng nạp chồng hàm, bao gồm cả phương thức hoặc hàm tạo.

Nếu bạn muốn một hàm hoạt động khác nhau tùy thuộc vào số lượng và loại tham số bạn chuyển cho nó, bạn sẽ phải đánh hơi chúng theo cách thủ công. JavaScript sẽ gọi một hàm có nhiều hơn hoặc ít hơn số đối số đã khai báo.

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

Bạn cũng có thể truy cập argumentsnhư một mảng giống như một mảng để nhận thêm bất kỳ đối số nào được truyền vào.

Nếu bạn cần các đối số phức tạp hơn, bạn có thể đặt một số hoặc tất cả chúng vào bên trong tra cứu đối tượng:

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

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

Python trình bày cách các đối số mặc định và được đặt tên có thể được sử dụng để bao hàm hầu hết các trường hợp sử dụng theo cách thực tế và duyên dáng hơn là nạp chồng hàm. JavaScript, không quá nhiều.


2
Cảm ơn, điều này thực sự tốt đẹp. Tôi sẽ nói rằng tùy chọn thứ hai hữu ích không chỉ khi bạn có các đối số phức tạp, mà còn cả các đối số đơn giản nhưng khó phân biệt, ví dụ như hỗ trợ MyObj({foo: "foo"})cộng MyObj({bar: "bar"}). MyObj có hai cấu trúc - nhưng cả hai mất một đối số, mà là một chuỗi :-)
Alex Dean

1
Bạn có thể thêm nhiều hơn vào mã ví dụ cho ví dụ cụ thể này.
Doug Hauf

Xin chào @DougHauf, cuốn sách 'JavaScript: The Good Parts' của Crockford có một phần về mục này có tên là 'Object Specifier', rất nhiều ví dụ tham khảo trên mạng.
Moika quay vào

29

Làm thế nào để bạn tìm thấy cái này?

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

Foobar.prototype = {
    foobar: null
};

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

2
trả về mới cái này (foobar); không hoạt động. Tôi thay đổi khi trở lại Foobar mới (foobar); và tất cả đều đúng.
isxaker

10
Tôi không hiểu. Bạn có thể thêm mã mà bạn thực sự đang sử dụng nó không? Bạn sẽ phải gọi từComponents mỗi lần? Bởi vì đó không thực sự là một hàm tạo, mà là một hàm trợ giúp. Câu trả lời của @ bobince sau đó có vẻ chính xác hơn.
hofnarwillie

1
@hofnarwillie Mặc dù không hoàn toàn là một hàm tạo chính xác, nhưng bằng cách sử dụng một phương thức tĩnh, nó hoạt động khá giống nhau, tức là var foobarObj = Foobar.fromComponents (foo, bar); là tất cả những gì bạn cần để tạo một đối tượng mới với các đối số thay thế.
Nathan Williams

21

bạn có thể sử dụng lớp với các phương thức tĩnh trả về một thể hiện của lớp đó

    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)

với mẫu này, bạn có thể tạo nhiều hàm tạo


3
Đây là câu trả lời tốt nhất. Những người khác dùng đến phân tích các mảng và thực hiện một loạt công việc không cần thiết.
Blane Townsend

13

Tôi không cảm thấy muốn làm điều đó bằng tay như trong câu trả lời của bobince, vì vậy tôi chỉ hoàn toàn tách ra khỏi mẫu tùy chọn plugin của jQuery.

Đây là hàm tạo:

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

Dưới đây là các cách khởi tạo khác nhau:

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

Và đây là những gì đã tạo ra:

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

Bây giờ tôi cũng đã cuộn cùng một mẫu trong node.js với: npmjs.com/package/extend
Jacob McKay

10

Đi xa hơn với câu trả lời của eruciform, bạn có thể xâu chuỗi newcuộc gọi vào initphương pháp của mình .

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

Vì vậy, về cơ bản những gì bạn đang làm ở đây là lấy đối tượng Foo và sau đó gọi các tham số init_1 và init_2 với các hàm nguyên mẫu. Nếu init_1 và init_2 của bạn có chức năng từ với chúng.
Doug Hauf

có phải có dấu chấm phẩy sau dấu} trong Foo () đầu tiên không.
Doug Hauf

Cảm ơn Doug, tôi đã thực hiện thay đổi.
laughingbovine

Bạn có chắc điều này làm việc? Tôi không thể liên kết new Foo()và cuộc gọi với initnhau vì tôi không thể truy cập các thuộc tính trên các đối tượng. Tôi phải chạyvar a = new Foo(); a.init_1('constructor 1');
Millie Smith

@MillieSmith Tôi thừa nhận rằng tôi đã không viết JS lâu rồi ... nhưng tôi vừa dán mã này vào bảng điều khiển JS của Chrome và chuỗi từ mới đến init đã hoạt động.
laughingbovine

3

Đôi khi, giá trị mặc định cho các tham số là đủ cho nhiều hàm tạo. Và khi điều đó không đủ, tôi cố gắng gói hầu hết các chức năng của phương thức khởi tạo thành một hàm init (other-params) được gọi sau đó. Cũng nên xem xét sử dụng khái niệm nhà máy để tạo một đối tượng có thể tạo hiệu quả các đối tượng khác mà bạn muốn.

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


1
Phương thức Factory có vẻ như là một giải pháp tốt - chỉ cần đảm bảo không nhầm lẫn nó với việc sử dụng một lớp factory riêng biệt, điều này có thể hoàn toàn không liên quan trong trường hợp sử dụng này.
Simon Groenewolt

1
Liên kết đó chẳng đi đến đâu. Không có liên kết Javascript trên trang đó.
Rob

3

Trả lời vì câu hỏi này được trả lại đầu tiên trong google nhưng các câu trả lời hiện đã lỗi thời.

Bạn có thể sử dụng các đối tượng Hủy cấu trúc làm tham số phương thức khởi tạo trong ES6

Đây là mẫu:

Bạn không thể có nhiều hàm tạo, nhưng bạn có thể sử dụng cấu trúc hủy và giá trị mặc định để làm những gì bạn muốn.

export class myClass {

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

    // ..
  }
}

Và bạn có thể làm điều này nếu bạn muốn hỗ trợ một phương thức khởi tạo 'không tham số'.

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

Sử dụng:

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

0

Đây là ví dụ được đưa ra cho nhiều hàm tạo trong Lập trình trong HTML5 với JavaScript và CSS3 - Tham khảo bài kiểm tra .

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

Và tính bất biến? sử dụng nguyên mẫu đặt thuộc tính công khai, phải không?
Gabriel Simas

6
Điều đó là không chính xác. Định nghĩa hàm tạo thứ hai của bạn ghi đè định nghĩa đầu tiên, vì vậy khi bạn gọi Book () mới sau này, bạn đang gọi hàm tạo thứ hai với tất cả các giá trị của tham số được đặt thành không xác định.
ErroneousFatality
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.