2012-03-06 26 views
8

Tôi đang ngày càng phát triển javascript và muốn đảm bảo rằng tôi đang theo các quy ước phổ biến. Hiện tại tôi có một thư viện bao gồm các chức năng có thể được truyền qua 1 mô hình để hoạt động hoặc nhiều mô hình.Quy ước Javascript cho các đối số độ dài thay đổi

Với khí hậu là một vài thư viện javascript rất phổ biến, tôi tò mò; liệu tôi có tuân theo 'tiêu chuẩn defacto' bằng cách đạt được yêu cầu 'một mục hoặc danh sách' của tôi hay không, bằng cách liệt kê biến đối số, hoặc bằng cách cho phép một trong các đối số là một mảng?

Kịch bản 1: Lập luận liệt kê

// passing a single entity to my function 
sendMail(email, recipient1); 

// passing multiple entities to my function 
sendMail(email, recipient1, recipient2); 

Kịch bản 2: đối số thực thể là một trong hai trường hợp duy nhất, hoặc mảng

// pass a single entity 
sendMail(email, recipient1); 

// passing multiple entities 
sendMail(email, [recipient1, recipient2]); 

Tôi đã thấy khu vực của jQuery mà sử dụng 'kịch bản 2 ', nhưng tôi vẫn muốn hỏi - cách tiếp cận nào là phổ biến nhất, và tại sao?

Cảm ơn

[EDIT]

Một vài ý kiến ​​đã theo bối cảnh đó, việc sử dụng một lập luận phản đối - đó là tương tự như 'kịch bản 2' - nhưng tôi cảm thấy nó giới thiệu sự phức tạp không cần thiết - các các yếu tố không cần phải được đặt tên, bởi vì chúng chỉ là một danh sách độ dài thay đổi. Tôi nghĩ tôi sẽ thêm vào đây trong trường hợp câu hỏi của tôi không đủ rõ ràng.

[EDIT]

tôi thấy mã như thế này suốt jQuery-1-7.js

queue: function(elem, type, data) { 
    var q; 
    if (elem) { 
     type = (type || "fx") + "queue"; 
     q = jQuery._data(elem, type); 

     // Speed up dequeue by getting out quickly if this is just a lookup 
     if (data) { 
      if (!q || jQuery.isArray(data)) { 
       q = jQuery._data(elem, type, jQuery.makeArray(data)); 
      } else { 
       q.push(data); 
      } 
     } 
     return q || []; 
    } 
} 

[EDIT]

Sau khi thảo luận với JP, tôi đến với điều này - mà tôi không nói là lựa chọn đúng, nhưng nó rất linh hoạt ...

lastArgumentAsParams: function() 
{ 
    var callerArgs = jQuery.makeArray(this.lastArgumentAsParams.caller.arguments); 

    // return empty set if caller has no arguments 
    if (callerArgs.length == 0) 
     return []; 
    callerArgs.splice(0, callerArgs.length - 1) 
    // remove all but the last argument 
    if (callerArgs.length == 1 && jQuery.isArray(callerArgs[0])) 
     return callerArgs[0]; 
    else 
     return callerArgs; 
} 

Nếu bạn gọi chức năng ở đầu của bất kỳ chức năng - nó sẽ xử lý arg cuối cùng trong người gọi như là một 'đối số chiều dài biến' - hỗ trợ bất kỳ của các công ước.

Ví dụ, tôi có thể sử dụng nó như thế này

function sendEmail(body, recipients) 
{ 
    recipients = lastArgumentAsParams(); 

    // foreach(recipient in recipients)... 
} 

Bây giờ, tôi có thể gọi là 'SendEmail' trong bất kỳ trong các cách sau và nó sẽ làm việc như mong đợi

sendEmail('hello world', "[email protected]"); 
sendEmail('hello world', "[email protected]", "[email protected]"); 
sendEmail('hello world', ["[email protected]", "[email protected]"]); 
+0

Lưu ý: một lần nữa: "đối số đối số" khi bạn nói, khác với câu trả lời của tôi và câu trả lời của Uzi. –

+0

Tôi đã chỉnh sửa câu trả lời của mình để hy vọng xóa sự nhầm lẫn. –

+0

Tôi thích nếu chúng ta không nhầm lẫn mẫu đối tượng được đặt tên với các danh sách độ dài thay đổi. Danh sách độ dài biến làm cho tôi nghĩ về những thứ như printf, có thể lấy bất kỳ số lượng đối số nào, trong khi đối số từ khóa là tuyệt vời cho các đối số và đối số tùy chọn có thể thay đổi thứ tự. Dù sao nó có lẽ sẽ là tốt nhất nếu JS giống như Python, nơi bạn có thể trộn và kết hợp hai kiểu. – hugomg

Trả lời

7

Cá nhân tôi thích sử dụng các đối tượng literals cho các đối số để hỗ trợ các tham số có tên, như sau:

var myfunc = function(params){ //same as: function myfunc(params){.... 
    alert(params.firstName); 
    alert(params.lastName); 
}; 

myfunc({firstName: 'JP', lastName: 'Richardson'}); 

Tôi nghĩ rằng nó làm cho mã rất dễ đọc và trật tự sẽ không thành vấn đề.

HOẶC

Bạn cũng có thể truy cập vào đối tượng arguments.Lưu ý, nó không phải là một mảng, nhưng nó "giống như mảng". Bạn có thể đọc về nó ở đây: http://javascriptweblog.wordpress.com/2011/01/18/javascripts-arguments-object-and-beyond/

Edit:

Bạn dường như có một sự hiểu lầm ở đây. Bạn đang sử dụng cụm từ "đối số đối số" và đang nghĩ rằng nó giống như ký hiệu chữ của đối tượng. Họ không phải.

