Learning JavaScript Design Patterns P.1 (ok)
https://addyosmani.com/resources/essentialjsdesignpatterns/book/#introduction
Object Creation
Ba cách phổ biến để tạo các đối tượng mới trong JavaScript như sau:
// Each of the following options will create a new empty object:
var newObject = {};
// or
var newObject = Object.create( Object.prototype );
// or
var newObject = new Object();Sau đó, có bốn cách để các khóa và giá trị có thể được gán cho một đối tượng:
// ECMAScript 3 compatible approaches
// 1. Dot syntax
// Set properties
newObject.someKey = "Hello World";
// Get properties
var value = newObject.someKey;
// 2. Square bracket syntax
// Set properties
newObject["someKey"] = "Hello World";
// Get properties
var value = newObject["someKey"];
// ECMAScript 5 only compatible approaches
// For more information see: http://kangax.github.com/es5-compat-table/
// 3. Object.defineProperty
// Set properties
Object.defineProperty( newObject, "someKey", {
value: "for more control of the property's behavior",
writable: true,
enumerable: true,
configurable: true
});
// If the above feels a little difficult to read, a short-hand could
// be written as follows:
var defineProp = function ( obj, key, value ){
var config = {
value: value,
writable: true,
enumerable: true,
configurable: true
};
Object.defineProperty( obj, key, config );
};
// To use, we then create a new empty "person" object
var person = Object.create( Object.prototype );
// Populate the object with properties
defineProp( person, "car", "Delorean" );
defineProp( person, "dateOfBirth", "1981" );
defineProp( person, "hasBeard", false );
console.log(person);
// Outputs: Object {car: "Delorean", dateOfBirth: "1981", hasBeard: false}
// 4. Object.defineProperties
// Set properties
Object.defineProperties( newObject, {
"someKey": {
value: "Hello World",
writable: true
},
"anotherKey": {
value: "Foo bar",
writable: false
}
});
// Getting properties for 3. and 4. can be done using any of the
// options in 1. and 2.Như chúng ta sẽ thấy phần sau của cuốn sách, các phương thức này thậm chí có thể được sử dụng để kế thừa, như sau:
Basic Constructors
Trên đây là một phiên bản đơn giản của mẫu hàm tạo nhưng nó có một số vấn đề. Một là nó làm cho việc kế thừa trở nên khó khăn và hai là các hàm như toString () được định nghĩa lại cho từng đối tượng mới được tạo bằng cách sử dụng hàm khởi tạo Car. Điều này không tối ưu lắm vì lý tưởng là chức năng này nên được chia sẻ giữa tất cả các phiên bản của loại Xe.
Rất may vì có một số lựa chọn thay thế tương thích với cả ES3 và ES5 cho việc xây dựng các đối tượng, nên việc khắc phục hạn chế này là rất nhỏ.
Constructors With Prototypes
Các hàm, giống như hầu hết các đối tượng trong JavaScript, chứa một đối tượng "nguyên mẫu". Khi chúng ta gọi một hàm tạo JavaScript để tạo một đối tượng, tất cả các thuộc tính của nguyên mẫu của hàm tạo sẽ được cung cấp cho đối tượng mới. Theo cách này, nhiều đối tượng Xe có thể được tạo để truy cập vào cùng một nguyên mẫu. Do đó, chúng ta có thể mở rộng ví dụ ban đầu như sau:
Ở trên, một phiên bản duy nhất của toString () bây giờ sẽ được chia sẻ giữa tất cả các đối tượng Car.
Module Pattern
Modules
Mô-đun là một phần không thể thiếu trong kiến trúc của bất kỳ ứng dụng mạnh mẽ nào và thường giúp giữ cho các đơn vị mã cho một dự án được phân tách và tổ chức rõ ràng.
Object Literals
Dưới đây, chúng ta có thể xem một ví dụ đầy đủ hơn về một mô-đun được xác định bằng cách sử dụng object literal:
Module Pattern
Trong JavaScript, mẫu Mô-đun được sử dụng để mô phỏng thêm khái niệm về các lớp theo cách mà chúng ta có thể bao gồm cả các phương thức và biến công khai / riêng tư bên trong một đối tượng duy nhất
Privacy
Cần lưu ý rằng không thực sự có ý nghĩa rõ ràng về "quyền riêng tư" bên trong JavaScript bởi vì không giống như một số ngôn ngữ truyền thống, nó không có công cụ sửa đổi quyền truy cập. Về mặt kỹ thuật, các biến không thể được khai báo là công khai hay riêng tư và vì vậy chúng tôi sử dụng phạm vi hàm để mô phỏng khái niệm này.
Examples
Hãy bắt đầu xem xét việc triển khai mô hình Mô-đun bằng cách tạo một mô-đun độc lập.
Ở đây, các phần khác của mã không thể đọc trực tiếp giá trị của incrementCounter () hoặc resetCounter (). Biến bộ đếm thực sự được bảo vệ hoàn toàn khỏi phạm vi toàn cục của chúng ta nên nó hoạt động giống như một biến riêng - sự tồn tại của nó bị giới hạn trong phạm vi đóng của mô-đun để mã duy nhất có thể truy cập phạm vi của nó là hai hàm của chúng ta.
Khi làm việc với mẫu Mô-đun, chúng tôi có thể thấy hữu ích khi xác định một mẫu đơn giản mà chúng tôi sử dụng để bắt đầu với nó. Đây là một trong đó bao gồm các biến không gian tên, công khai và riêng tư:
Nhìn vào một ví dụ khác, bên dưới chúng ta có thể thấy một giỏ hàng được triển khai bằng mẫu này. Bản thân mô-đun hoàn toàn tự chứa trong một biến toàn cục có tên là basketModule. Mảng giỏ trong mô-đun được giữ kín và do đó các phần khác của ứng dụng của chúng tôi không thể đọc trực tiếp nó. Nó chỉ tồn tại khi đóng mô-đun và vì vậy các phương thức duy nhất có thể truy cập nó là những phương thức có quyền truy cập vào phạm vi của nó (tức là addItem (), getItemCount (), v.v.).
Bên trong mô-đun, bạn có thể nhận thấy rằng chúng tôi trả về một đối tượng. Điều này sẽ tự động được gán cho basketModule để chúng tôi có thể tương tác với nó như sau:
Module Pattern Variations
Import mixins
Biến thể này của mẫu thể hiện cách các hình cầu (ví dụ: jQuery, Dấu gạch dưới) có thể được chuyển vào làm đối số cho hàm ẩn danh của mô-đun của chúng tôi. Điều này cho phép chúng tôi nhập chúng và bí danh cục bộ một cách hiệu quả như chúng tôi muốn.
Exports
Biến thể tiếp theo này cho phép chúng ta khai báo toàn cầu mà không cần tiêu thụ chúng và tương tự có thể hỗ trợ khái niệm nhập khẩu toàn cầu được thấy trong ví dụ cuối cùng.
Bộ công cụ và triển khai mẫu mô-đun dành riêng cho khung
Dojo
Dojo cung cấp một phương thức thuận tiện để làm việc với các đối tượng được gọi là dojo.setObject (). Điều này coi đối số đầu tiên của nó là một chuỗi được phân tách bằng dấu chấm, chẳng hạn như myObj.parent.child tham chiếu đến thuộc tính có tên "child" trong đối tượng "parent" được xác định bên trong "myObj". Sử dụng setObject () cho phép chúng ta đặt giá trị của các phần tử con, tạo bất kỳ đối tượng trung gian nào trong phần còn lại của đường dẫn được truyền nếu chúng chưa tồn tại.
Ví dụ: nếu chúng ta muốn khai báo basket.core như một đối tượng của không gian tên cửa hàng, điều này có thể đạt được như sau bằng cách sử dụng cách truyền thống:
Ví dụ: nếu chúng ta muốn khai báo basket.core như một đối tượng của store namespace, điều này có thể đạt được như sau bằng cách sử dụng cách truyền thống:
Or as follows using Dojo 1.7 (AMD-compatible version) and above:
ExtJS
Ở đây, chúng ta thấy một ví dụ về cách xác định một không gian tên mà sau đó có thể được điền bằng một mô-đun chứa cả API riêng và công khai. Ngoại trừ một số khác biệt về ngữ nghĩa, nó khá gần với cách mô-đun được triển khai trong JavaScript vani:
YUI
Tương tự, chúng ta cũng có thể triển khai Mô-đun mẫu khi xây dựng ứng dụng bằng YUI3. Ví dụ sau dựa nhiều vào việc triển khai mẫu Mô-đun YUI ban đầu của Eric Miraglia, nhưng một lần nữa, không khác nhiều so với phiên bản JavaScript vani:
jQuery
Có một số cách mà mã jQuery không cụ thể cho các plugin có thể được bao bọc bên trong mẫu Mô-đun. Ben Cherry trước đây đã đề xuất một triển khai trong đó một trình bao bọc hàm được sử dụng xung quanh các định nghĩa mô-đun trong trường hợp có một số điểm chung giữa các mô-đun.
Trong ví dụ sau, một hàm thư viện được định nghĩa để khai báo một thư viện mới và tự động liên kết hàm init với document.ready khi các thư viện mới (tức là mô-đun) được tạo.
Revealing Module Pattern
Mô hình Mô-đun tiết lộ ra đời khi Heilmann thất vọng với thực tế là anh ta phải lặp lại tên của đối tượng chính khi chúng ta muốn gọi một phương thức công khai từ một phương thức khác hoặc truy cập các biến công khai. Anh ấy cũng không thích yêu cầu của Mô-đun về việc phải chuyển sang ký hiệu chữ đối tượng cho những thứ anh ấy muốn công khai.
Kết quả của những nỗ lực của anh ấy là một mô hình được cập nhật trong đó chúng tôi chỉ cần xác định tất cả các hàm và biến của chúng tôi trong phạm vi riêng tư và trả về một đối tượng ẩn danh với các con trỏ đến chức năng riêng tư mà chúng tôi muốn tiết lộ dưới dạng công khai.
Mẫu cũng có thể được sử dụng để tiết lộ các chức năng và thuộc tính riêng tư với một lược đồ đặt tên cụ thể hơn nếu chúng ta muốn:
Singleton Pattern
Vì vậy, mẫu Singleton được biết đến vì nó hạn chế việc khởi tạo một lớp cho một đối tượng duy nhất. Về mặt cổ điển, mẫu Singleton có thể được thực hiện bằng cách tạo một lớp với một phương thức tạo ra một thể hiện mới của lớp nếu nó không tồn tại. Trong trường hợp một cá thể đã tồn tại, nó chỉ trả về một tham chiếu đến đối tượng đó.
Singleton khác với các lớp (hoặc đối tượng) tĩnh là chúng ta có thể trì hoãn việc khởi tạo chúng, nói chung là vì chúng yêu cầu một số thông tin có thể không có sẵn trong thời gian khởi tạo. Họ không cung cấp một cách để mã không biết về tham chiếu trước đó của họ để dễ dàng truy xuất chúng. Điều này là do nó không phải là đối tượng hoặc "lớp" được trả về bởi một Singleton, nó là một cấu trúc. Hãy nghĩ về cách các biến được đóng thực sự không phải là các bao đóng - phạm vi hàm cung cấp sự đóng lại là sự đóng lại.
Trong JavaScript, các Singleton đóng vai trò như một không gian tên tài nguyên được chia sẻ cách ly mã thực thi với không gian tên chung để cung cấp một điểm truy cập duy nhất cho các hàm.
Điều làm cho Singleton là quyền truy cập toàn cục vào cá thể (thường thông qua MySingleton.getInstance ()) vì chúng tôi không (ít nhất là trong các ngôn ngữ tĩnh) gọi trực tiếp MySingleton () mới. Tuy nhiên, điều này có thể thực hiện được trong JavaScript.
Trong thực tế, mẫu Singleton hữu ích khi cần chính xác một đối tượng để điều phối các đối tượng khác trên toàn hệ thống. Dưới đây là một ví dụ với mẫu được sử dụng trong ngữ cảnh này:
Observer Pattern
Observer là một mẫu thiết kế trong đó một object (được gọi là chủ thể) duy trì danh sách các đối tượng phụ thuộc vào observers (observers), tự động thông báo cho chúng về bất kỳ thay đổi nào đối với trạng thái.
Khi một đối tượng cần thông báo cho những người quan sát về một điều gì đó thú vị đang xảy ra, nó sẽ phát một thông báo cho những người quan sát (có thể bao gồm dữ liệu cụ thể liên quan đến chủ đề của thông báo).
Khi chúng tôi không còn muốn một quan sát viên cụ thể được thông báo về những thay đổi của chủ thể mà họ đã đăng ký, chủ thể đó có thể xóa họ khỏi danh sách quan sát viên.
Thường sẽ hữu ích khi tham khảo lại các định nghĩa đã xuất bản về các mẫu thiết kế không có ngôn ngữ để hiểu rộng hơn về cách sử dụng và lợi thế của chúng theo thời gian. Định nghĩa của mẫu Người quan sát được cung cấp trong sách GoF, Mẫu thiết kế: Các yếu tố của phần mềm hướng đối tượng có thể tái sử dụng,
Bây giờ chúng ta có thể mở rộng những gì chúng ta đã học được để triển khai mẫu Observer với các thành phần sau:
Subject: duy trì danh sách quan sát viên, tạo điều kiện thêm hoặc xóa quan sát viên
Observer: cung cấp giao diện cập nhật cho các đối tượng cần được thông báo về sự thay đổi trạng thái của Chủ thể
ConcreteSubject: phát thông báo cho người quan sát về những thay đổi của trạng thái, lưu trữ trạng thái của ConcreteObservers
ConcreteObserver: lưu trữ một tham chiếu đến ConcreteSubject, triển khai giao diện cập nhật cho Người quan sát để đảm bảo trạng thái nhất quán với Chủ thể
Đầu tiên, hãy lập mô hình danh sách các Quan sát viên phụ thuộc mà một đối tượng có thể có:
Tiếp theo, hãy lập mô hình Đối tượng và khả năng thêm, bớt hoặc thông báo cho các quan sát viên trong danh sách quan sát viên.
Sau đó, chúng tôi xác định một khung để tạo các Quan sát viên mới. Chức năng cập nhật ở đây sẽ được ghi đè sau đó với hành vi tùy chỉnh.
Sau đó, chúng tôi xác định các trình xử lý ConcreteSubject và ConcreteObserver để thêm người quan sát mới vào trang và triển khai giao diện cập nhật. Xem bên dưới để biết nhận xét nội tuyến về những gì các thành phần này làm trong bối cảnh của ví dụ của chúng tôi.
HTML:
Full code
C:\Users\Administrator\Desktop\gulp\index.html
C:\Users\Administrator\Desktop\gulp\es6.js
Differences Between The Observer And Publish/Subscribe Pattern
Mặc dù mẫu Observer rất hữu ích cần lưu ý, khá thường xuyên trong thế giới JavaScript, chúng tôi sẽ thấy nó thường được triển khai bằng cách sử dụng một biến thể được gọi là mẫu Publish / Subscribe. Mặc dù rất giống nhau, nhưng có sự khác biệt giữa các mẫu này đáng chú ý.
Mẫu Người quan sát yêu cầu người quan sát (hoặc đối tượng) muốn nhận thông báo chủ đề phải đăng ký mối quan tâm này với đối tượng kích hoạt sự kiện (chủ đề).
Tuy nhiên, mẫu Xuất bản / Đăng ký sử dụng kênh chủ đề / sự kiện nằm giữa đối tượng muốn nhận thông báo (người đăng ký) và đối tượng kích hoạt sự kiện (nhà xuất bản). Hệ thống sự kiện này cho phép mã xác định các sự kiện cụ thể của ứng dụng có thể chuyển các đối số tùy chỉnh chứa các giá trị mà người đăng ký cần. Ý tưởng ở đây là tránh sự phụ thuộc giữa người đăng ký và nhà xuất bản.
Điều này khác với mẫu Người quan sát vì nó cho phép bất kỳ người đăng ký nào triển khai một trình xử lý sự kiện thích hợp đăng ký và nhận thông báo chủ đề do nhà xuất bản phát.
Dưới đây là một ví dụ về cách một người có thể sử dụng Publish/Subscribe nếu được cung cấp triển khai chức năng hỗ trợ publish(), subscribe() và unsubscribe() đằng sau hậu trường:
Ý tưởng chung ở đây là sự thúc đẩy của khớp nối lỏng lẻo. Thay vì các đối tượng đơn lẻ trực tiếp gọi các phương thức của các đối tượng khác, chúng đăng ký vào một nhiệm vụ hoặc hoạt động cụ thể của một đối tượng khác và được thông báo khi nó xảy ra.
Publish/Subscribe Implementations
Xuất bản / Đăng ký rất phù hợp trong hệ sinh thái JavaScript, phần lớn bởi vì cốt lõi, việc triển khai ECMAScript là hướng sự kiện. Điều này đặc biệt đúng trong môi trường trình duyệt vì DOM sử dụng các sự kiện làm API tương tác chính của nó để tạo tập lệnh.
May mắn thay, các thư viện JavaScript phổ biến như dojo, jQuery (sự kiện tùy chỉnh) và YUI đã có các tiện ích có thể hỗ trợ dễ dàng triển khai hệ thống Xuất bản / Đăng ký với rất ít nỗ lực. Dưới đây, chúng ta có thể xem một số ví dụ về điều này:
A Publish/Subscribe Implementation
Example: Using Our Implementation
Bây giờ chúng tôi có thể sử dụng việc triển khai để xuất bản và đăng ký các sự kiện quan tâm như sau:

