Những mẫu thiết kế mã javaScript: Constructor, Object Literal, Module

  • JavaScript
  • 08 tháng 12 2013
  • bởi Văn Khương
  • 0 Comments

Có nhiều cách thức viết mã javaScript khác nhau kể cả có sử dụng thư viện hoặc không sử dụng thư viện hổ trợ. Trong javaScript chúng ta cũng có nhiều cách để khai báo và sử dụng đối tượng. Chúng ta cũng biết các thư viện hay các ứng dụng javaScript cũng được viết theo một mẫu nào đó. Việc viết mã theo những mẫu hướng đối tượng là điều quan trọng, cũng như những ưu điểm của lập trình hướng đối tượng bởi sự chặt chẽ logic, sử dụng giễ dàng, giễ kiểm soát khi ứng dụng lớn, có khả năng tái sử dụng và phát triển tiếp... Chúng ta sẽ tìm hiểu một số mẫu javaScript đang được sử dụng cả những mẫu cổ điển và hiện đại trong bài viết này.

Mẫu Constructor

Như chúng ta đã biết javaScript không hổ trợ khái niệm lớp nhưng nó lại hỗ trợ việc hàm cũng có cách làm việc như đối tượng. Với việc gọi hàm với từ khóa "new" chúng ta đã tạo ra đối tượng từ việc gọi hàm và có thể sử dụng các thành phần trong hàm như hướng đối tượng, ở mẫu constructor từ khóa this sử dụng xuyên suốt trong hàm lúc này được hiểu như việc tham chiếu chính là đối tượng được tạo. Ví dụ:

function Kconstruct(a, b){
   this.propertya = a;
   this.propertyb = b;
   this.methodC = function(){
      return: this.propertya + " and " + this.propertyb;
   }
}
var myk = new Kconstruct("you", "me");
// Kiểm tra
console.log(myk.methodC()); // "you and me"

Chúng ta còn có thể hiểu phương thức methodC được viết như trên còn được gọi là phương thức privileged, khi sử dụng mẫu constructor với prototype thì còn được hiểu như phương thức public như bài viết trước (hướng đối tượng trong javaScript) đã bàn đến

Mẫu Object Literal

Đây là mẫu phổ biến bởi khả năng đóng gói và độ tổ chức mã cao, các chức năng được phân tách rạch ròi, nó cũng giữ cho mã của bạn có được sự rõ ràng và làm hạn chế được việc đụng độ bởi việc sử dụng không gian tên.

var myObjectLiteral = {
    variableKey: variableValue,
    functionKey: function () {
      // ...
    }
};

Nhìn có vẻ giống JSON nhưng bạn nên chú ý đây không phải là cú pháp chuẩn của JSON nên nó không phải là JSON. Việc sử dụng mẫu này các chức năng được phân tách nhiều nên đồng thời lượng mã viết cũng nhiều dòng hơn và các chức năng được liên kết với nhau khá nhiều nên phần nào cũng gây khó khăn cho việc đọc hiểu ứng dụng với những người chưa có kinh nghiệm sử dụng mẫu, và phải định hình các chức năng được phân tách ngay từ đầu nên cũng khó khăn cho người mới viết mã nhưng nó cũng là ưu điểm. Để hiểu thêm về mẫu object literal bạn có thể đọc một bài viết trên rmurphey.com tại đây sẽ có 2 vị dụ rất tốt để bạn hiểu về object literal.

Mẫu Module

Có thể nói mẫu Module có cở sở dựa trên object literals, là một phần của object literals mẫu Module sử dụng object literals chỉ có điều là nó được trả về trong phạm vi của hàm. Trước tiên chúng ta sẽ cùng xem ví dụ:

var myNamespace = (function () {
  var myPrivateVar, myPrivateMethod;
  // A private counter variable
  myPrivateVar = 0;
  // A private function which logs any arguments
  myPrivateMethod = function( foo ) {
      console.log( foo );
  };
  return {
    // A public variable
    myPublicVar: "foo",
    // A public function utilizing privates
    myPublicFunction: function( bar ) {
      // Increment our private counter
      myPrivateVar++;
      // Call our private method using bar
      myPrivateMethod( bar );
    }
  };
})();