Đối tượng arguments cho phép bạn làm điều này:

function myfunc(){ 
    alert(arguments[0]); //JP 
    alert(arguments[1]); //Richardson 
} 

myfunc('JP', 'Richardson'); 

Điều đó giúp đỡ?

+0

Cảm ơn JP - nhưng đối tượng đối số sẽ không có ý nghĩa, bởi vì tôi không muốn truyền 'cấu trúc linh hoạt của các mục, trong đó mỗi mục có ngữ cảnh ngữ nghĩa khác biệt'. Mỗi 'mục biến' có cùng ý nghĩa. tức là cho phép cả hai "mailServer.send (email1);" và "mailServer.send (email1, email2);" Nhưng tôi đoán bạn có lẽ sẽ thích 'kịch bản 2' của tôi. – Adam

+0

@Adam Note đối số 'đối số' và đối tượng literals là khái niệm trực giao. Nếu có một tham số, thì tôi sẽ không sử dụng các đối tượng literals. Nếu có nhiều hơn một tham số, phần lớn thời gian, tôi thích các đối tượng chữ. Để rõ ràng 100%, tôi không phải là fan của "kịch bản 2" của bạn. –

+0

Ngoài ra, kịch bản 2 của bạn là không cần thiết. Bởi vì bạn có thể khai báo một hàm mà không có bất kỳ tham số nào và vượt qua bao nhiêu tùy thích. Xem liên kết của tôi trên đối tượng 'arguments'. –

2

Một cách phổ biến là sử dụng đối tượng theo nghĩa đen như biến:

myFunction(true, {option: value, option2: value}); 

Cá nhân tôi thích phương pháp này vì nó là tiết hơn, và với javascript loại lỏng lẻo, nó mang lại cho bạn một gợi ý tốt cho các biến này là gì và bỏ qua thứ tự.

Backbone.js đang sử dụng phương thức này làm phương thức ưu tiên.

+0

Cảm ơn Uzi - câu trả lời của bạn dường như giống như của JP - Bạn có nghĩ rằng cách tiếp cận này giới thiệu sự phức tạp không cần thiết? Cả người gọi và callee cần phải biết rằng quy ước đặt tên 'option1: X, option2: Y' cần được sử dụng. Sử dụng var-arg hoặc một mảng ([]) loại bỏ sự cần thiết phải 'tên' mỗi mục. – Adam

+0

Tôi không chắc chắn về mức độ phức tạp của quảng cáo. Nếu bạn nghĩ về nó theo cùng một cách khai báo một kiểu biến, hơn là nó không thêm nhiều phức tạp, và nó thêm rất nhiều độ dài có thể là một vấn đề đối phó với một ngôn ngữ được đánh máy lỏng lẻo. –

2

Để mở rộng các câu trả lời khác, có hai lựa chọn thay thế chính tôi thường thấy: đối số tùy chọn và đối số từ khóa. Tôi không nhớ thấy bất kỳ ví dụ tốt về thành ngữ "sử dụng mảng" và nó là loại lỗi thời cho cách mảng arguments luôn sẵn có.

Dù sao, quy tắc chung của tôi là.

  • Nếu tôi có nhiều đối số, hoặc danh sách đối số có thể thay đổi, hoặc nếu các đối số không có một trật tự tự nhiên tốt, sử dụng các đối số mẫu tên

    phần ưa thích của tôi về phong cách này là nó là bằng chứng thực sự linh hoạt và trong tương lai, trong khi cũng là loại tự tài liệu (trong một phong cách smalltalk).

    foo({x1:'1', x2:'2', x3:'3'}); 
    
    function foo(kwargs){ 
        //I try to always copy the arguments back into variables. 
        //Its a little verbose but it helps documentation a lot and also 
        // lets me mutate the variables if I want to 
    
        var x1 = kwargs.x1, 
         x2 = kwargs.x2, 
         x3 = kwargs.x3; 
    } 
    
  • Nếu tôi có vài tranh cãi, đó là không có khả năng thay đổi, và có một trật tự tự nhiên đối với họ, sử dụng một chức năng đơn giản (với các đối số tùy chọn cuối cùng trong thứ tự)

    foo(x1, x2); 
    foo(x1, x2, x3); 
    

    có ba biến thể chính tôi có thể nghĩ ngay bây giờ làm thế nào để xử lý các đối số tùy chọn trong hàm:

    var foo = function(x1, x2, x3){ 
    
        //variation 1: truthy/falsy 
        // Short, but I tend to only use it when the variable stands 
        // for an object or other always-truthy kind of value 
        x3 = x3 || 'default_value'; 
    
        //variation 2: using a special placeholder value for blank arguments. 
        // Usually this is null or undefined. (and undefined works if the arg is not passed too) 
        if(typeof x3 === 'undefined'){ x3 = 'default_value'; } 
    
        //variation 3: explicitly check the number of arguments 
        // I really like this one since it makes clear if the argument was passed or not. 
        if(arguments.length < 3){ x3 = 'default_value'; } 
    } 
    

Ngoài ra, có rất điều tôi cố gắng tránh:

  • Đừng có chức năng nhận được một danh sách đối số lớn. Nó có thể trở thành một mớ hỗn độn nếu họ bắt đầu trở thành tùy chọn và bạn quên thứ tự

    foo(1, 2, null, null, 3, null, null); //ugh 
    
  • Đừng mảng sử dụng chiều dài cố định để được khôn lanh.Họ là dư thừa không có mảng chút nào và khi tôi nhìn thấy một mảng tôi thường mong đợi nó đến 1) được đồng nhất và 2) có thể được miễn là tôi muốn

    foo(true, [1, 2]); //should be foo(true, 1, 2) 
    
Các vấn đề liên quan