2011-08-21 34 views
17

Tôi biết, điều này thường được thảo luận. Nhưng sau khi tìm kiếm xung quanh như một người nào đó trong thế kỷ 19, tôi cần một số lời khuyên. Tôi không có vấn đề bằng cách tuyên bố một "không gian tên", nhưng khi nói đến một chức năng prototype.foo, tôi bị mắc kẹt. Tôi tìm thấy một cách, nhưng tôi không thích nó:Khai báo không gian tên Javascript với hàm mẫu

Namespace = {} 
Namespace.obj = function() { 
    this.foo="bar"; 
} 
Namespace.obj.prototype.start = function() { 
    this.foo="fubar"; 
} 

blah = new Namespace.obj(); 
blah.start(); 

Bây giờ, kể từ khi tôi là một chút thần kinh trong trường hợp kịch bản, tôi muốn có một cái gì đó như thế này:

Namespace = { 
    obj: function() { 
     this.foo="bar"; 
    }, 
    obj.prototype.start: function(tabinst) { 
     this.foo="fubar"; 
    } 
} 
... 

Nhưng sau đó nó ném một lỗi: "Uncaught SyntaxError: Mã thông báo không mong muốn."

Tôi biết, điều này là mỹ phẩm, nhưng tôi nghĩ rằng phải có một phương pháp tốt hơn để khai báo một "không gian tên" có chứa một lớp và các hàm nguyên mẫu.

Trả lời

29

Cách tôi làm là sử dụng "Module pattern".
Về cơ bản, bạn gói gọn tất cả logic "Mô-đun" của mình trong một chức năng tự thực thi sẽ trả về một đối tượng có các lớp, hàm, biến, v.v ... của bạn.

Namespace = (function() { 
    /** Class obj **/ 
    var obj = function() { 
     this.foo = 'bar'; 
    }; 
    obj.prototype = { 
     start: function() { 
      this.foo = 'fubar'; 
     } 
    }; 

    /** Class obj2 **/ 
    var obj2 = function() { 
     this.bar = 'foo' 
    }; 
    obj2.prototype = { 
     start: function() { 
      this.bar = 'barfoo'; 
     }, 
     end: function() { 
      this.bar = ''; 
     } 
    }; 
    return { 
     obj : obj, 
     obj2: obj2 
    }; 
})(); 

var o = new Namespace.obj() 
o.start() 

Để đóng gói thêm các phương thức lớp "obj" và xây dựng chúng ta có thể làm như sau:

/** Class obj **/ 
var obj = (function() { 
    /** class Constructor **/ 
    var obj = function() { 
     this.foo = 'bar'; 
    }; 
    /** class methods **/ 
    obj.prototype = { 
     start: function() { 
      this.foo = 'fubar'; 
     } 
    }; 
    return obj; 
})(); 

Ngoài ra còn có một tính năng quan trọng mà đi kèm miễn phí sử dụng mô hình này, đó là " Biến riêng tư ", hãy xem xét các điều sau:

/** Class Foo **/ 
var Foo = (function() { 
    // Private variables 
    var private_number = 200 
    /** class Constructor **/ 
    var Foo = function() { 
     this.bar = 0; 
    }; 
    /** class methods **/ 
    Foo.prototype = { 
     add: function() { 
      this.bar += private_number; 
     } 
    }; 
    return Foo; 
})(); 

foo = new Foo(); 
alert(foo.bar); // 0 
foo.add(); 
alert(foo.bar);// 200 
alert(foo.private_number) //undefined 
+0

Cách tiếp cận tốt đẹp, +1. – Jiri

+0

Thans Amjad, điều này thật tuyệt. Nhưng bây giờ tôi lại vấp ngã. Tôi có nhìn thấy nó đúng không: Với cách tiếp cận này, không thể tạo ra một hàm Namespace.blah() tách biệt là obj? –

+2

@Johnny Nếu tôi hiểu đúng câu hỏi của bạn, chỉ cần thêm hàm 'blah' vào đối tượng trả về: '. . return { obj: obj, obj2: obj2, blah: function() {/ * làm điều gì đó * /} }; ' –

2

Có bởi vì, bạn không thể sử dụng loại chaining trong một tuyên bố đối tượng

obj.prototype hoặc obj.something ở đây, bởi vì ngôn ngữ xem sự obj như một giá trị phi vật thể. Bạn có thể giả mạo như vậy ảnh hưởng như thế này

Namespace = {}; 