Full code
Example: User-Interface Notifications
Tiếp theo, hãy tưởng tượng chúng ta có một ứng dụng web chịu trách nhiệm hiển thị thông tin chứng khoán theo thời gian thực.
Ứng dụng có thể có một lưới để hiển thị số liệu thống kê về kho và một bộ đếm để hiển thị điểm cập nhật cuối cùng. Khi mô hình dữ liệu thay đổi, ứng dụng sẽ cần cập nhật lưới và bộ đếm. Trong trường hợp này, chủ đề của chúng tôi (sẽ xuất bản các chủ đề / thông báo) là mô hình dữ liệu và người đăng ký của chúng tôi là lưới và bộ đếm.
Khi người đăng ký của chúng tôi nhận được thông báo rằng bản thân mô hình đã thay đổi, họ có thể tự cập nhật cho phù hợp.
Trong quá trình triển khai của chúng tôi, người đăng ký của chúng tôi sẽ lắng nghe chủ đề "newDataAvailable" để tìm hiểu xem có thông tin cổ phiếu mới hay không. Nếu một thông báo mới được xuất bản cho chủ đề này, nó sẽ kích hoạt gridUpdate để thêm một hàng mới vào lưới của chúng tôi có chứa thông tin này. Nó cũng sẽ cập nhật bộ đếm cập nhật lần cuối để ghi lại lần cuối cùng dữ liệu được thêm vào
Example: Decoupling applications using Ben Alman's Pub/Sub implementation
Trong ví dụ xếp hạng phim sau đây, chúng tôi sẽ sử dụng triển khai jQuery của Ben Alman về Xuất bản / Đăng ký để chứng minh cách chúng tôi có thể tách giao diện người dùng. Lưu ý rằng việc gửi xếp hạng chỉ có tác dụng công bố thực tế là có sẵn dữ liệu xếp hạng và người dùng mới.
Điều đó phụ thuộc vào người đăng ký các chủ đề đó để sau đó ủy quyền những gì xảy ra với dữ liệu đó. Trong trường hợp của chúng tôi, chúng tôi đang đẩy dữ liệu mới đó vào các mảng hiện có và sau đó hiển thị chúng bằng cách sử dụng phương thức .template () của thư viện Underscore để tạo khuôn mẫu.
Điều đó phụ thuộc vào người đăng ký các chủ đề đó để sau đó ủy quyền những gì xảy ra với dữ liệu đó. Trong trường hợp của chúng tôi, chúng tôi đang đẩy dữ liệu mới đó vào các mảng hiện có và sau đó hiển thị chúng bằng cách sử dụng phương thức .template () của thư viện Underscore để tạo khuôn mẫu.

C:\Users\Administrator\Desktop\gulp\index.html
C:\Users\Administrator\Desktop\gulp\es6.js
C:\Users\Administrator\Desktop\gulp\jquery.ba-tinypubsub.min.js
Example: Decoupling an Ajax-based jQuery application
Trong ví dụ cuối cùng của chúng tôi, chúng tôi sẽ xem xét thực tế cách tách mã của chúng tôi bằng cách sử dụng Pub / Sub ngay từ đầu trong quá trình phát triển có thể giúp chúng tôi tiết kiệm một số cấu trúc lại tiềm ẩn khó khăn sau này.
Khá thường xuyên trong các ứng dụng Ajax nặng, khi chúng tôi nhận được phản hồi cho một yêu cầu, chúng tôi muốn đạt được nhiều hơn chỉ một hành động duy nhất. Người ta có thể chỉ cần thêm tất cả logic sau yêu cầu của họ vào một lệnh gọi lại thành công, nhưng có những hạn chế đối với cách tiếp cận này.

C:\Users\Administrator\Desktop\gulp\index.html
C:\Users\Administrator\Desktop\gulp\es6.js
C:\Users\Administrator\Desktop\gulp\jquery.ba-tinypubsub.min.js
Last updated