Xem ví dụ trên ta có thể hiểu ngay rằng mẫu Module này giúp có được cả những thuộc tính và phương thức ở dạng public và private, điều này phân định rạch ròi những thứ chỉ được truy cập bên trong và những thứ có thể truy cập ở ngoài, bạn không thể chạm tới những thứ private mà phải thông qua những thứ public bởi những thứ public này có thể chạm tới những thứ private đó là 1 đặc điểm quan trọng của mẫu Module. Ở trên bạn cần chú ý tới từ khóa var khi khai báo biến để phạm vi của nó ở trong hàm. Thay vì tạo đối tượng khi return chúng ta còn có cách viết khác như sau:

// Global module
var myModule = (function () {
  var privateVariable = "Hello World";
  function privateMethod() {
    // ...
  }
  // Module object
  var module = {};
  module.publicProperty = "Foobar";
  module.publicMethod = function () {
    console.log( privateVariable );
  };
  return module;
}());

cách viết trên có ưu điểm là chúng ta có thể tạo ra nhiều đối tượng Object Literal có thể tương tác lẫn nhau trong global module và chỉ đối tượng nào được trả về thì mới là public, người ta gọi cái này là module export.

Nếu muốn sử dụng các đối tượng Global như thư viện jQuery chẳng hạn chúng ta chỉ việc truyền vào tham số hàm nặc danh của module, lúc này có thể đặt định danh cho nó như bạn muốn, người ta gọi cái này là global import. Ví dụ:

(function (JQ, YH) {
// Lúc này có thể truy cập jQuery như JQ và Yahoo như YH
}(jQuery, YAHOO));

Với mẫu module thì nó được viết xuyên suốt trong một file, trường hợp người khác hoặc chính bạn muốn viết tiếp hay mở rộng cho module mà không làm ảnh hưởng đến file ban đầu, nói cách khác là chúng ta muốn viết module ở nhiều file khác nhau thì cách thức thực hiện như ví dụ sau:

var myModule = (function (my) {
   // Thêm một phương thức
   my.anotherMethod = function () {
      // Ví dụ gọi phương thức publicMethod() đã viết
   my.publicMethod();
   };
   return my;
}(myModule || {}));

Ở ví dụ trên đoạn (myModule || {}) nói rằng nếu myModule chưa được tạo thì nó sẽ tạo ra module mới, bạn cần chú ý tham số my trong hàm nặc danh lúc này được trả về có ý nghĩa đại diện cho đối tượng module, người ta gọi cách viết trên là loose augmentation. Trường hợp bạn tạo lại thuộc tính hoặc phương thức đã có nó sẽ bị override, lúc này để đảm bảo vẫn có thể thao tác được với những thứ đã viết ta cần lưu vào thuộc tính hay biến mới.

Tiếp theo sẽ là trường hợp tạo ra một module mới có thể kế thừa lại những thuộc tính và phương thức public của một module đã tạo, cũng giống như cách trên nhưng có điều tham số trong hàm nặc danh của module lúc này đại diện cho module đã tạo mà bạn muốn kế thừa và giá trị trả về lúc này là đối tượng của module mới. Ví dụ:

var myModule_Two = (function (old) {
   var my = {}, key;
      for (key in old) {
         if (old.hasOwnProperty(key)) {
            my[key] = old[key];
         }
      }
      // Tạo một phương thức
      my.moduleMethod = function () {
         // Gọi lại phương thức đã sao chép
         my.publicMethod(); // có thể gọi old.publicMethod() nếu chưa sao chép
};
return my;
}(myModule));

Vòng for ở ví dụ trên đã sao chép tất cả thuốc tính và phương thức của module myModule đã tạo thông qua tham số đối tượng là old, lúc này trong vòng for sẽ dùng phương thức hasOwnProperty() trong javaScript để kiểm tra xem đối tượng old có tồn tại thuộc tính đó không nếu có thì làm giá trị cho đối tượng my, hàm nặc danh lúc này sẽ trả về đối tượng my cho module mới. Bạn có thể tìm hiểu kỹ hơn về mẫu module tại một bài viết ở adequatelygood.com

  • Chia sẻ
comments powered by Disqus