Namespace.obj =function() { 
     this.foo="bar"; 
}; 

Namespace.obj.prototype.start = function(tabinst) { 
     this.foo="fubar"; 
}; 

console.log(Namespace.obj.prototype); 

(thấy fiddle này http://jsfiddle.net/WewnF/)

EDIT: Wow, tôi chỉ nhận thấy rằng những gì tôi nói là đã nằm trong câu hỏi. Tôi rất xin lỗi đã không nhận thấy rằng sớm hơn ... Vâng, cách bạn mô tả chính mình là phương pháp chính xác để đạt được điều này.

Nếu không, bạn có thể viết lại mã của mình như thế này - nhưng không chính xác bạn đang làm gì và không hoạt động như cũ (vì obj sẽ không phải là một hàm và bạn sẽ phải gọi hàm chính của nó) như obj.main này();)

Namespace = { 
    obj: { 
      main : function() { 
       this.foo="bar"; 
      }, 
      prototype : { 
      start: function(tabinst) { 
      this.foo="fubar"; 
      } 
      } 
    } 
} 

EDIT 2: Xem fiddle này http://jsfiddle.net/NmA3v/1/

Namespace = { 
    obj: function() { 
     this.foo="bar"; 
    }, 
    prototype: { 
     obj : { 
      start : function(hi) { 
       alert(hi); 
      } 
     } 

    }, 

    initProto : function(){ 
     for(var key in Namespace) 
     { 
      if(key !== "prototype") 
      { 
       for(var jey in Namespace.prototype[ key ]) 
        Namespace[ key ].prototype[ jey ] = Namespace.prototype[ key ][ jey ]; 
      } 
     } 
    } 
} 

Namespace.initProto(); 

console.log(Namespace.obj); 

var test = new Namespace.obj(); 

test.start("Hello World"); 

này sẽ có tác dụng chính xác cùng. Giải thích: chúng ta khai báo các đối tượng của chúng ta như là các thuộc tính bình thường, và sau đó sử dụng một đối tượng nguyên mẫu chứa các đối tượng có cùng tên như trên, ví dụ cho mỗi Namespace.obj, cũng có một Namespace.prototype.obj chứa các hàm chúng ta muốn thêm vào trong chuỗi nguyên mẫu.

sau đó với namespace.protoInit(), chúng tôi lặp qua tất cả các thuộc tính - và trích xuất các hàm từ Namespace.prototype [key] và thêm chúng vào Namespace [key] .prototype - mở rộng thành công đối tượng mẫu thử nghiệm! Một chút không chính thống, nhưng hoạt động!

+0

Đoạn đầu tiên trong bản chỉnh sửa của bạn sẽ không hoạt động như bạn nghĩ. 'obj.main' và' obj.prototype' là hai hàm độc lập khác nhau. Có, 'this' sẽ chỉ đến cùng một đối tượng nếu bạn gọi chúng không có' new', nhưng chỉ vì nó đề cập đến 'window'. Vì vậy, bạn sẽ làm cho 'foo' toàn cầu. –

+0

Ví dụ thứ hai của bạn giới hạn 'Không gian tên 'để chỉ chứa một" lớp "mà bằng cách nào đó đánh bại mục đích của không gian tên. –

+0

Bạn là đúng cho ví dụ đầu tiên, và tôi cảm thấy ngu ngốc vì không nhận thấy điều này sớm hơn, nhưng tôi không đồng ý về điều thứ hai. Tại sao nó giới hạn nó chỉ với một "lớp"? Nếu bạn sử dụng nhiều đối tượng, nó sẽ lặp qua chúng và gán cho chúng các giá trị mẫu chính xác. – Pantelis

3

Chỉ để đá và mở rộng câu trả lời ở trên. Thêm một chút ký hiệu đối tượng dựa trên không gian tên lồng nhau

var NS = {}; 

// Class List 
NS.Classes = { 
    Shape: (function(){ 
    // Private 
    var whateveryouwishboss = false; 

    // Public 
    var Shape = function(x,y,w,h){ 
     this.x = x; 
     this.y = y; 
     this.w = w; 
     this.h = h; 
    }; 
    Shape.prototype = { 
     draw: function(){ 
     //... Im on prototype Shape 
     } 
    } 
    return Shape; 
    })(), 
    Person: (function(){ 
    //.... 
    })() 
} 

/////// Let the games begin 

var rect = new NS.Class.Shape(0,0,10,10); 
rect.draw() 
Các vấn đề liên quan