2008-08-16 15 views
13

tôi đã thường xuyên gặp phải các trang web đặt tất cả các javascript của họ bên trong một cấu trúc "namespace" dọc theo dòng củaCó cách nào "súc tích" để thực hiện đặt tên trong JavaScript không?

namespaces = { com : { example: { example.com's data} } 

Nhưng thiết lập này một cách an toàn đối với các khuôn khổ namespaced khác với dường như đòi hỏi một số lượng tương đối khổng lồ của mã (được định nghĩa là> 2 dòng). Tôi đã tự hỏi liệu có ai biết một cách ngắn gọn để làm điều này? và liệu có một cách tương đối chuẩn/nhất quán để cấu trúc nó không? ví dụ. sao không gian tên "com" được gắn trực tiếp vào đối tượng toàn cục, hay nó được gắn vào một đối tượng không gian tên?

[Chỉnh sửa: Rất tiếc, rõ ràng là {com = { ... } } sẽ không thực hiện được bất kỳ điều gì gần với ý định của tôi, nhờ Shog9 đã chỉ ra điều đó. : D]

Trả lời

19

Javascript không có không gian tên độc lập. Nó có các hàm, có thể cung cấp phạm vi để giải quyết tên và các đối tượng, có thể đóng góp vào dữ liệu có tên có thể truy cập trong một phạm vi nhất định.

Dưới đây là ví dụ của bạn, điều chỉnh:

var namespaces = { com: { example: { /* example.com's data */ } } } 

Đây là một biến namespaces được gán một đối tượng chữ. Đối tượng chứa một thuộc tính: com, một đối tượng có một thuộc tính: example, một đối tượng có thể chứa nội dung thú vị.

Vì vậy, bạn có thể nhập một cái gì đó như namespaces.com.example. somePropertyOrFunctionOnExample và tất cả sẽ hoạt động. Tất nhiên, nó cũng vô lý. Bạn không có một không gian tên phân cấp, bạn có một đối tượng chứa một đối tượng có chứa một đối tượng với những thứ bạn thực sự quan tâm.

var com_example_data = { /* example.com's data */ }; 

Điều đó cũng hoạt động tốt, không có phân cấp vô nghĩa.

Bây giờ, nếu bạn thực sự muốn để xây dựng một hệ thống phân cấp, bạn có thể thử một cái gì đó như thế này:

com_example = com_example || {}; 
com_example.flags = com_example.flags || { active: false, restricted: true}; 

com_example.ops = com_example.ops || (function() 
    { 
     var launchCodes = "38925491753824"; // hidden/private 
     return { 
     activate: function() { /* ... */ }, 
     destroyTheWorld: function() { /* ... */ } 
     }; 
    })(); 

... đó là, IMHO, hợp lý súc tích.

+1

Mặc dù, bây giờ 'com_example' sẽ là một phần của đối tượng toàn cầu. Giả sử chúng ta thêm nhiều đối tượng 'com_something_else',' com_etc', thì chúng ta vẫn đang làm ô nhiễm mức root của đối tượng toàn cầu. Nó sẽ không được ưa thích hơn nếu chúng ta chỉ có một đối tượng 'com' trong toàn cầu, nơi tất cả các đối tượng khác đã được thêm vào? Ngoài ra, chúng tôi không muốn ghi đè lên bất kỳ đối tượng hiện có nào, nếu có nhiều thư viện đang được sử dụng. – Peter

+2

@Peter: nếu nhiều thư viện xác định cùng một biểu tượng, bạn sẽ gặp vấn đề không có vấn đề gì; đó là lý do tại sao các thư viện như jQuery đi đến độ dài như vậy để nhồi nhét mọi thứ vào một đối tượng toàn cầu duy nhất. Quan điểm của tôi không phải là bạn * nên * sử dụng nhiều đối tượng cấp cao nhất, chỉ đơn thuần là các không gian tên giả mạo với các đối tượng lồng nhau không thực sự mua cho bạn bất cứ thứ gì trên các tên đối tượng điên rồ. Xem ví dụ cuối cùng của tôi cho một phương pháp thực tế hơn: sử dụng một tên chung duy nhất không có khả năng va chạm, và sau đó là một kỹ thuật cho phép các bit mã khác nhau thêm các đối tượng vào nó. – Shog9

3

Thư viện YUI library có mã xử lý việc đặt tên bằng cách sử dụng chức năng mà bạn có thể thấy thích hợp hơn. Các thư viện khác cũng có thể làm điều này.

12

Đây là một bài viết thú vị của Peter Michaux trên Javascript Namespacing. Ông thảo luận về 3 loại khác nhau của Javascript namespacing:

  1. Prefix namespacing
  2. Object Độc namespacing
  3. Object Nested namespacing

Tôi sẽ không ăn cắp của những gì ông nói ở đây nhưng tôi nghĩ rằng bài viết của ông là rất thông tin.

Peter thậm chí đã đi xa đến mức chỉ ra rằng có những cân nhắc về hiệu suất với một số người trong số họ.Tôi nghĩ rằng chủ đề này sẽ là thú vị để nói về xem xét rằng các kế hoạch ECMAScript Harmony mới đã giảm 4,0 kế hoạch cho không gian tên và đóng gói.

6

Tôi cố gắng tuân theo quy ước của Yahoo về việc tạo một đối tượng cha mẹ duy nhất trong phạm vi toàn cầu để chứa mọi thứ;

var FP = {}; 
FP.module = {}; 
FP.module.property = 'foo'; 
1

Là một thay thế cho một dấu chấm hoặc dấu gạch dưới, bạn có thể sử dụng ký tự ký hiệu đô la:

var namespaces$com$example = "data"; 
+0

Điều này mang lại lợi ích gì? – eyelidlessness

+0

Bằng cách làm theo cách này, bạn không phải xác định các không gian tên của bạn như một đối tượng có các đối tượng bên trong lồng nhau. Bạn chỉ có thể xác định tên ở bất cứ đâu. –

+0

Tôi vẫn không thấy lợi ích của việc sử dụng ký hiệu $ thay vì dấu chấm hoặc dấu gạch dưới. Tôi nghĩ rằng ký hiệu $ làm cho từ khó đọc hơn một dấu chấm hoặc dấu gạch dưới. –

5

Để chắc chắn rằng bạn không ghi đè lên một đối tượng hiện có, bạn nên để một cái gì đó như:

if(!window.NameSpace) { 
    NameSpace = {}; 
} 

hoặc

var NameSpace = window.NameSpace || {}; 

Bằng cách này bạn có thể đặt điều này ở đầu mỗi tập tin trong ứng dụng/trang web của bạn mà không phải lo lắng về việc ghi đè lên đối tượng vùng tên. Ngoài ra, điều này sẽ cho phép bạn viết các bài kiểm tra đơn vị cho từng tệp riêng lẻ.

1

Tôi cũng này (source) thích:

(function() { 
    var a = 'Invisible outside of anonymous function'; 
    function invisibleOutside() { 
    } 

    function visibleOutside() { 
    } 
    window.visibleOutside = visibleOutside; 

    var html = '--INSIDE Anonymous--'; 
    html += '<br/> typeof invisibleOutside: ' + typeof invisibleOutside; 
    html += '<br/> typeof visibleOutside: ' + typeof visibleOutside; 
    contentDiv.innerHTML = html + '<br/><br/>'; 
})(); 

var html = '--OUTSIDE Anonymous--'; 
html += '<br/> typeof invisibleOutside: ' + typeof invisibleOutside; 
html += '<br/> typeof visibleOutside: ' + typeof visibleOutside; 
contentDiv.innerHTML += html + '<br/>';​ 
0

Sử dụng một đối tượng theo nghĩa đen và một trong hai đối tượng this hoặc tên rõ ràng để làm không gian tên dựa trên các tính chất anh chị em ruột của biến địa phương, trong đó có chức năng.Ví dụ:

var foo = { bar: function(){return this.name; }, name: "rodimus" } 
 
var baz = { bar: function(){return this.name; }, name: "optimus" } 
 

 
console.log(foo.bar()); 
 
console.log(baz.bar());

Hoặc nếu không có sự rõ ràng name tài sản:

var foo = { bar: function rodimus(){return this; } } 
 
var baz = { bar: function optimus(){return this; } } 
 

 
console.log(foo.bar.name); 
 
console.log(baz.bar.name);

Hoặc mà không sử dụng this:

var foo = { bar: function rodimus(){return rodimus; } } 
 
var baz = { bar: function optimus(){return optimus; } } 
 

 
console.log(foo.bar.name); 
 
console.log(baz.bar.name);

Sử dụng RegExp hoặc Object chức năng xây dựng thêm các thuộc tính tên để đối phó với các biến và các tên thông thường khác, sau đó sử dụng một thử nghiệm hasOwnProperty để làm kiểm tra:

var foo = RegExp(/bar/); 
 
    
 
/* Add property */ 
 
foo.name = "alpha"; 
 

 
document.body.innerHTML = String("<pre>" + ["name", "value", "namespace"] + "</pre>").replace(/,/g, "&#09;"); 
 

 
/* Check type */ 
 
if (foo.hasOwnProperty("name")) 
 
    { 
 
    document.body.innerHTML += String("<pre>" + ["foo", String(foo.exec(foo)), foo.name] + "</pre>").replace(/,/g, "&#09;"); 
 
    } 
 

 
/* Fallback to atomic value */ 
 
else 
 
    { 
 
    foo = "baz"; 
 
    } 
 

 
var counter = Object(1); 
 

 
/* Add property */ 
 
counter.name = "beta"; 
 

 
if (counter.hasOwnProperty("name")) 
 
    { 
 
    document.body.innerHTML += String("<pre>" + ["counter", Number(counter), counter.name] + "</pre>").replace(/,/g, "&#09;"); 
 
    } 
 
else 
 
    { 
 
    /* Fallback to atomic value */ 
 
    counter = 0; 
 
    }

DOM sử dụng quy ước sau đây để không gian tên HTML và định nghĩa giao diện SVG Element:

  • HTMLTitleElement
  • SVGTitleElement
  • SVGScriptElement
  • HTMLScriptElement

Javascript lõi sử dụng nguyên mẫu để không gian tên phương pháp toString như một hình thức đơn giản của đa hình.

Tài liệu tham khảo

Các vấn đề liên quan