Home Blog Page 96

Tuốt tuồn tuột về Java 8 – những thay đổi lớn!

Tuốt tuồn tuột về Java 8 – những thay đổi lớn!

Bài viết được sự cho phép của tác giả Kiên Nguyễn

Java 8 xuất hiện với nhiều cải tiến rõ rệt, hãy cùng Kieblog tìm hiểu xem nhưng thay đổi lớn nào đã giúp Java 8 trở nên mạnh mẽ và linh động hơn.

Bài viết dưới đây liệt kê ra 5 THAY ĐỔI LỚN có ở JAVA 8. Hãy cùng đọc nhé!

  10 câu hỏi javascript để nâng cao trình độ
  10 lý do cho thấy tại sao bạn nên theo học ngôn ngữ lập trình Java

1. Phương thức forEach()

Cập nhật này đúng ra thì là quá chậm trễ so với .NET. Visual Basic hay C# đều đã có forEach từ lâu. Hãy quên đi những câu for xưa cũ để chuyển qua sử dụng ForEach

Phương thức này cũng được hỗ trợ tốt bởi Iterator (java.lang.Interable). Cùng xem xét ví dụ add tất cả các đối tượng i vào list như sau:

// Cách cũ truyền thống từ xưa vẫn sử dụng
// Nhìn thôi đã thấy rườm rà, chán
List<Integer> listDanhSach = new ArrayList<Integer>();
for(int i=0; i<69; i++) listDanhSach.add(i);

// Loop với Iterator
Iterator<Integer> it = listDanhSach.iterator();
while(it.hasNext()){
Integer i = it.next();
}

Bùm, với Java 8, chỉ đơn giản là:

// Easy for ence với forEach
listDanhsachA.forEach(a -> listDanhSachB.add(a.getB()));

2. Java 8 Lambda

Nhắc tới Java 8 mà không nhắc tới Lambda qủa thật là một sự thiếu sót to lớn. Lambda giúp cho functional programming (lập trình hàm) trở nên đơn giản hơn nhiều.

Syntax: parameter -> expression body. Dấu mũi tên biểu thị cho reference (tham chiếu tới cái gì đó)

Java Lambda liệt kê thành 4 loại sau đây:

Optional type declaration − No need to declare the type of a parameter. The compiler can inference the same from the value of the parameter

Không cần khai báo tham số. Trình compiler có thể tự suy luận các tham số cần thiết

Optional parenthesis around parameter − No need to declare a single parameter in parenthesis. For multiple parameters, parentheses are required.

Trường hợp có sử dụng tham số (nhiều hơn 2), bắt buộc phải khai báo bên trong cặp ngoặc ().

Optional curly braces − No need to use curly braces in expression body if the body contains a single statement.

Loại này không cần dấu ngoặc nhọn, nếu phần xử lí chỉ đơn giản được gói gọn trong phần body

Optional return keyword − The compiler automatically returns the value if the body has a single expression to return the value.

Loại sử dụng từ khóa return. Trình compiler sẽ tự động return về giá trị nếu body có một biểu thức trả về các giá trị.

Ông nào muốn tìm hiểu sâu hơn về Lambda có thể tham khảo bài viết về Java 8 Lambda ở Kieblog

3. Stream API

Sự xuất hiện của Stream trong Java 8 như là sự cứu rỗi cho các đoạn source loằng ngoằng trong Java. Nay với Stream, tất cả chỉ gói gọn trong một dòng code.

Đối với Stream thì Kieblog đã có một bài viết tương đối chi tiết và đặc sắc (Tuốt tuồn tuột về Stream trong Java 8).

4. Method reference

So với các ngôn ngữ như Scala hay Ruby on Rail đã có từ lâu. Method Reference cũng chỉ mới xuất hiện trên Java 8, khá trễ nhưng có còn hơn không.

Từ sau khi được release trên bản Java 8, Method Reference giúp code dễ đọc hơn, đỡ rườm rà, một số trường hợp còn dễ hiểu hơn cả Lambda.

Sơ bộ có thể chia Method Reference thành 4 loại chính:

4.1 Reference tới phương thức static

Các refer này khá sử dụng, với syntax là ContainingClass::methodName.

Cùng xem xét ví dụ sau đây:

// Cách viết này sử dụng lambda kiểm tra i có tồn tại trong list không
boolean isVisible = list.stream().anyMatch(i -> Item.isVisible(i));

Còn đây là cách sử dụng Java 8 method reference

// Chỉ đơn giản sử dụng ::, không cần care param, khá gọn
boolean isVisible = list.stream().anyMatch(Item::isVisible);

4.2 Reference tới instance của method

Khi new lên một instance method. Syntax có hơi khác hơn chút xíu: containingInstance::methodName

// Các dùng tương tự
Item item = new Item()
boolean isVisible = list.stream().anyMatch(item::isVisible())

4.3 Reference tới Instance Method của Object các kiểu đặc biệt

Loại này có syntax: ContainingType::methodName. Trường hợp nếu sử dụng với String, Long, Integer, … đều sử dụng được tất cả các instance method

// Tính tổng các String item trong list không empty
int count = list.stream().filter(String::isEmpty).count();

4.4 Reference tới Constructor

Loại này có ít bạn nhớ (sử dụng với từ khóa ::new), nhưng thực tế vẫn có thể reference tới constructor theo kiểu như sau:

// Tính tổng các String item trong list không empty
Stream<Item> stream = list.stream().map(Item::new);

5. Optional <T>

Trước khi Java 8 xuất hiện, để handle các trường hợp xuất hiện Exception thường rất vất vả. Catch đủ thứ, lỗi nào có thể văng ra thì catch lỗi đó. Đôi khi là hoa cả mắt xem lỗi đó catch ở đâu.

Class Optional <T> xuất hiện, giúp handle các khả năng văng NPE (Null Pointer Exception).

Handle NPE với Optional rõ ràng dễ hơn hẳn, cho phép ta cấu hình một số việc cần làm khi gặp NPE, trường hợp không có, chỉ đơn giản là thực thi một đoạn code nào đó.

// Lấy ra một list, nếu list khác null thì trả về list
// Nếu list null thì cần new ArrayList<>
List<String> listA = doAnyThingToGetList();
List<String> listB = list != null ? list : new ArrayList<>();

Sau khi áp dụng Optional:

// Đối với Java 8 Optional - chỉ đơn giản là một dòng code
List<String> listB = doAnyThingToGetList().orElseGet(() -> new ArrayList<>());

6. Tham khảo

Bài viết gốc được đăng tải tại kieblog.vn

Có thể bạn quan tâm:

Xem thêm Việc làm java lương cao hấp dẫn trên TopDev

Building Microservices Application – Phần mở đầu: Bức tranh tổng thể

Trong bài viết đầu tiên này, hãy cùng xem xét về bức tranh tổng thể khi xây dựng một ứng dụng Microservices

Bài viết được sự cho phép của tác giả Edward Thien Hoang

Đây là bài viết đầu tiên trong phần Xây dựng ứng dụng với Microservices. Trong những loạt bài trước, chúng ta đã tìm hiểu qua phần lý thuyết về những “viên gạch” (building block) chủ đạo trong Microservies. Loạt bài tiếp theo sẽ hướng đến việc implement những pattern như API Gateway, Service Discovery, Circuit Breaker trong kiến trúc Microservices như thế nào.

  Cải thiện hiệu năng cho JavaScript Web Application chỉ trong vòng vài bước đơn giản
  Security Considerations khi Designing Web Applications

Đáng lẽ mình sẽ tự tay implement và giải thích về ý nghĩa của từng phần, tuy nhiên, trong thời gian research đã tìm ra được một nguồn tài liệu viết rất chuyên nghiệp và đầy đủ. Vì vậy mình sẽ dựa trên đó để viết, nhằm mang đến cái nhìn professional và đúng đắn nhất 🙂 Các bạn có thể đọc các bài viết nguyên bản tiếng Anh tại ĐÂY.

Trong bài viết đầu tiên này, hãy cùng xem xét về bức tranh tổng thể khi xây dựng một ứng dụng Microservices, sẽ gồm những thành phần (chính) nào, và cách chúng coordinate với nhau như thế nào.

1. ĐIỀU KIỆN CẦN

Điều gì là cần thiết để triển khai một số lượng lớn các microservices trong hệ thống?

Hình vẽ dưới đây, theo Martin Fowler, sẽ cho ta biết chính xác điều chúng ta cần đạt được

1

(Nguồn: http://martinfowler.com/articles/microservices.html)

Tuy nhiên, trước khi chúng ta có thể bắt đầu tung ra số lượng lớn các microservices trong hệ thống để thay thế các ứng dụng nguyên khối, có một số điều kiện tiên quyết cần được đáp ứng (hoặc ít nhất là ở mức độ nào đó). Chúng ta cần:

  • một kiến ​​trúc mục tiêu
  • một chuỗi công cụ phân phối liên tục (continues delivery)
  • một tổ chức phù hợp

Hãy xem xét một cách ngắn gọn từng điều kiện tiên quyết.

1.1. KIẾN ​​TRÚC MỤC TIÊU

Đầu tiên chúng ta cần một ý tưởng kiến ​​trúc về cách phân vùng tất cả các microservices. Ví dụ, có thể phân vùng chúng theo chiều dọc trong một số layer như:

  • Core services Xử lý logic nghiệp vụ cốt lõi
  • Composite services có thể phối hợp một số Core services để thực hiện nhiệm vụ chung hoặc tổng hợp thông tin từ một số Core services.
  • API services cung cấp chức năng cho bên ngoài

… và theo chiều ngang, chúng ta có thể áp dụng một số phân vùng theo domain. Điều này có thể dẫn đến một kiến ​​trúc như dưới đây:

2

Lưu ý: Đây chỉ là một kiến ​​trúc mẫu, kiến ​​trúc của bạn có thể hoàn toàn khác nhau. Điều quan trọng ở đây là cần phải có một kiến ​​trúc mẫu được thiết lập trước khi bắt đầu mở rộng quy mô triển khai các microservices. Nếu không, bạn có thể kết thúc trong một cảnh quan hệ thống mà chỉ trông giống như một dĩa mì spaghetti (cực kỳ rối rắm, vô tổ chức) với đặc điểm thậm chí còn tồi tệ hơn so với các ứng dụng nguyên khối hiện có.

1.2. CONTINOUS DELIVERY

Chúng ta cũng giả định rằng có một hệ thống continuous delivery tool chain để có thể triển khai các microservices của mình theo cách có hiệu quả và có thể lặp lại được, ví dụ:

3

(Nguồn: http://www.infoq.com/minibooks/emag-devops-toolchain)

1.3. TỔ CHỨC

Cuối cùng, giả định rằng chúng ta đã thông qua tổ chức của mình để tránh các vấn đề với định luật Conway:

“Organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations.”

“Một công ty thiết kế hệ thống thế nào cũng sẽ làm ra những thiết kế giống y hệt với thiết kế hệ thống của chính công ty họ.”

4

(Nguồn: http://martinfowler.com/articles/microservices.html)

2. MỘT HỆ THỐNG PHỨC TẠP HƠN

Điều gì sẽ xảy ra trong một hệ thống khi chúng ta bắt đầu phân chia ứng dụng nguyên khối và thay thế chúng bằng một số lượng lớn các microservices?

Số lượng đơn vị triển khai (tức là microservice) lớn hơn. Nhiều microservices thay vì một ứng dụng nguyên khối lớn, do đó cần phải quản lý và theo dõi nhiều thành phần hơn.

Các services sử dụng và được sử dụng bởi các services khác sẽ dẫn đến một hệ thống mà nhiều services sẽ kết nối với nhau. (Xem thêm IPC)

Một số services cung cấp các API ra bên ngoài nhằm đóng gói và bảo vệ các services khác khỏi sự truy cập từ bên ngoài. (Xem thêm API Gateway)

Hệ thống sẽ động (dynamic) hơn. Các services mới được triển khai, các services cũ được thay thế hoặc loại bỏ, các instance mới của một service hiện có được khởi chạy thêm để đáp ứng tải gia tăng. Điều này có nghĩa là các services sẽ đến và đi với tần suất cao hơn nhiều so với trước đây. (Xem thêm Service Discovery)

MTBF (Mean time between failures – thời gian để có lỗi xảy ra) sẽ giảm (tức là lỗi nhiều hơn). Với rất nhiều service được triển khai và hoạt động thì xác suất xảy ra lỗi sẽ tăng lên là điều hiển nhiên.

3. NHỮNG VẤN ĐỀ ĐẶT RA

Làm thế nào tất cả các microservices được cấu hình và nó có đúng không? Xử lý cấu hình không phải là vấn đề lớn với một vài ứng dụng, ví dụ: mỗi ứng dụng lưu trữ cấu hình của riêng nó trong các tệp thuộc tính trên đĩa hoặc các bảng cấu hình trong cơ sở dữ liệu riêng của nó. Với một số lượng lớn các microservices được triển khai với nhiều instances trên nhiều máy chủ, cách tiếp cận này sẽ tạo nên vấn đề về cách quản lý cấu hình. Nó sẽ dẫn đến rất nhiều tập tin cấu hình nhỏ trên tất cả hệ thống làm cho việc duy trì và kiểm soát rất khó khăn.

Những microservices nào được triển khai và ở đâu? Bởi vì việc các microservies được triển khai với các địa chỉ máy chủ / cổng khác nhau. Với một số lượng lớn các microservices được triển khai độc lập với nhau sẽ có nhiều thay đổi liên tục trong hệ thống và điều này có thể dễ dẫn đến cơn ác mộng bảo trì nếu phải xử lý thủ công.

Cách cập nhật thông tin định tuyến (routing)? Client sử dụng các services cũng gặp các khó khăn. Cụ thể, nếu các bảng định tuyến, ví dụ như các reverse proxies hoặc các tệp cấu hình của Client, cần được cập nhật theo cách thủ công. Về cơ bản sẽ không có thời gian để chỉnh sửa thủ công các bảng định tuyến trong một hệ thống đang được phát triển liên tục với các microservices mới xuất hiện trên các địa chỉ máy chủ / cổng mới. Thời gian delivery sẽ kéo dài và rủi ro đối với các lỗi thủ công sẽ gây rủi ro về khía cạnh chất lượng và / hoặc làm cho chi phí hoạt động không cần thiết tăng lên.

Làm thế nào để ngăn chặn chuỗi sự cố xảy ra (chain of failures)? Vì các microservices sẽ được kết nối với nhau, cần phải chú ý đặc biệt để tránh các chuỗi sự cố. Nếu không được xử lý đúng thì một lỗi ở một microservies nào đó cũng có thể dẫn đến việc ngừng trệ toàn bộ cả hệ thống.

Làm cách nào để xác minh rằng tất cả các services đều đang hoạt động? Việc theo dõi trạng thái của một vài ứng dụng khá đơn giản nhưng làm cách nào để chúng ta xác minh rằng tất cả các microservices đều khỏe mạnh và sẵn sàng nhận request?

Làm cách nào để theo dõi các thông điệp giữa các services? Điều gì xảy ra nếu team bắt đầu nhận được khiếu nại về một số quá trình xử lý không thành công? Microservice nào là nguyên nhân gốc rễ của vấn đề? Làm thế nào ta có thể phát hiện ra rằng việc xử lý, ví dụ, đơn hàng 12345 bị kẹt vì không thể truy cập vào microservice A hoặc cần phê duyệt thủ công trước khi microservice B có thể gửi thông báo xác nhận liên quan đến đơn hàng đó?

Làm thế nào để đảm bảo rằng chỉ các API-services được đưa ra bên ngoài? Ví dụ: làm cách nào để tránh truy cập trái phép từ bên ngoài vào các microservices nội bộ?

Làm cách nào để bảo mật các API-services? Không phải là câu hỏi mới hoặc cụ thể liên quan đến microservices nhưng vẫn rất quan trọng để bảo đảm cho các microservices an toàn khi đưa ra ngoài.

4. CÁC THÀNH PHẦN CHÍNH TRONG MICROSERVICES

Để giải quyết các câu hỏi này, chúng ta sẽ cần các thành phần sau trong một hệ thống microservies:

Central Configuration server. Thay vì cấu hình cục bộ cho mỗi đơn vị triển khai (tức là microservice), chúng ta cần quản lý cấu hình tập trung. Chúng ta cũng cần một configuration API để các microservices có thể sử dụng để lấy thông tin cấu hình.

Service Discovery server. Thay vì theo dõi thủ công những microservices nào được triển khai hiện tại và trên máy chủ và cổng nào, chúng ta cần chức năng Service Discovery cho phép microservices tự đăng ký khi khởi động thông qua API.

Dynamic Routing and Load Balancer. Với chức năng service discovery, các thành phần định tuyến có thể sử dụng discovery API để tra cứu nơi mà microservice được yêu cầu được triển khai và các thành phần cân bằng tải có thể quyết định định tuyến yêu cầu tới instance nào nếu nhiều instance được triển khai cho một service được yêu cầu.

Circuit Breaker. Để tránh chuỗi sự cố, cần phải áp dụng Circuit Breaker pattern, bạn có thể đọc thêm trong cuốn sách Release It! hoặc bài đăng trên blog của Fowler – Circuit Breaker.

Monitoring. Vì đã có circuit breakers, chúng ta có thể bắt đầu theo dõi trạng thái của chúng và thu thập số liệu thống kê thời gian chạy từ chúng để có được một bức tranh về tình trạng sức khỏe của hệ thống.

Centralized log analysis. Để có thể theo dõi messages và phát hiện khi chúng bị kẹt (stuck), chúng ta cần một chức năng phân tích log tập trung có khả năng tiếp cận với máy chủ và thu thập các tệp log mà mỗi services microservice tạo ra. Chức năng phân tích log lưu trữ thông tin log này trong cơ sở dữ liệu trung tâm và cung cấp khả năng tìm kiếm và dashboard. Lưu ý : Để có thể tìm thấy các messages liên quan, điều quan trọng là tất cả các microservices phải sử dụng id đồng nhất trong các log message.

Edge Server. Để đưa các API services ra bên ngoài và để ngăn chặn truy cập trái phép vào các microservices nội bộ, chúng ta cần một edge server nơi tất cả request bên ngoài đi qua. Một edge server có thể tái sử dụng khả năng định tuyến động và cân bằng tải dựa trên service discovery được mô tả ở trên. Edge server sẽ hoạt động như một proxy ngược chủ động mà không cần cập nhật thủ công khi hệ thống nội bộ thay đổi.

OAuth 2.0 protected API’s Để bảo vệ các API services được expose ra bên ngoài, quy trình của OAuth 2.0 có thể như sau:

  • Một component mới có thể đóng vai trò như một Máy chủ ủy quyền (OAuth Authorization Server)
  • Các API services sẽ đóng vai trò như các Máy chủ tài nguyên (OAuth Resource Server)
  • Các Client bên ngoài gọi đến API services với tư cách là OAuth Clients
  • Edge server sẽ làm việc như một OAuth Token Relay, có nghĩa là:
    • Nó sẽ hoạt động như một OAuth Resource Server
    • Nó sẽ chuyển các OAuth Access Tokens có trong request bên ngoài đến các API services

5. MÔ HÌNH THAM CHIẾU

5

Lưu ý: Để giảm độ phức tạp, các tương tác giữa microservices và các services hỗ trợ không được vẽ.

6. BƯỚC TIẾP THEO

Trong các bài viết sắp tới, chúng ta sẽ lần lượt tìm hiểu về từng thành phần trong mô hình tham chiếu.

Series này là phần tiếp theo series Microservices: Từ Thiết Kế Đến Triển Khai, tập trung vào việc hiện thực hóa các khái niệm đã mô tả ở phần lý thuyết. Hi vọng sẽ giúp ích được cho các bạn khi làm quen với microservies. Các bạn có thể tham khảo thêm về phần Architecture căn bản ở đây nhé.

Bài viết gốc được đăng tải tại edwardthienhoang.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm IT Job hấp dẫn trên TopDev

Tại sao nên sử dụng controller as trong AngularJS?

Tại sao nên sử dụng controller as trong AngularJS

Bài viết được sự cho phép của tác giả Tino Phạm

Cho tới thời điểm này cú pháp Controller As được nhiều người khuyến khích sử dụng.

Tại sao vậy? có gì lợi hại hơn khi dùng Controller As?

  Inversion of Control nguyên lý của các nguyên lý

  Inversion of Control và Dependency Injection

Trước hết hãy xem 2 ví dụ sau đây, một cái dùng Controller và một dùng Controller As

  • Ví dụ 1 – dùng $Scope bình thường

  • Ví dụ 2 – dùng Controller as

Với cách dùng Controller as chúng ta thấy code dễ hiểu hơn. Đó là cái thứ nhất.

Khi bạn dùng cú pháp controller as thì Angular controller sẽ tạo ra một đối tượng và gán đối  tượng này vào $scope với tên mà bạn đã đặt trước đó. Ở đây các đối tượng được tạo ra là: main, another, yet.

Ảnh từ angular.org

Với $scope bạn sẽ gặp phải các vấn đề khi dùng controller lồng nhau, và các controller đó có nhưng thuộc tính giống nhau. Vậy bạn sẽ phải nhớ từng thuộc tính và cẩn thận khi dùng nó. Với Controller as, bạn sẽ có một cách viết rõ ràng và an toàn hơn khi sử dụng.

Khi bạn cần truy xuất các thuộc tính của $scope cha (parent scope), bạn sẽ không cần làm thế này:

mà bạn sẽ viết thế này

Bạn thấy không, chúng ta không cần phải viết dài dòng: $scope.$parent.$parent. Việc này khiến bạn phải cẩn thận và phải nhớ là có bao nhiêu $parent để có thể lấy chính xác dữ liệu mà bạn muốn, code của bạn xấu xí khó nhìn và cũng khó hiểu.

Tôi thường thấy mọi người dùng Controll as vm. Tại sao lại dùng biến vm? nó có khác biệt gì khi tôi đặt tên khác không?

Câu trả lời là bạn hoàn toàn CÓ THỂ đặt tên gì bạn muốn và nó KHÔNG KHÁC biệt gì cả. Nó giống nhau cả.

Nhưng, tại sao nhiều người hay dùng vm?

Bởi vì nó ngắn gọn và thường nó được hiểu như khái niệm view-model (nó thật sự không chính xác lắm nhưng theo nhiều người thường quy ước như vậy). Hãy xem ví dụ sau đây để hiểu thêm một vấn đề nữa.

Xem ví dụ trên, chúng ta có customers.customers bên trong ng-repeat. Đoạn code này làm bạn khó hiểu đúng không.

Vậy thì tôi sẽ đặt tên cho controller as chẳng hạn như: customerCtrl hoặc là custCtrl.

Đây là vấn để sở thích và phóng cách riêng của mỗi người nên bạn hoàn toàn có thể làm thế.

Tại sao lại dùng var vm = this?

Vì từ khóa this  được hiểu khác nhau trong từng ngữ cảnh (context) cho nên việc dùng nó đôi khi sẽ gặp vài vấn đề không theo ý muốn.

Vậy có phải tôi không cần dùng đến $scope nữa không?

Không phải hoàn toàn, vì chúng ta vẫn cần dùng đến $scope trong các trường hợp như: $scope.$on(), $scope.$watch(), $scope.apply(),….

Tóm lại, việc dùng controller as vì những lý do sau đây:

  1. Giúp code dễ hiểu và an toàn hơn. Nhất là trường hợp controller lồng nhau.
  2. Chúng ta dùng vm thay cho this là vì:
    1. this được hiểu khác nhau trong từng ngữ cảnh (context).
    2. vm viết ngắn gọn nhưng chúng ta vẫn hiểu được đó là một dạng view-model.

Bài viết xin kết thúc tại đây. Hy vọng được các bạn chia sẽ và đóng góp thêm ý kiến.

Bài viết gốc được đăng tải tại thangphampt.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Hiện thực WebSocket với Spring framework

Hiện thực WebSocket với Spring framework

Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh

WebSocket là một trong các loại Socket, nói nôm na cho các bạn dễ hình dung về WebSocket thì nó giúp chúng ta có thể tạo kết nối 2 chiều giữa server side và client side trong một web application bất kỳ. Một khi kết nối đã được thiết lập thì client và server có thể trao đổi các thông tin với nhau, client có thể gửi message cho server và ngược lại server cũng vậy. Khác với HTTP connection thì chỉ có client mới có thể gửi request tới server, server trả về response, server không thể tự gửi message tới bất kỳ client nào. WebSocket thường được sử dụng trong các ứng dụng web đòi hỏi tính realtime của một chức năng nào đó. Trong bài viết này, mình sẽ hướng dẫn các bạn cách hiện thực WebSocket trong một web application với Spring framework các bạn nhé!

  10 Java Web Framework tốt nhất
  10 tip tối ưu code trên JavaScript mà web developer nào cũng nên biết

Đầu tiên, mình sẽ tạo mới một Spring Boot project:

Hiện thực WebSocket với Spring framework

với Web và WebSocket dependency như sau:

Hiện thực WebSocket với Spring framework

để làm ví dụ.

Kết quả:

Hiện thực WebSocket với Spring framework

Tạo mới WebSocket server

Để khởi tạo WebSocket server với Spring WebSocket, trước tiên, các bạn cần phải nắm một số khái niệm như sau:

Đầu tiên là về Message Broker, nó là một message-oriented middleware server đứng ở giữa để delivery message từ các request tới các topic theo cơ chế pub-sub hoặc queue theo cơ chế point-to-point. Có nghĩa là thay vì các application gửi thẳng message tới topic hoặc queue mà các bạn thường thấy khi làm việc với Message Queue thì với Message Broker, các message phải đi qua Message Broker này. Spring sử dụng Message Broker để hiện thực WebSocket behind the sense đó các bạn!

Cái thứ hai là mình sẽ nói về STOMP. STOMP là gì? Nó là viết tắt của từ Streaming Text Oriented Messaging Protocol, dịch ra thì STOMP là một giao thức tin nhắn hướng văn bản, được sử dụng để client và server sau khi đã connect được với nhau, sử dụng để trao đổi thông tin. Spring cũng hỗ trợ giao thức này trong việc truyền thông tin giữa client và server với WebSocket đó các bạn.

OK, giờ chúng ta sẽ khai báo để tạo mới một WebSocket server các bạn nhé!

Các bạn cần tạo mới một class để cấu hình cho WebSocket. Class này sẽ implement interface WebSocketMessageBrokerConfigurer và được annotate với annotation @EnableWebSocketMessageBroker nha các bạn:

package com.huongdanjava.springboot.websocket;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

}

Tất nhiên, là nó cũng cần được annotate với annotation @Configuration để Spring Boot tự động scan nữa!

Có 2 phương thức mà chúng ta cần implement trong class WebSocketConfiguration này là configureMessageBroker() và registerStompEndpoints(). Phương thức configureMessageBroker() với tham số là class MessageBrokerRegistry cho phép chúng ta có thể cấu hình Message Broker với phương thức enableSimpleBroker():

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}

Tham số của phương thức enableSimpleBroker() là tên endpoint để các client có thể subscribe và nhận message từ server.

Trong phương thức configureMessageBroker() trên, mình cũng sử dụng thêm phương thức setApplicationDestinationPrefixes() để định nghĩa prefix cho các destination mà client sẽ gửi message tới WebSocker server. Các bạn nếu đã làm việc với RESTful Web Service sử dụng Spring MVC thì có thể hình dung mục đích của phương thức này giống như các bạn định nghĩa một request mapping trong Controller ở class level. Những method định nghĩa các request URL sẽ có prefix là value của request mapping này.

Phương thức registerStompEndpoints() với tham số là class StompEndpointRegistry thì cũng giống như khi định nghĩa các request URL trong RESTful Web Service, giúp chúng ta định nghĩa những endpoint mà client sẽ sử dụng để gọi và kết nối tới WebSocket. Chúng ta sử dụng phương thức addEndpoint() của class StompEndpointRegistry để thêm các endpoint mà các bạn muốn. Ví dụ mình định nghĩa một endpoint như sau:

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello");
}

Một số trình duyệt có thể sẽ không hỗ trợ WebSocket connection ví dụ như chế độ ẩn danh của trình duyệt Chrome chẳng hạn. Trong trường hợp này, các bạn có thể gọi thêm method withSockJS() để sử dụng các giải pháp thay thế khác như xhr-streaming, xhr-polling thay vì kết nối WebSocket mặc định.

Nội dung class WebSocketConfiguration của mình lúc này như sau:

package com.huongdanjava.springboot.websocket;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello").withSockJS();
}

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}

Để handle message từ client gửi tới endpoint mà chúng ta vừa mới configure ở trên “/hello”, các bạn có thể tạo mới một controller MessageController với nội dung như sau:

package com.huongdanjava.springboot.websocket;

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

@Controller
public class MessageController {

@MessageMapping("/hello")
@SendTo("/topic/messages")
public String send(String username) {
return "Hello, " + username;
}
}

Giống như controller trong Spring MVC, các bạn có thể annotate class handle message từ client với annotation @Controller nhưng thay vì sử dụng annotation @RequestMapping trong method handle message, chúng ta sử dụng annotation @MessageMapping với value là giá trị của endpoint mà chúng ta đã cấu hình trong class WebSocketConfiguration, ví dụ của mình là “/hello”.

Sau khi method xử lý business logic và trả về kết quả, kết quả này sẽ được gửi tới destination mà client đã subscribe, được khai báo trong annotation @SendTo.

Bây giờ, nếu các bạn chạy ứng dụng, xem log message, các bạn sẽ thấy WebSocket server sẽ start và sẵn sàng nhận kết nối từ phía client như sau:

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.0)

2021-06-05 11:36:45.108 INFO 38061 --- [ main] c.h.s.w.SpringBootWebsocketApplication : Starting SpringBootWebsocketApplication using Java 15.0.1 on Khanhs-MBP with PID 38061 (/Users/khanh/Documents/workspace-spring-tool-suite-4-4.9.0.RELEASE/spring-boot-websocket/target/classes started by khanh in /Users/khanh/Documents/workspace-spring-tool-suite-4-4.9.0.RELEASE/spring-boot-websocket)
2021-06-05 11:36:45.110 INFO 38061 --- [ main] c.h.s.w.SpringBootWebsocketApplication : No active profile set, falling back to default profiles: default
2021-06-05 11:36:46.683 INFO 38061 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-06-05 11:36:46.694 INFO 38061 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-06-05 11:36:46.694 INFO 38061 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.46]
2021-06-05 11:36:46.860 INFO 38061 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-06-05 11:36:46.860 INFO 38061 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1609 ms
2021-06-05 11:36:47.306 INFO 38061 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-06-05 11:36:47.307 INFO 38061 --- [ main] o.s.m.s.b.SimpleBrokerMessageHandler : Starting...
2021-06-05 11:36:47.307 INFO 38061 --- [ main] o.s.m.s.b.SimpleBrokerMessageHandler : BrokerAvailabilityEvent[available=true, SimpleBrokerMessageHandler [org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry@6a1ef65c]]
2021-06-05 11:36:47.308 INFO 38061 --- [ main] o.s.m.s.b.SimpleBrokerMessageHandler : Started.
2021-06-05 11:36:47.319 INFO 38061 --- [ main] c.h.s.w.SpringBootWebsocketApplication : Started SpringBootWebsocketApplication in 2.769 seconds (JVM running for 3.982)
2021-06-05 11:36:47.320 INFO 38061 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state LivenessState changed to CORRECT
2021-06-05 11:36:47.321 INFO 38061 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state ReadinessState changed to ACCEPTING_TRAFFIC
2021-06-05 11:37:47.023 INFO 38061 --- [MessageBroker-1] o.s.w.s.c.WebSocketMessageBrokerStats : WebSocketSession[0 current WS(0)-HttpStream(0)-HttpPoll(0), 0 total, 0 closed abnormally (0 connect failure, 0 send limit, 0 transport error)], stompSubProtocol[processed CONNECT(0)-CONNECTED(0)-DISCONNECT(0)], stompBrokerRelay[null], inboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], outboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], sockJsScheduler[pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]

Tiếp theo, chúng ta sẽ code phần client để xem WebSocket hoạt động như thế nào nhé các bạn!

Tạo mới client kết nối tới WebSocket server

Mình sẽ viết code HTML, JavaScript để giả lập việc gửi message từ client tới server, và cả việc server gửi message tới client như thế nào.

Mình sẽ sử dụng WebJars để thêm JQuerySocketJS client và Stomp WebSocket dependencies như sau:

<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
<dependency>
<groupId>org.webjars.npm</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>sockjs-client</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>stomp-websocket</artifactId>
<version>2.3.4</version>
</dependency>

JQuery dùng để viết code Javascript dễ dàng hơn, SockJS để làm việc với WebSocket connection còn Stomp WebSocket thì để chúng ta làm việc với STOMP message đó các bạn!

Mình sẽ tạo mới một trang HTML cho phép chúng ta nhập tên user, nhấn nút gửi tới WebSocket server, và một nơi để hiển thị kết quả trả về từ WebSocket server.

Hiện thực WebSocket với Spring framework

Nội dung của tập tin index.html trong thư mục src/main/resources/static như sau:

<!DOCTYPE html>
<html>
<head>
<title>Hello WebSocket</title>
<script src="/webjars/jquery/dist/jquery.min.js"></script>
<script src="/webjars/sockjs-client/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/stomp.min.js"></script>
<script src="/app.js"></script>
</head>
<body>
<div id="main-content">
<div>
<form>
<div>
<label>What is your name?</label> 
<input type="text" id="name" placeholder="Your name here...">
</div>
<button id="send" type="submit">Send</button>
</form>
</div>
</div>
<div>
<label>Message from server: </label><span id="message"></span>
</div>
</body>
</html>

Tập tin app.js cũng trong thư mục src/main/resources/static có nội dung như sau:

var stompClient = null;

$(document).ready(function() {
connect();
});

function connect() {
var socket = new SockJS('/hello');
stompClient = Stomp.over(socket);
stompClient.connect({}, function() {
console.log('Web Socket is connected');
stompClient.subscribe('/topic/messages', function(message) {
$("#message").text(message.body);
});
});
}

$(function() {
$("form").on('submit', function(e) {
e.preventDefault();
});
$("#send").click(function() {
stompClient.send("/app/hello", {}, $("#name").val());
});
});

Nếu các bạn biết một chút về JQuery thì sẽ hiểu code của mình có nghĩa là: khi browser đã load nội dung của trang index.html, web của mình sẽ tự động connect tới WebSocket server sử dụng thư viện SockJS client và sử dụng thư viện Stomp WebSocket để gửi STOMP message. Đối tượng Stomp Client sẽ subscribe vào “/topic/messages” để nhận message từ WebSocket server.

Stomp Client cho phép chúng ta có thể gửi một STOMP message tới WebSocket server sử dụng endpoint “/app/hello” với giá trị chúng ta nhập trong textbox.

Mỗi khi nhận message từ WebSocket server thì giá trị trong phần body của STOMP message này sẽ được hiển thị.

Kết quả khi mình chạy ứng dụng, nhập Khanh vào textbox và nhấn nút Send như sau:

Hiện thực WebSocket với Spring framework

Bài viết gốc được đăng tải tại huongdanjava.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Điều hướng trong Node.js

Điều hướng trong Node.js

Bài viết được sự cho phép của smartjob.vn

Các bạn mất 20 phút thực hành và đi tới phần này để hiểu hơn về cách hoạt động khi có 1 request tới và điều hướng trả về file Html nào .Ví dụ như sau khi bạn nhập trình duyệt : http://127.0.0.1/about.html thì server trả về cho bạn nội dung có trong file about.html

  10 Công ty hàng đầu thế giới sử dụng Node.js
  Cách tạo một Docker đơn giản cho Node.JS

Tạo file và thư mục tại bất kỳ đâu bạn muốn dưới đây demo mình để ở  ổ E như hình  dưới:

Cấu trúc thư file folder như sau:  public   ,  dieuhuong.js  , about.html ,  home.html

Nội dung các file như sau :

Trên file trên sẽ đọc request  của url  lấy nội dung file trong thư mục public truyền vào biến data respone về trình duyệt.

about.html

home.html

Sau đó mở CMD  tới thư mục chứa file dieuhuong.js  thự thi tiến trình bằng cách gõ lệnh node dieuhuong.js  ở đây mình để ở thư mục     E:\dieuhuong_node.js_smartjob.vn

Sau đó mở trình duyệt gõ địa chỉ và kiểm tra:  http://127.0.0.1/about.html    http://127.0.0.1/home.html

Các bạn  có thể thêm các file smartjob.html hay  file khác trong html và thứ request . Trên đây là hướng dẫn cơ bản nhất code thuần node js để diều hướng và gửi về  nội dung file html  để các bạn có thể hình dung ra cách hoạt động . Sau này việc điều hướng Route sẽ sử dụng thư viện express trong node js để diều hướng với nhiều phân cấp chức năng hơn .

Chúc các bạn thực hành thành công mọi thắc mắc các bạn có thể liên hệ qua Skype : nguyenanhdung90.

Bài viết gốc được đăng tải tại smartjob.vn

Có thể bạn quan tâm:

Xem thêm IT Jobs Developer hấp dẫn trên TopDev

Hướng dẫn Angular 2 cho người mới bắt đầu – Phần 3

Hướng dẫn Angular 2 cho người mới bắt đầu – Phần 3

Bài viết được sự cho phép của tác giả Tino Phạm

Ở phần 2, bạn đã tạo được một ứng dụng với Angular 2 + Typescript. Tuy nhiên, nó không có gì ngoài hiển thị dòng chữ “My First Angular 2 App”. Trong phần này, mình sẽ cố gắng giải thích thêm về các bước mà chúng ta đã thực hiện ở phần 2.

  "Muốn đi nhanh phải dựa vào dev, muốn đi nhanh hơn nữa phải dựa vào khách hàng"

  8 lợi thế khi sử dụng Polymer so với Angular và React
  1. File tsconfig.json
    File tsconfig.json là file cấu hình cho trình biên dịch của Typescript (Typescript compiler configuration). Nghĩa là, chúng ta viết code Typescript ( *.ts ) nhưng khi chạy ứng dụng thì browser sẽ đọc nội dung file ( *. js ). Ví dụ: main.ts => sẽ có main.jsmain.js.map được sinh ra.Các files main.jsmain.js.map được Typescript compiler (tsc) tạo ra khi chúng ta gọi lệnh npm start.Vậy khi Typescript compiler chạy, nó sẽ đọc nội dung file tsconfig.json để biết được làm thế nào để biên dịch từ Typescript sang Javascript.

    • target: “es5”  => sử dụng phiên bản ECMAScript 2009 (ES6: ECMAScript 2015). Bạn có thể thay đổi nếu muốn dùng ES6 để biên dịch.
    • module: “system” => chỉ ra làm thế nào để các modules được load lên khi làm việc với các file riêng lẽ. Ở đây sử dụng system. Ngoài ra còn các patterns: CommonJS, AMD, UMD
    • sourceMap: true => cho phép tạo ra file *.map tương ứng.
    • moduleResolution: “node” => cách này chúng ta có thể load modules từ thư mục node_modules.
    • emitDecoratorMetadata và experimentalDecorators: true => enable sử dụng decorators.
    • noImplicitAny: false => disable thông báo lỗi khi method hay property không có kiểu.
    • exclude: định nghĩa những thư mục, những files mà sẽ bị loại ra hay  bỏ ra khi biên dịch.
  2. File typings.json
    Nhiều thư viện (Library) Javascript mở rộng thêm các tính năng mới và cú pháp mới cho môi trường Javascript. Nhưng, trình biên dịch của Typescript (Typescript compiler) không nhận ra được và nó sẽ quăng ra lỗi.
    File typings.json sẽ được dùng để giải thích cho những định nghĩa mà bạn dùng để mở rộng Javascript trong ứng dụng của bạn.

    • core-js: giúp cho các trình duyệt chỉ hỗ trợ ES5 trở xuống có thể hiểu được những code viết bằng ES6.
    • jasmine: sử dụng Jasmine test framework.
    • node: dùng cho code mà nó tham chiếu đến các đối tượng trong môi trường NodeJS
  3. File package.json
    package.json lưu lai thông tin của ứng dụng, cùng với thông tin của những gói thư viện mà ứng dụng của bạn đang dùng. Khi chúng ta gõ lệnh: npm install thì những Library được định nghĩa trong package.json sẽ được tải về và cài đặt.
  4. Terminal trong VS Code và Command Line (cmd) trong window
    Trong Visual Studio Code bạn có thể sử dụng Terminal thay cho Command Line của window. Sẽ tiện lợi hơn cho bạn không cần mở nhiều windows khi làm việc.
  5. Một số lệnh cần thiết khi build và run ứng dụng
    • npm install: dùng để cài đặt tất cả các gói được định nghĩa sẵn  trong file package.json
    • npm install tên_package -g –save: để cài đặt từng gói thư viện mà bạn cần và lưu thông tin vào package.json. Cách này dùng khi bạn build ứng dụng của bạn ban đầu. Khi gửi ứng dụng của bạn cho người khác bạn sẽ bỏ qua (bỏ ra) thư mục node_modules. Đây là thư mục chứa những gói thư viện được dùng cho ứng dụng của bạn. Vậy, những người khác sẽ phải gõ lệnh: npm install để tải về và cài đặt những gói được lưu trong package.json
    • tsc: lệnh này dùng để biên dịch file *.ts thành *.js
    • npm run lite: chạy lite server
    • npm start: lệnh này sẽ tự động thực thi lệnh tsc và npm run lite
    • ctrl + c : stop lite server
    • ctrl + `: mở chế độ Terminal trong VS Code

Lưu ý: để sử dụng được lệnh tsc bạn phải update typescript 2.0 và trong file tsconfig.json bạn sửa thông tin:
“target”: “es6“,
“module”: “commonjs

Trong phần 4, chúng ta sẽ viết thêm các tính năng mới và mở rộng ứng dụng.

Tham khảo:
1. http://www.typescriptlang.org/docs/handbook/compiler-options.html
2. https://angular.io/docs/ts/latest/guide/typescript-configuration.html
3. https://www.tutorialspoint.com/angular2/angular2_environment.htm

Bài viết gốc được đăng tải tại thangphampt.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Cấu trúc trang HTML cơ bản

Cấu trúc trang HTML cơ bản

Bài viết được sự cho phép của tác giả Kien Dang Chung

Quá trình học lập trình thường khá dài và hầu hết mọi người đều muốn nhanh chóng bước vào các bài lý thuyết lập trình và thực hành các ví dụ thực tế. Những bài viết đầu tiên một khóa học lập trình web chủ yếu giới thiệu các thông tin xoay quanh ngôn ngữ, các thuật ngữ liên quan tuy nhiên cũng rất quan trọng bởi khi bạn đã nắm được HTML5 là gì? thì việc học các cấu trúc, các thẻ html chỉ là công cụ để xây dựng website mà thôi. Có rất nhiều bạn đã vào nghề lập trình web rất lâu nhưng không hiểu rõ bản chất HTML là gì hay còn mơ hồ về siêu văn bản, tại sao lại phải sử dụng HTML?… mà chỉ nhăm nhăm muốn code ngay. Những kiến thức cơ bản là nền tảng để phát triển tư duy công việc sau này, bạn không chỉ là một người lập trình (coder) mà biết đâu bạn có thể trở thành một người nghiên cứu, một người phát triển những ngôn ngữ, những công nghệ mới? Dài dòng một chút những chia sẻ về nghề và giờ là lúc chúng ta cùng đi vào tìm hiểu kiến thức HTML cơ bản. Theo truyền thống, một ví dụ HTML đầu tiên – Chào mừng đến với khóa học HTML cơ bản, một ví dụ đơn giản cho cái nhìn đầu tiên về HTML.

  HTML5 khác HTML như thế nào?

1. Ví dụ HTML đầu tiên – Chào mừng đến với khóa học HTML cơ bản

Trong suốt khóa học HTML cơ bản chúng ta sẽ sử dụng hai công cụ để tiện demo và show code cho các bạn là Sublime Text và JsFiddle. Ok, bạn hãy mở Sublime Text tạo một file hello-world.html với nội dung sau:

<!DOCTYPE html>
<html>
  <head>
    <meta charset=utf-8>
    <title>Ví dụ HTML đầu tiên - Chào mừng đến với Khóa học HTML cơ bản</title>
  </head>
  <body>
    <h1 class="text-success">Khóa học HTML cơ bản</h1>
    <p>Chào mừng bạn đến với khóa học HTML cơ bản từ website allaravel.com, chúng ta sẽ cùng nhau tìm hiểu từ những vấn đề cơ bản nhất của HTML và những gì mới nhất trong phiên bản HTML5.</p>
  </body>
</html>

Kết quả khi chạy file hello-world.html chúng ta được như sau:

[jsfiddle url=”https://jsfiddle.net/allaravel/808ahvjg/” height=”200px” include=”result,html,js” font-color=”39464E” menu-background-color=”FFFFFF” code-background-color=”f3f5f6″ accent-color=”1C90F3″]

Chú ý, phần kết quả thay vì chụp lại nội dung hiển thị trên trình duyệt thì chúng ta sẽ mặc định dùng JsFiddle để xem được nhanh chóng và trực quan.

Ví dụ HTML đầu tiên

Trong ví dụ HTML đầu tiên này, chúng ta tạm coi như đã biết code HTML, các phần tiếp theo sẽ diễn giải những gì đã sử dụng. Mã HTML ở trên khá nhiều nhưng khi xem trên trình duyệt, nội dung lại rất ít, còn toàn văn bản vì HTML là ngôn ngữ đánh dấu siêu văn bản, nó cho trình duyệt biết chỗ nào phải hiển thị như là tiêu đề (thẻ <h1>) và chỗ nào là đoạn văn mô tả (thẻ <p>).

2. Các khái niệm HTML cơ bản

Trong ví dụ HTML đầu tiên nếu bạn mới bắt đầu học HTML cơ bản, bạn sẽ thấy hơi hoa mắt chút nhưng đảm bảo rằng sau khi được giới thiệu các khái niệm HTML cơ bản, bạn sẽ làm chủ được đoạn code này dễ dàng.

  HTML là gì?

Cấu phần của HTML element

2.1 HTML element vs thẻ HTML

Để ý trong ví dụ HTML đầu tiên, có rất nhiều các chuỗi ký tự được mở đầu bằng < hoặc </ và kết thúc bằng >. Mỗi chuỗi ký tự đó được gọi là thẻ HTML, ví dụ <title><h1>… chúng ta gọi đây là thẻ title hoặc thẻ h1. HTML element là các thành phần của HTML, ví dụ <h1>Khóa học HTML cơ bản</h1> là thành phần h1 của HTML, nó được bắt đầu bằng thẻ mở <h1> và kết thúc bằng thẻ đóng </h1>. Vậy mỗi thành phần HTML sẽ bao gồm:

  • Thẻ mở bắt đầu bằng < và kết thúc bằng >, ví dụ <h1><p>.
  • Thẻ đóng bắt đầu bằng </ và kết thúc bằng >, ví dụ </h1></p>.

Nội dung giữa thẻ mở và thẻ đóng của một HTML element sẽ là nội dung được hiển thị trên trình duyệt, thẻ mở và thẻ đóng sẽ “đánh dấu” (markup) để trình duyệt hiểu được cụm từ “Khóa học HTML cơ bản” là tiêu đề loại lớn nhất (h1 – Heading 1).

Trong thực tế, chúng ta cũng không cần quá phân biệt HTML element với HTML tag (thẻ HTML) mà có thể gọi chung là thẻ h1, thẻ p, thẻ body… chúng ta thống nhất trong suốt Khóa học HTML cơ bản, khi nói đến thẻ HTML chúng ta coi đó là HTML element.

Như vậy trong ví dụ trên chúng ta có các thẻ HTML là html, head, title, meta, body, h1, p.

2.2 Thuộc tính của thẻ html

Trong thẻ <h1 class=”text-success”>Khóa học HTML cơ bản</h1>, chuỗi class=”text-success” là thuộc tính của thẻ HTML, nó cung cấp thông tin thêm cho thẻ HTML. Ở đây có thể có nhiều các thẻ h1 và chúng ta phân biệt các thẻ này bằng thuộc tính class, tức là các thẻ h1 có thuộc tính class là text-success sẽ được nhóm chung vào một nhóm để có thể tô màu, tăng giảm kích thước chữ, chọn font chữ sau này.

Thuộc tính của một thẻ HTML có những tính chất như sau:

  • Tất cả các thẻ HTML đều có có thể các thuộc tính.
  • Các thuộc tính cung cấp thêm các thông tin cho thẻ HTML.
  • Các thuộc tính luôn được đưa vào thẻ mở trong thẻ HTML.
  • Thuộc tính luôn đi theo cặp tên thuộc tính/giá trị thuộc tính, ví dụ class=”text-success”.

Thuộc tính class của thẻ h1 trong ví dụ trên chưa thực sự rõ ý nghĩa sử dụng do chúng ta chưa sử dụng đến thẻ này, chúng ta cùng xem một số ví dụ tiếp theo bạn sẽ hiểu rõ hơn thuộc tính trong HTML sử dụng làm gì?

Ví dụ 1: thuộc tính src của thẻ  giúp chỉ rõ đường dẫn đến ảnh cần hiển thị

<img src="public/news/anh-dep.jpg"

Ví dụ 2: thuộc tính style giúp “trang điểm” cho thẻ HTML, ví dụ này chúng ta sẽ tô màu đỏ cho thẻ h1

<h1 style="color:red">Khóa học HTML căn bản</h1>

Tham khảo việc làm lập trình viên HTML lương cao trên TopDev

3. Cấu trúc căn bản một trang HTML

Như vậy bạn đã nắm được một số khái niệm căn bản trong HTML và giờ là lúc xem lại code của ví dụ HTML đầu tiên, nó đã bớt phức tạp hơn. Trong đầu bạn hiện lại có những câu hỏi tiếp theo, các thẻ h1, p thì rõ ý nghĩa của nó rồi, còn lại một đống thẻ HTML khác để làm gì? Khoan đi vào chi tiết, bạn chỉ cần nhớ rằng, đây là cấu trúc chung của một trang HTML.

<!DOCTYPE html>
<html>
  <head>
    <meta charset=utf-8>
    <title>Tiêu đề của trang</title>
  </head>
  <body>

  </body>
</html>

Đầu tiên, trước khi khai báo các thẻ khác trong HTML chúng ta cần khai báo dạng tài liệu bằng thẻ <!DOCTYPE>, cách khai báo này là khác nhau cho các phiên bản HTML.

Trong HTML4 chúng ta khai báo nội dung tiếp theo viết theo tiêu chuẩn HTML4 bằng cách đưa cú pháp sau vào dòng đầu tiên của mã nguồn:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

Với HTML5, cách khai báo đơn giản hơn do HTML5 không còn dựa trên SGML nên không phải khai báo DTD:

<!DOCTYPE html>

Tiếp theo, toàn bộ nội dung trong thẻ <htm> chính là nội dung siêu văn bản. Trong nội dung này chúng ta nhìn bố cục sẽ có hai phần:

  • Phần đầu được khai báo bằng thẻ <head>. Trong phần này, chúng ta có thể khai báo một số vấn đề như:
    • Tiêu đề của văn bản
    • Văn bản sử dụng bảng mã ký tự nào
    • Các thông tin thêm cho văn bản chính (metadata) như thông tin tác giả, mô tả bài viết, từ khóa bài viết…
    • Các file css, javascript có thể chèn vào tại đây.
  • Phần nội dung được khai báo bằng thẻ <body>, đây là phần sẽ hiển thị trên trình duyệt.

Về bố cục một trang HTML bạn có thể nắm được như vậy, khi viết một trang HTML mới, bạn có thể sao chép cấu trúc trang HTML cơ bản này. Tiếp theo chúng ta cùng tìm hiểu cụ thể một số thẻ HTML có trong bố cục.

Thẻ title

Xác định tiêu đề của văn bản, tiêu đề này sẽ được hiển thị trong phần tab của trình duyệt giúp chúng ta nhanh chóng biết được siêu văn bản (trang web) nào đang được mở khi một trình duyệt mở nhiều trang một lúc.

Thẻ title HTML

Thẻ meta

Định nghĩa các thông tin thêm (metadata) cho tài liệu, các thông tin này bao gồm thông tin về tác giả, thông tin mô tả nội dung, thông tin từ khóa… có thể nói rằng thẻ meta mô tả thông tin của thông tin. Các thông tin của thẻ meta không hiển thị trên trình duyệt nhưng các bộ máy khác có thể sử dụng chúng, ví dụ bộ máy tìm kiếm Google, Bing, Facebook sẽ sử dụng các thông tin từ thẻ meta để phân loại nội dung trang web. Có duy nhất thẻ meta nhưng lại khai báo được nhiều các thông tin về metadata là do chúng ta có thể sử dụng các thuộc tính khác nhau:

  <meta charset="UTF-8">
  <meta name="description" content="HTML5 là phiên bản mới nhất của ngôn ngữ HTML, những bài viết trong khóa học HTML5 cơ bản giúp bạn xây dựng website nhanh chóng.">
  <meta name="keywords" content="HTML5,khóa học HTML,HTML cơ bản">
  <meta name="author" content="FirebirD[Kiên Đặng]">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

Thẻ meta đầu tiên thiết lập bảng mã sử dụng, UTF-8 (8-bit Unicode Transformation Format – Định dạng chuyển đổi Unicode 8-bit) là bộ mã hóa ký tự dành cho Unicode, nó có thể tương thích ngược với bảng mã ASCII. UTF-8 là bộ mã phổ biến và thông dụng cho các nội dung điện tử như các file tài liệu, thư điện tử, trang web và các phần mềm xử lý văn bản. Với phiên bản HTML4 trở xuống, để thiết lập bảng mã ký tự phải sử dụng thuộc tính http-equiv kết hợp với content.

<meta http-equiv="content-type" content="text/html; charset=UTF-8">

Ba thẻ meta tiếp theo mô tả thông tin về trang web, nó giúp các bộ máy tìm kiếm như Google, Bing phân loại nội dung, các thẻ này tuy không hiển thị nhưng cực kỳ quan trọng khi bạn muốn website của mình có thứ hạng cao trong kết quả tìm kiếm của Google.

Thẻ meta cuối cùng cho phép các nhà thiết kế điều khiển được khung hiển thị, tính năng này chỉ có ở HTML5. Khung hiển thị là vùng có thể nhìn thấy của người dùng trên một trang web, nó phụ thuộc vào kích thước màn hình các thiết bị khác nhau, ví dụ các thiết bị di động thông minh hiện rất phổ biến nhưng màn hình nó khá nhỏ nên cần trình bày lại sao cho đọc được nội dung dễ dàng.

  Tổng hợp 50+ thẻ HTML phổ biến nhất

4. Thành phần thẻ HTML có ngữ nghĩa

Các thẻ HTML được chia ra thành hai loại:

  • Semantic element là các thẻ có ngữ nghĩa, ví dụ thẻ <form><table><img>
  • Non-semantic element: các thẻ không có ngữ nghĩa, ví dụ <div><span>

Các phiên bản HTML mới sẽ có nhiều hơn các thẻ có ngữ nghĩa vì khi sử dụng các thẻ này có nhiều lợi ích:

  • Dễ dàng chỉnh sửa và duy trì: Với các thẻ không ngữ nghĩa khó phân tách lại phần đánh dấu bằng các thẻ, do đó rất khó để hiểu được bố cục tổng thể và ý nghĩa các thành phần.
  • Tăng khả năng truy xuất: các trang web hiện đại viết bằng HTML5 có khả năng điều hướng thông qua các liên kết, menu tốt hơn chỉ bằng các công cụ cơ bản do nó đưa ra thành phần HTML mới là <nav> thay cho việc dùng các thẻ <div>.
  • Tốt hơn cho bộ máy tìm kiếm: đây là một trong những lợi ích lớn nhất, bạn muốn trang web của mình được nhiều người biết đến thông qua các kết quả tìm kiếm, việc sử dụng các thẻ có ngữ nghĩa giúp Google nhanh chóng phân tích được nội dung một cách chính xác và tối ưu hóa cho bộ máy tìm kiếm.
  • Thích hợp cho các trình duyệt tương lai: các trình duyệt mới và công cụ thiết kế web mới sẽ tận dụng các thông tin về ngữ nghĩa.

4.1 Sự tiến hóa trong HTML5

Trong HTML5 xuất hiện nhiều hơn các thẻ HTML có ngữ nghĩa, ví dụ như <header><footer><nav><article>… tại sao vậy, sự tiến hóa của HTML là tất yếu khách quan khi mà nhu cầu tạo ra các thành phần cơ bản của một trang HTML ngày càng lớn. Quay ngược lại hơn 10 năm trước, những khảo sát về HTML giúp ta có được câu trả lời.

Năm 2004, một thành viên nhóm soạn thảo đặc tả HTML5, Ian Hickson đã làm một thống kê trên một tỉ trang web thông qua hệ thống chỉ mục của Google để tìm xem thực tế cách tạo ra các trang web. 5 năm sau đó, Opera MAMA cũng thực hiện một việc tương tự nhưng với các thuộc tính class của thẻ HTML từ ngẫu nhiên hơn 2 triệu đường dẫn và kết quả như sau:

STT Giá trị thuộc tính class Tần suất lặp lại
1 footer 179,528
2 menu 146,673
3 style1 138,308
4 msonormal 123,374
5 text 122,911
6 content 113,951
7 title 91,957
8 style2 89,851
9 header 89,274
10 copyright 86,979
11 button 81,503
12 main 69,620
13 style3 69,349
14 small 68,995
15 nav 68,634
16 clear 68,571
17 search 59,802
18 style4 56,032
19 logo 48,831
20 body 48,052

Bảng kết quả tiếp theo khi thống kê thuộc tính id của thẻ HTML từ 1.5 triệu đường dẫn ngẫu nhiên:

STT Giá trị thuộc tính id Tần suất lặp lại
1 footer 288,061
2 content 228,661
3 header 223,726
4 logo 121,352
5 container 119,877
6 main 106,327
7 table1 101,677
8 menu 96,161
9 layer1 93,920
10 autonumber1 77,350
11 search 74,887
12 nav 72,057
13 wrapper 66,730
14 top 66,615
15 table2 57,934
16 layer2 56,823
17 sidebar 52,416
18 image1 48,922
19 banner 44,592
20 navigation 43,664

Từ các thống kê này, trong HTML5 người ta thấy rằng cần thiết phải đưa vào thêm một số các thẻ HTML có ngữ nghĩa mới như nav, header, footer… Những thẻ HTML có ngữ nghĩa mới này đã làm thay đổi cấu trúc trang HTML cơ bản. Nếu các bạn có điều kiện thực hiện các trang web từ những năm đầu của thế kỷ 21 có thể thấy cách cấu trúc đã có những đợt thay đổi như sau:

  • 2000-2005: Sử dụng thẻ table để cấu trúc trang HTML
  • 2005-2010: Sử dụng thẻ div để cấu trúc trang HTML
  • 2010 đến nay: Sử dụng các thẻ HTML có ngữ nghĩa mới trong HTML5 để cấu trúc trang.

Các ví dụ tiếp theo đây cho thấy được những thay đổi đáng kể trong cách cấu trúc trang HTML, đầu tiên chúng ta xem xét cách cấu trúc dùng thẻ div

Cấu trúc trang HTML sử dụng thẻ div

<div id="header">
  <h1>Khóa học HTML5 cơ bản</h1>
</div>
<div id="sidebar">
  <h2>Menu</h2>
  <ul>
    <li><a href="html5-introduction.html">Chương I: Giới thiệu HTML5</a></li>
    <li><a href="html5-contruction.html">Chương II: Cấu trúc trang HTML</a></li>
    <li><a href="html5-form.html">Chương III: Xây dựng form nhập liệu</a></li>
  </ul>
</div>
<div class="post">
  <h2>HTML5 là gì?</h2>
  <p>Ngôn ngữ HTML5 giúp tạo ra các trang web một cách nhanh chóng đáp ứng được các nhu cầu thực tế.</p>
</div>
<div class="post">
  <h2>Cấu trúc trang HTML cơ bản</h2>
  <p>HTML5 đã có những cải tiến thay đổi cách cấu trúc trang HTML bằng semantic element.</p>
</div>
<div id="footer">
  <p><small> Bản quyền thuộc về Allaravel.com. 2018</small></p>
</div>

Với việc thêm vào các thẻ HTML có ngữ nghĩa mới trong HTML5, cấu trúc trang HTML đã thay đổi đáng kể:

Cấu trúc trang HTML sử dụng thẻ HTML có ngữ nghĩa

Mã HTML cũng có những thay đổi

<header>
  <h1>Khóa học HTML5 cơ bản</h1>
</header>
<nav>
  <h2>Menu</h2>
  <ul>
    <li><a href="html5-introduction.html">Chương I: Giới thiệu HTML5</a></li>
    <li><a href="html5-contruction.html">Chương II: Cấu trúc trang HTML</a></li>
    <li><a href="html5-form.html">Chương III: Xây dựng form nhập liệu</a></li>
  </ul>
</nav>
<article>
  <h2>HTML5 là gì?</h2>
  <p>Ngôn ngữ HTML5 giúp tạo ra các trang web một cách nhanh chóng đáp ứng được các nhu cầu thực tế.</p>
</article>
<article>
  <h2>Cấu trúc trang HTML cơ bản</h2>
  <p>HTML5 đã có những cải tiến thay đổi cách cấu trúc trang HTML bằng semantic element.</p>
</article>
<footer>
  <p><small> Bản quyền thuộc về Allaravel.com. 2018</small></p>
</footer>

4.2 Trình duyệt không tương thích với HTML5

Thật may là các thẻ HTML có ngữ nghĩa trong HTML5 được hỗ trợ diện rộng trên các trình duyệt web hiện đại, rất khó để có thể tìm thấy các phiên bản Chrome, Firefox, Safari hoặc Opera không hỗ trợ. Nhưng không phải là không có những ngoại lệ, ví dụ các phiên bản Internet Explorer trước IE9 là gặp vấn đề với HTML5.

Khi một trình duyệt không phát hiện ra các thẻ HTML mới, nó sẽ xử lý các thẻ này như một inline element và không hiển thị chúng như các khối (block), để khắc phục vấn đề này, bạn cần thêm một ít code CSS vào:

article, aside, figure, span, footer, header, main, nav, section, summary { 
  display: block; 
}

Code CSS này không ảnh hưởng gì với các trình duyệt có thể nhận diện được thẻ HTML5. Kỹ thuật này là đủ để giải quyết vấn đề tương thích với hầu hết các trình duyệt, tuy nhiên với IE8 hoặc phiên bản thấp hơn thì có một thách thức khác: Các trình duyệt này từ chối áp dụng định dạng CSS cho các thẻ HTML mà chúng không thể nhận ra. Với vấn đề này chúng ta xử lý bằng cách đưa vào một đoạn mã Javascript giúp IE có thể nhận ra và style các thẻ HTML:

<script>
  document.createElement(‘header’);
  document.createElement(‘nav’);
  document.createElement(‘article’);
  document.createElement(‘footer’);
</script>

Nhóm phát triển Google cũng đưa ra một giải pháp riêng tổng thể hơn với một thư viện Javascript giúp cho mọi trình duyệt không hỗ trợ HTML5 có thể hoạt động được.

<head>
  <!--[if lt IE 9]> 
  <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> 
  <![endif]-->
</head>

5. Các thẻ HTML mới trong HTML5

5.1 Thẻ HTML5

Thẻ <header> xác định tiêu đề cho một trang hoặc một phần của trang, thẻ được sử dụng như một “khung chứa” cho các nội dung giới thiệu hoặc có thể bao gồm cả các điều hướng trang. Thẻ <header> không bắt buộc phải có trong trang và có thể có nhiều thẻ <header> trong một trang.

Trong hầu hết các trang web, thành phần đầu tiên thường là tiêu đề, nó có thể chứa tiêu đề của website, hình ảnh logo, các liên kết đến trang chủ… Thẻ <header> có thể chứa các thẻ tiêu đề từ h1 đến h6 hoặc một thẻ <hgroup> để nhóm các tiêu đề ở các mức khác nhau nhưng không bắt buộc. Thực tế khi xây dựng website, thành phần <header> có thể được sử dụng để tạo ra bảng nội dung, form tìm kiếm, phần logo trang…

<header>
  <a href="/"><img src=logo.png alt="Trang chủ"></a>
  <h1>Khóa học HTML5 cơ bản</h1>
</header>

Hoặc bạn có thể sử dụng <hgroup> để nhóm các tiêu đề với nhau:

<header>
  <a href="/"><img src=logo.png alt="Trang chủ"></a>
  <hgroup>
    <h1>Khóa học HTML5 cơ bản</h1>
    <h2>15 bài lý thuyết, có bài tập thực hành, câu hỏi trắc nghiệm.</h2>
  </hgroup>
</header>

Đôi khi tiêu đề cũng có thể chứa các thành phần điều hướng đặc biệt khi thiết kế website kiểu master template có một mẫu cho tất cả các trang. Ví dụ:

<header>
  <hgroup>
    <h1>Khóa học HTML5 cơ bản</h1>
    <h2>15 bài lý thuyết, có bài tập thực hành, câu hỏi trắc nghiệm.</h2>
  </hgroup>
  <nav>
    <ul>
      <li><a href="/">Trang chủ</a></li>
      <li><a href="html5-basic.html">HTML5 cơ bản</a></li>
      <li><a href="html5-advance.html">HTML5 nâng cao</a></li>
    </ul>
  </nav>
</header>

Chú ý, thẻ <nav> không bắt buộc phải có trong <header> và hoàn toàn có thể đưa thẻ này ra khỏi thẻ <header>. Nó phụ thuộc vào thiết kế bố cục của website, độ lớn các menu điều hướng. Trong ví dụ tiếp theo, chúng ta không thể đưa thẻ

Template Method Pattern – Khuôn mẫu cho tất cả

Template Method Pattern

Bài viết được sự cho phép của tác giả Edward Thien Hoang

Chào mọi người, hôm nay mình sẽ tiếp tục loạt bài về Design Pattern với một pattern mới: Template Method Pattern. Từ template làm chúng ta liên tưởng đến các template trong thiết kế web, khi chúng ta có 1 trang template đã có sẵn header, footer, navigation, chỉ riêng phần boby là để trống và sẽ display nội dung theo từng page. Nghĩa là chỉ có phần body là sẽ thay đổi theo từng page, còn các phần khác sẽ giống nhau cho tất cả các page. Trừ 1 số page đặc biệt mà nội dung của header, footer, navigation sẽ thay đổi. Việc làm này sẽ giúp giảm thiểu các công việc giống nhau ở nhiều nơi. Thay vì phải viết tất cả các thành phần ở mỗi page, thì bây giờ các thành phần chung sẽ được gom lại và đặt trong một template.

  Factory Pattern - Nhà máy của những đối tượng
  Giải thích Flux Pattern theo phong cách John Wick

Trong lập trình, khái niệm template cũng tương tự như vậy. Nếu các bạn đã từ sử dụng từ khóa abstract trong Java thì khả năng cao là chính các bạn cũng đang sử dụng mẫu template này đấy.

Hãy cụ thể hóa bài toán web template ở trên vào ngôn ngữ lập trình minh họa bằng Java.

Đầu tiên hãy xây dựng một lớp PageTemplate

PageTemplate.java

package behavior.templatemethod;

public abstract class PageTemplate {

protected void displayHeader() {
System.out.println("HEADER");
}

protected void displayNavigation() {
System.out.println("NAVIGATION");
}

protected void displayFooter() {
System.out.println("FOOTER");
}

/**
* Let each subclass define it own content
* @author Edward
*/
protected abstract void displayBody();

/**
* Display all content of web page
* @author Edward
*/
public void displayWebPage() {
displayHeader();
displayNavigation();
displayBody();
displayFooter();
}
}

Lớp PageTemplate đã có sẵn các phương thức để hiển thị các thành phần header, footer, navigation. Riêng phương thức displayBody sẽ là abstract method, các trang khác nhau sẽ có nội dung hiển thị khác nhau. Sau đó cùng hiển thị tất cả lên màn hình theo một thứ tự đã cho trước trong hàm displayWebPage. Bây giờ hãy tạo ra 1 số trang sử dụng template này.

DesignPatternPage.java

package behavior.templatemethod;

public class DesignPatternPage extends PageTemplate {
@Override
protected void displayBody() {
System.out.println("DESIGN PATTERN CONTENT");
}
}

Java8TutorialPage.java

package behavior.templatemethod;

public class Java8TutorialPage extends PageTemplate {
@Override
protected void displayBody() {
System.out.println("JAVA 8 TUTORIAL CONTENT");
}
}

ContactPage.java

package behavior.templatemethod;

public class ContactPage extends PageTemplate {
@Override
protected void displayBody() {
System.out.println("ABOUT CONTENT");
}

@Override
protected void displayNavigation() {
// We do NOT want to display Navigation here
// Just do nothing
}
}

Các lớp trên đều kế thừa từ lớp PageTemplate. Chúng có một yêu cầu bắt buộc là phải implement lại method displayBody để hiển thị nội dung cho từng trang. Riêng có lớp ContactPage sẽ implement lại method displayNavigation để không hiển thị gì. Viết một lớp để test tất cả:

TemplateMethodTest.java

package behavior.templatemethod;

public class TemplateMethodTest {

public static void main(String[] args) {
PageTemplate designPattern = new DesignPatternPage();
designPattern.displayWebPage();

System.out.println();

PageTemplate java8Tutorial = new Java8TutorialPage();
java8Tutorial.displayWebPage();

System.out.println();

PageTemplate contact = new ContactPage();
contact.displayWebPage();
}

}

Kết quả khi output:

HEADER
NAVIGATION
DESIGN PATTERN CONTENT
FOOTER

HEADER
NAVIGATION
JAVA 8 TUTORIAL CONTENT
FOOTER

HEADER
ABOUT CONTENT
FOOTER

Cùng xem qua Class diagram mối quan hệ giữa các class với nhau

TemplateMethod_ClassDiagram

Như ta thấy, tất cả các page sẽ đều có chung các thành phần trong template đã định nghĩa, chúng chỉ cần implement lại những thành phần mà CHỈ CÓ RIÊNG nó mới quyết định được. Vậy nguyên lý của Template Method pattern này là: Đặt tất cả những xử lý chung trong lớp cha, sau đó định nghĩa các hàm abstract và để các lớp con tự định nghĩa lấy. Việc này sẽ giảm thiểu sự trùng lặp code và dễ dàng bảo trì về sau khi mỗi lớp con cần có sự thay đổi.

Các bạn có thể tham khảo thêm các bài viết về Design Pattern trong Series về Design Pattern

Bài viết gốc được đăng tải tại edwardthienhoang.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Cách học một công nghệ mới

Cách học một công nghệ mới

Bài viết được sự cho phép của tác giả Tino Phạm

Trong bài này, mình xin chia sẽ cách học của mình khi tiếp cận một công nghệ mới. Bạn có thể tham khảo và chia sẽ lại với mình về cách học của bạn.

  "Khi công nghệ không chỉ dành cho nam giới" - Lea Trúc, Founder của Women Meet Tech

  10 bí kíp để startup và FinTech startup thành công đột phá

Bước 1: đọc và làm theo chính xác những gì người khác hướng dẫn. Làm đúng theo từng bước của họ. Đảm bảo chúng ta phải chạy được giống như những gì họ đã làm.

Bước 2: xem lại code đã viết và đặt câu hỏi tại sao? và nó có nghĩa gì? Từ đó đọc lại hướng dẫn và search google để tìm hiểu để giúp bạn hiểu rõ hơn những gì bạn đã làm.

Bước 3: đập hết mọi thứ và làm lại từ đầu. Lúc này bạn cần thống kê lại mình sẽ làm gì?làm thế nào?. Liệt kê các bước thực hiện. Trong quá trình làm lại bạn sẽ gặp phải lỗi, bạn tìm cách fix nó, từ đó sẽ giúp bạn hiểu rõ hơn vấn đề và giúp bạn có thêm kinh nghiệm với công nghệ mới mà bạn đang học.

Bước 4: Lặp lại bước 1 tới bước 3 với nhiều projects khác nhau hoặc trên cùng một project càng nhiều càng tốt.

Bước 5: Tiến hành hoàn thiện và nâng cập cho những projects mà bạn đã thực tập (Refactor, optimize, improve code,…).

Trên đây là các bước mà mình thường sử dụng khi học một công nghệ mới. Hy vọng được các bạn chia sẽ thêm về cách học của các bạn.

Bài viết gốc được đăng tải tại thangphampt.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Đọc ghi file trên Node.js

Đọc ghi file trên Node.js

Bài viết được sự cho phép của smartjob.vn

Bài này mình giới thiệu về phần đọc ghi file .Trong Node js có nét mới là đọc ghi file khác so với PHP có 2 chế độ là : Đồng bộ và không đồng bộ ( hay có khái niệm mới Synchronous vs Asynchronous).Asynchronous :bất đồng bộ khi tiến trình bắt đầu chạy thì tất cả cách lệnh cùng chạy và Synchronous :đồng bộ khi tiến trình chạy thì các câu lệnh được đọc  trình tự từ trên xuống dưới.

  10 Công ty hàng đầu thế giới sử dụng Node.js
  Ghi chú file package.json của node module

Bắt đầu ví dụ : tạo 2 file : file.js và sample.txt trong thư mục  E:\file_nodejs như sau :

1. Asynchronous

đọc ghi file bất đồng bộ tiến trình bắt đầu tất cả các dòng lệnh cùng chạy 

Nội dung trong file : file.js

Nội dung trong file : example.txt

Sau đó cmd mở của sổ lênh command line trỏ tới thư mục chứa file file.js và gõ lệnh:

Màn hình sẽ hiển thị lên:

Ghi file bất  đồng bộ cũng tương tự  tạo file writefile.js có nội dung như sau :

Sau đó cmd mở của sổ lênh command line trỏ tới thư mục chứa file writefile.js và gõ lệnh:

Mở file sample.txt  sẽ có nội dung như sau :

2. Synchronous đọc ghi file đồng bộ (tuần tự từ trên xuống)

Cũng làm tương tự với đọc file  nhưng code 2 file file.js và writefile.js như sau

file writefile.js nội dung:

Trên là hướng dẫn trên môi trường window với các cài riêng gói node.js

skype: nguyenanhdung90

Bài viết gốc được đăng tải tại smartjob.vn

Xem thêm Việc làm nodeJS hấp dẫn trên TopDev

Tìm việc làm IT Đà Nẵng, Hồ Chí Minh, Hà Nội mới nhất

Facade Pattern – Đơn giản hóa tất cả

facade pattern

Bài viết được sự cho phép của tác giả Edward Thien Hoang

FACADE PATTERN

Chào mọi người, hôm nay mình sẽ tiếp tục loạt bài về Design Pattern với một pattern mới: Facade Pattern. Cái tên nghe rất lạ nhưng khi bước vào implement, các bạn sẽ thấy đây là mẫu pattern gần gũi và được sử dụng nhiều nhất trong chương trình.

  Các loại Design patterns
  Design pattern là gì? Tại sao nên sử dụng Design pattern?

ĐỊNH NGHĨA

Nói một cách đơn giản như chính việc implement pattern này, giúp Client đơn giản hóa các lời gọi hàm từ nhiều object khác nhau bằng cách cung cấp 1 interface đơn giản hơn để Client làm việc. Điều này giúp đơn giản hóa và giảm độ phụ thuộc của Client đến các object bên trong.

Hình phía dưới sẽ minh họa cho điều mình vừa nói ở trên:

facade

Các Client thay vì phải gọi vào nhiều component phía trong, đối tượng Facade sẽ đảm nhiệm việc đó và cung cấp các interface đơn giản hơn đến Client.

VÍ DỤ

Hãy lấy một ví dụ có sẵn trong Java Swing, lớp javax.swing.JOptionPane:

facade_advanced2

JOptionPane được thiết kế như một đối tượng Facade. Thay vì phải gọi trực tiếp đến các lớp phía trong như: JDialog, BorderFactory, Panel… để tạo ra các dialog như: Confirm, Input, Message and OptionDialogs. Thì bây giờ chỉ cần thông qua JOptionPane, nó sẽ giúp chúng ta làm chuyện đó.

Dưới đây là 1 ví dụ nếu không sử dụng JOptionPane

...
JFrame frame = new JFrame("My Message Dialog");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Quit");
JLabel label = new JLabel("This is My Message Dialog!");

ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
System.exit(0);
}
};

button.addActionListener(actionListener);
Container contentPane = frame.getContentPane();
contentPane.add(label, BorderLayout.CENTER);
contentPane.add(button, BorderLayout.SOUTH);
frame.setSize(300, 200);
frame.setVisible(true);
...

Quá phức tạp và quá nhiều phụ thuộc. Nếu sử dụng JOptionPane như là 1 Facade thì mọi chuyện sẽ chỉ đơn giản như dưới đây:

...
JOptionPane optionPane = new JOptionPane(
"This Dialog is generated by the JOptionPane Facade!",
JOptionPane.OK_OPTION);
// OR
JDialog dialog = optionPane.createDialog(frame.getContentPane(),
"JOptionPane Message Dialog");
dialog.setVisible(true);
...

Kết thúc bài viết về Facade Pattern tại đây. Các bạn chỉ cần nhớ 1 điều, khi có nhiều lời gọi qua nhiều lớp đối tượng hãy nghĩ đến Facade để đơn giản hóa chúng, mọi thay đổi trong các lời gọi hàm sẽ được thực hiện trong lớp Facade mà không ảnh hưởng đến chương trình.

Có một mẫu design cũng gói lại nhiều lớp đối tượng để đưa ra những xử lý đơn giản hơn đó là Mediator Pattern. Trong khi Facade Pattern hướng đến việc cung cấp những API đơn giản hơn từ đến Client, thì Mediator sẽ dùng cho mục đích khác, tách biệt nhiều xử lý phức tạp trong các lớp đối tượng, và có thể thêm hoặc bớt bất cứ thành phần nào trong đó. Cùng đọc về Mediator Pattern để đưa ra sự so sánh chính xác nhất với 2 Pattern này.

Các bạn có thể tham khảo thêm các bài viết về Design Pattern trong Series về Design Pattern

Bài viết gốc được đăng tải tại edwardthienhoang.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Ngắm và bắn với thuộc tính watch trong Vue instance

Ngắm và bắn với thuộc tính watch trong Vue instance

Bài viết được sự cho phép của tác giả Kien Dang Chung

Trong lập trình chúng ta thấy các ứng dụng là sự tác động qua lại giữa dữ liệu và các phương thức xử lý dữ liệu, với góc nhìn này chúng ta thấy được lý do tại sao có các thành phần trong Vue instance như data, methods, computed. Từ đây một câu hỏi được đặt ra, còn thành phần nào liên quan đến dữ liệu và phương thức xử lý dữ liệu? Để trả lời câu hỏi này, bạn hãy cùng tôi rà soát các vấn đề cần làm xung quanh dữ liệu:

  10 kinh nghiệm khi làm việc với các dự án lớn viết bằng Vue.js
  3 phút làm quen với Vue.js

Vue instance

  • Dữ liệu và tự bản thân nó thể hiện trong phần data, trong hệ thống reactivity.
  • Tính toán, thao tác với dữ liệu đã có các computed property.
  • Với mỗi dữ liệu, thực hiện các phương thức riêng đã có methods.
  • Sự thay đổi của dữ liệu dẫn đến các thao tác đặc biệt thì xử lý thế nào?

Vấn đề cuối cùng có thể xử lý bằng computed property nhưng đây là các thuộc tính nên nó không có tham số đầu vào, chính vì vậy có một khái niệm nữa là watcher là những “đơn vị giám sát” dữ liệu trong thành phần data của Vue instance và thực hiện những công việc cần thiết để bổ sung công cụ cho chúng ta khi viết ứng dụng.

1. Watcher là gì trong framework Vue.js?

Đúng như tên gọi của nó, watcher giám sát các thay đổi trong một đối tượng, sử dụng watcher có thể có cùng kết quả với các giá trị được tính toán trước trong computed property nhưng với watcher nó phức tạp hơn. Chúng ta thường sử dụng watcher với những tình huống đòi hỏi phải xử lý phức tạp như:

  • Các hoạt động bất đồng bộ đáp ứng lại việc thay đổi dữ liệu
  • Các thiết lập giá trị ngay lập tức
  • Hạn chế số lần thực hiện phương thức khi dữ liệu thay đổi.

Watcher có thể được khai báo trong thành phần watch của Vue instance, cú pháp như sau:

  new Vue({
    el: '#app',
    data: {
      // Dữ liệu gán với view
    },
    watch: {
      // Các hoạt động bất đồng bộ muốn thực hiện khi dữ liệu thay đổi
    }
  });

Trong ví dụ tiếp theo, chúng ta xây dựng một ứng dụng giả lập công cụ tìm kiếm trực tuyến mà mỗi khi gõ vào một chuỗi truy vấn tìm kiếm ngay lập tức có câu trả lời. Hoạt động của ứng dụng này như sau, ứng dụng liên tục kiểm tra xem có sự thay đổi trong ô nhập truy vấn tìm kiếm hay không, nếu có nó sẽ gửi từ khóa đến một API để lấy câu trả lời. Chúng ta sẽ khai báo một phương thức giám sát (watcher) ô tìm kiếm.

<!DOCTYPE html>
<html>
<head>
    <title>Watcher Vue.js - allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
    <div class="container" id="app">
        <input class="form-control" type="text" @input="isTyping = true" v-model="searchQuery">
        <p v-if="isTyping">Đang tìm kiếm...</p>
        <div v-else>
            <ul class="list-group">
                <li class="list-group-item" v-for="result in results">{{ result }}</li>
            </ul>
        </div>
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.min.js"></script>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data: {
                searchQuery: '',
                results: [],
                isTyping: false
            },
            watch: {
                searchQuery: function(query) {
                    console.log(query);
                    var vm = this;
                    setTimeout(function() {
                        console.log('setTimeout call');
                        vm.results = ['Vue.js', 'React', 'Angular 2'];
                        vm.isTyping = false;
                    }, 1000);
                } 
            }
        });
    </script>
</body>
</html>

Đoạn mã trên là rất dễ hiểu với một View có một ô nhập liệu được gán dữ liệu hai chiều với một Model là searchQuery thông qua v-model (Xem lại Gán dữ liệu hai chiều với v-model nếu bạn chưa biết về v-model). Trên ô nhập liệu này chúng ta cũng kiểm tra sự kiện nhập liệu để có thông báo lên “Đang tìm kiếm…” thông qua v-on:input và viết tắt thành @input (Xem thêm Quản lý sự kiện với v-on).

    <div class="container" id="app">
        <input class="form-control" type="text" @input="isTyping = true" v-model="searchQuery">
        <p v-if="isTyping">Đang tìm kiếm...</p>
        <div v-else>
            <ul class="list-group">
                <li class="list-group-item" v-for="result in results">{{ result }}</li>
            </ul>
        </div>
    </div>

Kết quả tìm kiếm được hiển thị trong một danh sách được đưa vào thẻ <ul> với directive v-for duyệt qua các kết quả và hiển thị từng kết quả trong thành phần danh sách <li>.

Tiếp đến là phần quan trọng nhất trong đoạn code này, giám sát sự thay đổi của searchQuery và truyền chuỗi truy vấn người dùng nhập vào đến API xử lý.

watch: {
    searchQuery: function(query) {
        var vm = this;
        setTimeout(function() {
            vm.results = ['Vue.js', 'React', 'Angular 2'];
            vm.isSearching = false;
        }, 1000);
    }
}

Ở đây chúng ta đưa vào hàm setTimeout với thời gian chờ là 1 giây để giả lập thời gian xử lý truy vấn từ API, sau 1 giây kết quả trả về là một mảng tên các framework Javascript. Khi sử dụng hàm setTimeout có một chú ý là biến this sẽ trỏ đến đối tượng window chứ không phải trỏ đến Vue instance như chúng ta mong muốn. Như vậy chúng ta cần sao chép Vue instance sang một biến khác để tham chiếu bên trong hàm setTimeout().

Chương trình chạy ok nhưng có một vấn đề xảy ra, có quá nhiều lời gọi đến setTimeout không cần thiết khi mà người dùng gõ quá nhanh. Chúng ta cùng tìm hiểu vấn đề này:

Watcher Vuejs

Có quá nhiều lời gọi setTimeout trong một khoảng thời gian quá ngắn khi mà người dùng đang gõ chuỗi truy vấn, làm thế nào để khắc phục vấn đề này? Đây là một vấn đề rất hay gặp phải khi xử lý các đoạn mã bất đồng bộ. Chúng ta sử dụng đến hàm _.debound() là một hàm trong bộ thư viện lodash, nó cho phép ngừng một thời gian và chỉ gọi phương thức xử lý một lần sau khoảng thời gian đó. Code khi sử dụng lodash như sau:

<!DOCTYPE html>
<html>
<head>
    <title>Watcher Vue.js - allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
    <div class="container" id="app">
        <input class="form-control" type="text" @input="isSearching = true" v-model="searchQuery">
        <p v-if="isSearching">Searching...</p>
        <div v-else>
            <ul class="list-group">
                <li class="list-group-item" v-for="result in results">{{ result }}</li>
            </ul>
        </div>
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.5/lodash.min.js"></script>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data: {
                searchQuery: '',
                results: [],
                isSearching: false
            },
            watch: {
                searchQuery: _.debounce(function (query) {
                    console.log(query);
                    this.results = ['Vue.js', 'React', 'Angular 2'];
                    this.isSearching = false;
                }, 1000) 
            }
        });
    </script>
</body>
</html>

Watcher Vuejs sử dụng hàm debound trong lodash

Bạn thấy đấy, watcher này vẫn giám sát sự thay đổi của searchQuery nhưng chỉ thực sự xử lý khi phương thức này tạm dừng một giây, tức là khi nào người dùng ngừng gõ 1 giây thì mới gửi chuỗi truy vấn đến API để xử lý. Với cách xử lý này, nó giúp cho hạn chế số lượng lời gọi đến API mà vẫn cho kết quả cuối cùng, các lời gọi khác do xử lý quá nhanh nên chưa kịp cho ra kết quả đã phải xử lý tiếp theo gây dư thừa xử lý trên phía máy chủ cung cấp API.

2. Tham số đầu vào của watcher

Trong ví dụ trên chúng ta thấy watcher cho searchQuery có tham số đầu vào là query chính là chuỗi truy vấn người dùng nhập vào, đây là giá trị mới nhất của searchQuery. Chúng ta cũng có thể lấy lại giá trị trước đó của searchQuery thông qua tham số thứ hai của watcher.

watch: {
    searchQuery: function(newVal, oldVal) {
        console.log(newVal);
        console.log(oldVal);
    }
}

Tham số đầu tiên của watcher là newVal sẽ chứa giá trị mới nhất của thuộc tính đang được “giám sát”, tham số thứ hai oldVal chứa giá trị trước khi có thay đổi của thuộc tính được giám sát. Watcher cũng có thể chỉ có một tham số đầu vào.

watch: {
    searchQuery: function(newVal) {
        console.log(newVal);
    }
}

3. Giám sát thuộc tính được lồng bên trong đối tượng

Đối tượng trong thành phần data của Vue instance có thể rất phức tạp với các thuộc tính được lồng ở cấp sâu hơn, ví dụ:

data: {
    person: {
        name: 'Nguyễn Văn A',
        drivingLicense: {
            id: 'GPLX0393928282',
            issueDate: '20180417',
            issueBy: 'Bộ GTVT'
        }
    }
}

Khi đó nếu chúng ta muốn giám sát thuộc tính issueDate thì sử dụng cú pháp tham chiếu đến thuộc tính thông qua dấu chấm.

watch: {
    'person.drivingLicense.issueDate': function(newVal, oldVal) {
        alert('Giấy phép được gia hạn từ ' + oldVal + ' sang ' + newVal);
    }
}

Nếu bạn không muốn sử dụng cách tham chiếu với dấu chấm và dấu nháy đơn có thể gói nó vào trong một computed property:

computed: {
    licenseIsUpgrade() {
        return this.person.drivingLicense.issueDate;
    }
},
watch: {
    licenseIsUpgrade: function(newVal, oldVal) {
        alert('Giấy phép được gia hạn từ ' + oldVal + ' sang ' + newVal);
    }
}

Trên đây chúng ta mới chỉ giám sát sự thay đổi của các thuộc tính trong một đối tượng, nếu giám sát cả đối tượng thì thế nào? Trong watcher có thể khai báo mức độ giám sát thông qua thuộc tính deep.

watch: {
    'person': {
        handler: function (newVal, oldVal) {
            console.log('Giám sát đối tượng', ' giá trị cũ: ', newVal, ' giá trị cũ:', oldVal)
        },
        deep: true
    }
}

Khi đó bất kể thành phần nào của đối tượng person thay đổi thì watcher đều nhìn thấy. Chú ý, với ví dụ này newVal và oldVal sẽ cùng giá trị bởi vì khi thay đổi đối tượng hoặc mảng, Vue không giữ bản sao của giá trị trước đó. Cả hai tham số sẽ cùng tham chiếu đến cùng một đối tượng hoặc mảng, bởi vậy khi viết code liên quan đến giá trị cũ và mới của đối tượng hoặc mảng chúng ta phải có thêm phần xử lý.

data: {
    person: {
        name: 'Nguyễn Văn A',
        drivingLicense: {
            id: 'GPLX0393928282',
            issueDate: '20180417',
            issueBy: 'Bộ GTVT'
        }
    }
}
computed: {
    clonePerson: function() {
        return JSON.parse(JSON.stringify(this.person));
    }
},
watch: {
    clonePerson: function(newVal, oldVal) {
        alert(JSON.stringify(newVal));
        alert(JSON.stringify(oldVal));
    }
}

4. Thêm hoặc hủy bỏ các watcher trong khi chạy ứng dụng

Khi khai báo các watcher chúng ta khai báo trong Vue Instance, vậy nếu chúng ta muốn thêm các watcher hoặc hủy bỏ chúng đi ở bên ngoài thực thể Vue thì sao? Bạn hoàn toàn yên tâm, Vue instance có biến $watch giúp bạn thực hiện công việc này.

<!DOCTYPE html>
<html>
<head>
    <title>Watcher Vue.js - allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
    <div class="container" id="app">
        <p>Counter: {{ counter }}</p>
        <button @click="counter++">Tăng bộ đếm</button>
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.min.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el: '#app',
            data: {
                counter: 1
            }
        });
        vm.$watch('counter', function(newValue, oldValue) {
            alert('Bộ đếm tăng từ ' + oldValue + ' lên ' + newValue + '!');
        });
    </script>
</body>
</html>

Với watcher được thêm vào ở ngoài Vue instance cũng có tham số để thiết lập xem chúng ta giám sát cả đối tượng hay không?

vm.$watch('person', function(newVal, oldVal) {
    alert('Nhân sự thay đổi từ ' + oldVal.fullName + ' sang ' + newVal.fullName + '!');
}, { deep: true });

Với các watcher phức tạp, có thể thay biểu thức tham chiếu đến một thuộc tính đối tượng thông qua toán tử dấu chấm bằng một hàm trả về biểu thức cần giám sát.

vm.$watch(
    function() {
        return this.counter;
    },
    function(newValue, oldValue) {
        alert('Bộ đếm tăng từ ' + oldValue + ' lên ' + newValue + '!');
    }
);

Chúng ta đã nói đến việc thêm watcher ở ngoài Vue instance, vậy làm cách nào để Vue không giám sát tiếp các thuộc tính trong data? Rất đơn giản, phương thức $watch() trả về một phương thức mà nếu chúng ta gọi đến phương thức này, Vue sẽ không giám sát thuộc tính trong data nữa.

var vm = new Vue({
    el: '#app',
    data: {
        counter: 1
    }
});
var unwatch = vm.$watch(
    function() {
        return this.counter;
    },
    function(newValue, oldValue) {
        alert('Bộ đếm tăng từ ' + oldValue + ' lên ' + newValue + '!');
    }
);
// Sau 10 giây ngừng giám sát thuộc tính counter của data
setTimeout(function() {
    unwatch();
}, 10000);

Sau 10 giây mọi thay đổi của counter sẽ không được giám sát nữa.

5. So sánh computed, watch và methods trong Vue instance

Chúng ta cùng xem xét một ví dụ sau:

var vm = new Vue({
    el: '#welcome',
    data: {
        message: 'Hello',
        name: 'World',
        nameEdits: 0
    },
    computed: {
        welcomeMessage: function () {
            return this.message + ' ' + this.name
        }
    },
    watch: {
        name: function () {
            if (this.message.toLowerCase() === 'reset') {
                this.nameEdits = 0
            } else {
                this.nameEdits += 1 
            }
        }
    },
    methods: {
        numRenders: function () {
            console.log('Page rendered')
        }
    }
})

Đầu tiên chúng ta xem phần computed, welcomeMessage chỉ được gọi khi message hoặc name thay đổi vì nó phụ thuộc vào thuộc tính này. Vì vậy, nếu nameEdits thay đổi, welcomeMessage cũng không được gọi. Thuộc tính Computed giúp ứng dụng hoạt động hiệu quả tối ưu mà vẫn có những phản ứng.

Tiếp theo chúng ta sang phần watch, nó đang giám sát thuộc tính name, có nghĩa là bất cứ khi nào name thay đổi, hàm khai báo sẽ được gọi để cập nhật nameEdits. Chú ý, mỗi watch chỉ giám sát trên một thuộc tính, ở đây là name, do đó khi nameEdits và message thay đổi, hàm này không được kích hoạt.

Cuối cùng, chúng ta xem phần methods, numRender được gọi mỗi khi render xong (cụ thể hơn là được gọi khi các đoạn mã gọi đến hoặc sự kiện người dùng khi giao diện đã được render), vì vậy bất cứ khi nào có gì đó được cập nhật trên giao diện người dùng, numberRenders được gọi. Ví dụ, nếu bạn có một ứng dụng hiển thị đồng hồ và nó cập nhật theo từng giây, tất cả các phương thức sẽ được gọi từng giây bất kể phương thức đó làm gì.

6. Bài tập

Continue

7. Lời kết

Các khái niệm trên đây là rất cơ bản khi làm việc với Vue.js do đó bạn cần nắm rõ nó, có thể bạn chỉ mới hiểu lờ mờ nhưng đừng lo các dự án cụ thể sẽ giúp bạn nắm rõ hơn.

Bài viết gốc được đăng tải tại allaravel.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Hàm explode() trong PHP

Hàm explode() trong PHP

Bài viết được sự cho phép của tác giả Kien Dang Chung

Từ phiên bản PHP 4, có một số các hàm xử lý chuỗi rất tiện lợi như explode, implode… giúp cho công việc phân tích, sàng lọc chuỗi dễ chịu hơn nhiều. Trong bài viết này chúng ta sẽ làm quen với hàm explode trong PHP cùng với một số ví dụ hay dùng trong thực tế.

1. Cơ bản về hàm explode trong PHP

Hàm explode trong PHP cho phép bạn chuyển một chuỗi sang một mảng dựa trên các ký tự phân cách. Trong thực tế, xử lý chuỗi là rất cần thiết và sử dụng khá thường xuyên, ví dụ khi bạn muốn tách họ và tên của một người dùng, tách từng từ khóa trong một danh sách từ khóa có phân cách bằng một ký tự nào đó… Cú pháp của hàm explode:

explode(separator,string,limit)

Trong đó:

  • separator: ký tự hoặc chuỗi ký tự phân cách sử dụng để phân biệt các phần tử trong chuỗi.
  • string: chuỗi cần tách thành mảng.
  • limit: xác định số phần tử của mảng đầu ra.
    • >0: trả về mảng có số phần tử là limit phần tử đầu
    • <0: trả về mảng có số phần tử là limit phần tử cuối
    • 0: trả về mảng với 1 phần tử

Chú ý: Hàm explode được giới thiệu từ phiên bản PHP 4, tham số limit được thêm vào từ PHP 4.1 và hỗ trợ giá trị âm từ PHP 5.1.0.

Tìm việc làm PHP đãi ngộ tốt trên TopDev

2. Các ví dụ thực tế sử dụng hàm explode

2.1 Ví dụ đơn giản về explode

Một cách đơn giản để lưu nhiều giá trị vào một cột đó là sử dụng dấu phân cách, cách thức này được sử dụng khá nhiều trước đây khi chưa có các công nghệ như XML, JSON… Ví dụ trong một bảng dữ liệu để lưu thông tin người dùng trong một cột người ta sử dụng chuỗi !# để phân cách các thông tin: Nguyễn Văn A!#19810101!#Hà Nội!#anv@allaravel.com

Để bóc tách chuỗi này chúng ta sử dụng explode

<?php
$strUserInformation = "Nguyễn Văn A!#19810101!#Hà Nội!#anv@allaravel.com";
$arrUserInformation = explode("!#", $strUserInformation);
print_r($arrUserInformation);

Kết quả: Array ( [0] => Nguyễn Văn A [1] => 19810101 [2] => Hà Nội [3] => anv@allaravel.com )

2.2 Ví dụ phân tách từ khóa trong một danh sách từ khóa sử dụng explode

Trong các ứng dụng blog, CMS… trong các bài viết chúng ta thường nhập vào một danh sách từ khóa được phân cách với nhau bằng dấu , hoặc ; hoặc |… vậy làm thế nào để phân cách chuỗi từ khóa này thành một mảng tiện cho xử lý và lưu trữ vào CSDL?

Ví dụ khi danh sách từ khóa, thẻ cho bài viết này như sau: “xử lý chuỗi trong PHP, explode trong PHP; PHP tách chuỗi | PHP string process”, ở đây dấu phân cách sử dụng rất đa dạng.

<?php
$keywords =  "xử lý chuỗi trong PHP, explode trong PHP; PHP tách chuỗi | PHP string process";
$delimiters = array(",",";","|");
$keywords = str_replace($delimiters, $delimiters[0], $keywords);
$arrKeyword= explode($delimiters[0], $keywords);
foreach ($arrKeywordas $key)
{
   // Code xử lý cho từng từ khóa và lưu CSDL
}

Đầu tiên chúng ta thực hiện replace toàn bộ dấu phân cách về một loại, ở đây đưa hết về dấu phẩy. Tiếp theo, sử dụng explode như thông thường để thực hiện chuyển chuỗi thành mảng.

  10 Frameworks tốt nhất hiện nay cho PHP
  10 PHP Instagram Scripts & Widgets tốt nhất

2.3 Lọc họ tên người dùng sử dụng php explode

Trong các ứng dụng để tránh cho người dùng phải mất quá nhiều thao tác khi nhập họ tên thường chúng ta đưa cả họ và tên đầy đủ vào một ô nhập liệu sau đó trong xử lý nghiệp vụ mới bóc tách họ, tên người dùng này. Ví dụ: “Nguyễn Văn A”, để bóc tách họ tên trong PHP chúng ta có thể sử dụng hàm explode:

<?php
$fullName = "Nguyễn Văn A";
$arrName = explode(" ", $fullName);
$firstName = array_shift($arrName); //Họ chính là phần tử đầu tiên của mảng
$lastName = array_pop($arrName); //Tên chính là phần tử cuối cùng của mảng
$middleName = implode(" ", $arrName); //Tên đệm chính là kết nối các phần tử còn lại

Trong ví dụ trên có sử dụng hàm implode, trong PHP hàm này ngược lại với hàm explode. Hàm implode biến một mảng thành một chuỗi.

3. Kết luận

Qua bài viết bạn đã nắm được cách áp dụng explode một cách thành thục khi lập trình PHP. Sử dụng explode giúp giảm thời gian viết code, các xử lý chuỗi cũng đơn giản hơn khi kết hợp với các vòng lặp trong PHP. Nếu bạn có trường hợp nào cần xử lý chuỗi hãy để lại bình luận cuối bài viết nhé, chúng ta sẽ cùng thảo luận.

Bài viết gốc được đăng tải tại allaravel.com

Có thể bạn quan tâm:

Xem ngay những tin đăng tuyển dụng IT mới nhất trên TopDev

Truy vấn cơ sở dữ liệu MongoDB bằng PHP

Truy vấn cơ sở dữ liệu MongoDB bằng PHP

Bài viết được sự cho phép của smartjob.vn

MongoDB hỗ trợ rất nhiều Driver cho các ngôn ngữ lập trình khác nhau. Trong bài viết này, SmartJob trình bày về việc kết nối, truy vấn từ PHP.

Máy tính sử dụng: Windows 10, 64 bit, sử dụng bộ tích hợp XAMPP.
Cài đặt MongoDB sử dụng MEAN stack (bạn xem các bài viết trước đã hướng dẫn cách cài đặt).

Xem thêm việc làm mongoBD tại các công ty hàng đầu trên TopDev

Bước 1. Tải về tập tin mở rộng dll tại đường link:

Bước 2. Giải nén. Copy file php_mongodb.dll  vào thư mục ext, ví dụ trên máy của tác giả là: C:\xampp\php\ext

Bước 3. Tìm file php.ini , ví dụ, trên máy tác giả là: C:\xampp\php\php.ini .

Chèn vào cuối tập tin này:

extension=php_mongodb.dll

Bước 4. Giả sử có thư mục: C:\xampp\htdocs\vy\mongophp
Sử dụng cmd:

Gõ lệnh:

composer require "mongodb/mongodb=^1.0.0"

để tải thư viện bằng Composer về.

Composer tự động tải về và thư mục có thêm 1 thư mục và 2 tập tin mới:

Tạo 3 tập tin info.phpadd.phpfind.php để kiểm tra các tính năng mà thư viện MongoDB PHP cung cấp:

Tập tin info.php

Tập tin add.php

Tập tin find.php

Bước 5. Khởi chạy máy chủ PHP dựng sẵn

php -S localhost:1111 -t C:\xampp\htdocs\vy\mongo-php

Bước 6. Truy cập

http://localhost:1111/info.php

xem kết quả để thấy rằng extension MongoDB đã được cài đặt thành công trong PHP.

Bước 7. Thêm dữ liệu bằng cách truy cập đường dẫn

Bước 8. Tìm kiếm dữ liệu, bằng cách truy cập đường dẫn

Để thực hiện nhiều thao tác đa dạng khác (đọc, ghi, sửa, xóa), bạn hãy xem thêm tài liệu như bên dưới.

TÀI LIỆU THAM KHẢO

1. http://php.net/manual/en/mongodb.installation.windows.php
2. http://mongodb.github.io/mongo-php-library/api/class-MongoDB.Collection.html
3. https://gist.github.com/gatesvp/977676

Tải mã nguồn từ server SmartJob: mongo-php
hoặc tải về/fork từ server Github: https://github.com/SmartJobVN/mongo-php

Bài viết gốc được đăng tải tại smartjob.vn

Có thể bạn quan tâm:

Xem ngay những tin đăng tuyển dụng IT mới nhất trên TopDev

Singleton Pattern – Một Object Duy Nhất

singleton pattern

Bài viết được sự cho phép của tác giả Edward Thien Hoang

Xin chào các bạn, hôm nay chúng ta sẽ tiếp tục làm quen với một mẫu Design Pattern mới: Singleton pattern. Cái tên đã nói lên tất cả, nếu muốn trong suốt chương trình chỉ tồn tại duy nhất một đối tượng của một lớp nào đó thì Singleton chính là điều chúng ta cần nghĩ đến đầu tiên. Ví dụ như các lớp Logging, Configuration, … Trong JDK tồn tại khá nhiều class dưới dạng Singleton như java.lang.Runtime, tất cả các chương trình Java đều có duy nhất một đối tượng Runtime để cho phép tương tác với environment của chương trình đang chạy. Hoặc java.awt.Desktop, java.awt.GraphicsEnvironment. Ngoài ra, Singleton Pattern còn được sử dụng kèm với các Pattern khác như: Abstract Factory, Builder, Prototype, Facade…

  Singleton Pattern là gì? Khái niệm và ứng dụng
  Single page app không hề tệ như bạn nghĩ

TẠO MỘT LỚP SINGLETON

Để gọi là một Singleton, hay nói đơn giản nếu bạn muốn tạo một lớp Singleton thì lớp đó phải đáp ứng một số yêu cầu sau:

  1. Private constructor: nhằm không để bên ngoài có thể khởi tạo các thể hiện của lớp một cách tùy ý.
  2. Private static instance: một lớp Singleton cần có một thể hiện static của chính nó.
  3. Public static function: một hàm public static để thực hiện việc khởi tạo và trả về thể hiện của lớp. Nếu một class muốn gọi các hàm (non-static) khác của lớp thì cần thực hiện thông qua hàm static này.

Mình sẽ giải thích kỹ hơn bằng các ví dụ dưới đây. Chúng ta sẽ cùng điểm qua một số cách khởi tạo lớp Singleton, những điểm cần lưu ý cũng như best practice khi áp dụng Singleton:
1. Eager initialization
2. Static block initialization
3. Lazy Initialization
4. Thread Safe Singleton
5. Bill Pugh Singleton Implementation
6. Using Reflection to destroy Singleton Pattern
7. Enum Singleton
8. Serialization and Singletons

1. EAGER INITIALIZATION

public class EagerInitializedSingleton {

private static final EagerInitializedSingleton instance = new EagerInitializedSingleton();

//private constructor to avoid client applications to use constructor
private EagerInitializedSingleton(){}

public static EagerInitializedSingleton getInstance(){
return instance;
}
}

Đây là cách đơn giản và an toàn nhất. Tuy nhiên, cách này có một nhược điểm là nếu lớp này không được sử dụng sau đó thì việc khởi tạo sẽ trở thành phí phạm vì biến instance sẽ được khởi tạo ngay lúc chương trình chạy bất kể là có sử dụng đến lớp Singleton hay không. Một điểm nữa là không thể handle exception.

2. STATIC BLOCK INITIALIZATION

Cũng giống như Eager initialization ngoại trừ việc biến instance được khởi tạo trong khối static, ở ngay đây, exception sẽ được handle.

public class StaticBlockSingleton {

private static StaticBlockSingleton instance;

private StaticBlockSingleton(){}

//static block initialization for exception handling
static{
try{
instance = new StaticBlockSingleton();
}catch(Exception e){
throw new RuntimeException("Exception occured in creating singleton instance");
}
}

public static StaticBlockSingleton getInstance(){
return instance;
}
}

3. LAZY INITIALIZATION

public class LazyInitializedSingleton {
private static LazyInitializedSingleton instance;

private LazyInitializedSingleton(){}

public static LazyInitializedSingleton getInstance(){
if(instance == null){
instance = new LazyInitializedSingleton();
}
return instance;
}
}

Sử dụng cơ chế Lazy Initialization sẽ đảm bảo biến instance chỉ được khởi tạo nó thực sự được dùng đến, nghĩa là khi chúng ta cần đến lớp Singleton để xử lý công việc thông qua việc gọi hàm getInstance. Tuy nhiên Lazy Initialization lại để lộ ra một nhược điểm khi chạy trong môi trường multithreading. Khi có nhiều thread truy xuất đến hàm getInstance, sẽ xảy ra việc có nhiều đối tượng Singleton được tạo ra. Vì vậy chúng ta cần có các cơ chế implementation khác để đảm bảo tính thread-safe cho lớp Singleton. Cùng điểm qua 1 số cách dưới đây

4. THREAD SAFE SINGLETON

public class ThreadSafeSingleton {

private static ThreadSafeSingleton instance;

private ThreadSafeSingleton(){}

public static synchronized ThreadSafeSingleton getInstance(){
if(instance == null){
instance = new ThreadSafeSingleton();
}
return instance;
}

}

Bằng cách synchronized hàm getInstance, sẽ đảm bảo chỉ có duy nhất 1 thread được truy cập vào hàm getInstance và khởi tạo 1 đối tượng instance duy nhất. Đây là cách đơn giản và thông dụng nhất để đảm bảo tính thread-safe cho lớp Singleton. Tuy nhiên việc synchronized như vậy sẽ gây tốn chi phí về thời gian, vì tại 1 thời điểm, chỉ có duy nhất 1 thread được truy cập vào hàm getInstance để lấy ra (hoặc khởi tạo) đối tượng instance.

Thay vào đó, sử dụng kỹ thuật double checked locking sẽ giảm được chi phí cho hàm getInstance

public static ThreadSafeSingleton getInstanceUsingDoubleLocking(){
if(instance == null){
synchronized (ThreadSafeSingleton.class) {
if(instance == null){
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}

5. BILL PUGH SINGLETON IMPLEMENTATION

Phương pháp Bill Pugh sử dụng inner static helper class để khởi tạo đối tượng Singleton. Cách này được xem là hay và nên áp dụng nhất.

public class BillPughSingleton {

private BillPughSingleton(){}

private static class SingletonHelper{
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}

public static BillPughSingleton getInstance(){
return SingletonHelper.INSTANCE;
}
}

Ở đây, tuy là lớp SingletonHelper đã khởi tạo trực tiếp biến INSTANCE, nhưng biến INSTANCE chỉ được load vào memory khi nó được gọi thông qua hàm getInstance (các bạn tham khảo thêm về static inner class trong Java)

Ở trên là 1 số ví dụ về việc tạo ra 1 lớp Singleton trong Java. Còn rất nhiều vấn đề liên quan đến Singleton mà mình sẽ đề cập ở các bài viết khác như:

  • So sánh Singleton và Static class
  • Singleton trong môi trường multi JVM
  • Singleton sẽ không được đảm bảo nếu sử dụng Reflection
  • Serialize và deserialize đối tượng Singleton

http://www.edwardthienhoang.wordpress.com

Bài viết gốc được đăng tải tại edwardthienhoang.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Hướng dẫn Angular 2 cho người mới bắt đầu – Phần 2

Hướng dẫn Angular 2 cho người mới bắt đầu – Phần 2

Bài viết được sự cho phép của tác giả Tino Phạm

Phần 2: Tạo ứng dụng với Angular 2 + Typescript

Phần 1 mình đã hướng dẫn bạn cài đặt môi trường để có thể phát triển ứng dụng với Angular 2. Trong phần này, chúng ta sẽ đi vào thực hành Angular 2. Để bắt đầu tạo ứng dụng thực hành với Angular 2, các bạn có thể tham khảo về cách học một công nghệ mới và xin hãy chia sẽ với mình về ý kiến của bạn.

OK,  bắt đầu thực hành thôi nào.

  8 lợi thế khi sử dụng Polymer so với Angular và React

  Angular - Tự xây dựng module "lazy load images"

Bước 1: tạo thư mục vơi tên “AngularDemo“.

Bước 2: Mở Visual Studio Code (VS Code) > File > Open Folder… > tìm và chọn thư mục “AngularDemo”.

Bước 3: Click vào button New File > đặt tên file là tsconfig.json với nội dung như sau:

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules",
    "typings/main",
    "typings/main.d.ts"
  ]
}

setting-project-2.png

Bước 4: Tạo file typings.json với nội dung:

{
  "globalDependencies": {
    "core-js": "registry:dt/core-js#0.0.0+20160602141332",
    "jasmine": "registry:dt/jasmine#2.2.0+20160621224255",
    "node": "registry:dt/node#6.0.0+20160621231320"
  }
}

Bước 5: Tạo file package.json với nội dung như sau:

{
  "name": "angular2-demo",
  "version": "1.0.0",
  "scripts": {
    "start": "concurrent \"npm run tsc:w\" \"npm run lite\" ",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "lite": "lite-server",
    "typings": "typings",
    "postinstall": "typings install"
  },
  "license": "ISC",
  "dependencies": {
    "angular2": "2.0.0-beta.7",
    "systemjs": "0.19.22",
    "es6-promise": "^3.0.2",
    "es6-shim": "^0.33.3",
    "reflect-metadata": "0.1.2",
    "rxjs": "5.0.0-beta.2",
    "zone.js": "0.5.15"
  },
  "devDependencies": {
    "concurrently": "^2.0.0",
    "lite-server": "^2.1.0",
    "typescript": "^1.7.5",
    "typings":"^0.6.8"
  }
}

Bước 6: Nhấn Ctrl + ` để mở chế độ Terminal trong VS Code. Gõ lệnh: npm install

Bước 7: Trong VS Code nhấn nút tạo thư mục và đặt tên là app

Bước 8: Trong VS Code chọn thư mục app > nhấn nút tạo file và đặt tên appComponent.ts với nội dung:

appComponent

Bước 9: Tạo file với tên main.ts nội dung như sau:

import {bootstrap} from "angular2/platform/browser"
import {AppComponent} from "./environment_app.component"

bootstrap(AppComponent);

Bước 10: Tạo file index.html trong thư mục AngularDemo với nội dung như sau:

index-html

Bước 11: Để chạy ứng dụng bạn gõ lệnh: npm start trong Terminal. Sau đó nhấn Enter.

setting-project-3.png

Đây là kết quả của chúng ta:

setting-project-4.png

Trong phần phần 3, mình sẽ giải thích cho các bạn hiểu rõ các tại sao và ý nghĩa mà chúng ta làm ở từng bước trên.

Tham khảo:
practical angular 2
www.tutorialspoint.com

Bài viết gốc được đăng tải tại thangphampt.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Strategy Pattern – Chiến lược với những thay đổi

STRATEGY PATTERN – CHIẾN LƯỢC VỚI NHỮNG THAY ĐỔI

Bài viết được sự cho phép của tác giả Edward Thiên Hoàng

Chào mừng đến với THẾ GIỚI VỀ SỰ CHUẨN MỰC TRONG VIỆC THIẾT KẾ VÀ XÂY DỰNG KIẾN TRÚC CHƯƠNG TRÌNH. Như đã nói ở bài trước, mình sẽ bắt đầu viết những đoạn code đơn giản để minh họa bài toán CON VỊT áp dụng các kỹ thuật trong lập trình hướng đối tượng bằng Java. Yêu cầu là xây dựng chương trình để hiện thực những con vịt lên trên màn hình.

  Các loại Design patterns
  Top 5 công cụ mã nguồn mở dành cho MySQL administrator

TÍNH KẾ THỪA TRONG LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG

Áp dụng tính kế thừa, ta có: Lớp Duck là lớp cơ sở cho những loài vịt cụ thể như MallarDuck, RedHeadDuck.

public abstract class Duck {
public void quack() {
// Quack..
}
public void swim() {
// Swim...
}
public abstract void display();
}

public class MallarDuck extends Duck {
@Override
public void display() {
// Display MallarDuck
}
}

public class RedHeadDuck extends Duck {
@Override
public void display() {
// Display RedHeadDuck
}
}

Ở đây, những con vịt đều có chung hành vi là bơi và kêu, riêng chỉ có hình dáng của chúng là khác nhau nên phương thức display sẽ là abstract, mấy con vịt sẽ tự định nghĩa phương thức đó để hiển thị đúng hình ảnh của chúng.

Sau này có yêu cầu những con vịt có thể bay được. Vậy việc duy nhất chúng ta làm là thêm phương thức fly vào trong lớp Duck, và những lớp con sẽ có thể bay.

public abstract class Duck {
public void quack() {
// Quack..
}
public void swim() {
// Swim...
}
public abstract void display();
public void fly() {
// Fly
}
}

MallarDuck, RedHeadDuck đều là những con vịt thật, chúng có thể kêu, bay và bơi. Bây giờ lại có thêm yêu cầu là support luôn con vịt cao su. Lớp RubberDuck cũng kế thừa từ Duck như sau:

public class RubberDuck extends Duck {
@Override
public void display() {
// Look like a rubber duck
}
}

Chạy chương trình:

public class Test {
public static void main(String[] args) {
Duck mallarDuck = new MallarDuck();
Duck rubberDuck = new RubberDuck();

mallarDuck.quack();
mallarDuck.fly();

rubberDuck.fly();
}
}
Output:
Quackkkkkkk...
I'm flying
I'm flying

Oạch, rất ngạc nhiên khi vịt cao su mà cũng có thể bay. Vấn đề đang dần dần hiện ra, nhưng trong trường hợp này, chúng ta vẫn còn có thể chữa cháy bằng cách override lại phương thức fly của RubberDuck để nó không bay được nữa.

public class RubberDuck extends Duck {
@Override
public void display() {
System.out.println("Look like a RubberDuck");
}
@Override
public void fly() {
// Do nothing. It cannot fly
}
}

Khi chạy lại chương trình thì vịt cao su không thể bay được nữa.

Giờ lại có thêm yêu cầu mới, chúng ta cần support thêm lớp vịt gỗ. Vịt gỗ thì không kêu được, và cũng không bay được. Nghĩa là chúng ta sẽ phải override lại 2 hàm quack và fly để chúng không làm gì cả…

Bây giờ thì vấn đề của tính kế thừa quá rõ ràng. Các lớp dẫn xuất phải phụ thuộc quá chặt vào lớp cơ sở. Mỗi khi có sự thay đổi, chúng ta luôn phải xem xét lại ở mọi lớp để quyết định hành vi chính xác với mỗi lớp. Việc thay đổi ở nhiều lớp sẽ khiến cho những gì đã chắc chắn chạy đúng trước đây, bây giờ không có gì để đảm bảo nữa và việc test lại tất cả những thay đổi là điều không thể tránh khỏi. Với những hệ thống vận hành lâu năm, nếu cái core không được viết một cách cẩn thận, luôn có những ảnh hưởng rộng mỗi khi có sự thay đổi thì việc test lại toàn bộ những chức năng đã vận hành lâu nay sẽ là một ác mộng. Các bạn có thể tham khảo thêm bài viết “Why extends is evil” tại đây để có cái nhìn rõ hơn về những nhược điểm của Kế thừa. Tuy nhiên mình không nói là chúng ta nên loại tính kế thừa ra khi thiết kế hệ thống, tính kế thừa cũng có ưu điểm của nó và chỉ có 3 từ để nói đến là “Tái sử dụng”. Ở đây mình đang nói đến một hướng khác, đó là làm thế nào để có thể giữ lại được những ưu điểm của Kế thừa, đồng thời loại bỏ đi những phiền phức mà nó mang lại, đó là Sự thay đổi.

INTERFACE TRONG LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG

implements chính là từ khóa chúng ta nghĩ đến khi không muốn nhắc đến từ extends (Mình đang dùng một số từ khóa trong Java. implements có nghĩa là một lớp sẽ định nghĩa lại một giao diện interface nào đó, và extends có nghĩa là 1 lớp muốn kế thừa lại một lớp nào đó). Với thiết kế hiện tại, chúng ta sẽ định nghĩa ra các interface như: Flyable, Quackable.

public interface Flyable {
public void fly();
}

public interface Quackable {
public void quack();
}

Khi này, các lớp vịt con có thể implement giao diện (hành vi) mà nó có. Chúng ta sẽ có một thiết kế giống hình sau:
1_DuckInterface

Theo các bạn thì với Design như vậy so với ban đầu thì sao nhỉ? Có thể nói đó là một mớ hỗn độn, có quá nhiều mối quan hệ ở đây. Cũng giống như kế thừa, interface cũng mang lại không ít phiền phức. Hãy tưởng tượng có một “trang trại vịt” có tới 30 loài flyalbe (biết bay) thì chúng ta phải implement 30 phương thức fly. Có một sự duplication không hề nhẹ ở đây.

Có một nguyên lý trong thiết kế hướng đối tượng nói rằng: kiến trúc chương trình cần đóng cho những sự thay đổi và mở cho việc mở rộng. Đó là điều chúng ta cần. Cần có một thiết kế sao cho những thay đổi sẽ có ảnh hưởng ít nhất đến phần còn lại của chương trình. Bằng cách tách biệt những thành phần dễ bị thay đổi ra khỏi những phần khó bị thay đổi. (Nếu đã đọc qua loạt bài về NGUYÊN LÝ THIẾT KẾ HƯỚNG ĐỐI TƯỢNG, bạn sẽ hiểu những gì mình đang viết).

TÁCH BIỆT NHỮNG PHẦN THAY ĐỔI

Cùng phân tích và tái cấu trúc lại “trang trại vịt” ở trên. fly và quack đang là những thành phần gây rắc rối. Mỗi loài vịt sẽ có tiếng kêu khác nhau (Quack!!!, Queck!!!, … (hoặc không kêu)) và tương tự cho việc biết bay hay không. Vì vậy cần phải tách biệt những thành phần này ra. Nguyên lý “The Open Closed Principle” sẽ giúp chúng ta có hướng đi đúng đắn trong trường hợp này.

Phân tích kỹ hơn chút nữa, nếu ta gom nhóm các tiếng kêu: Quack!!!, Queck!!!, … (không biết kêu). Chúng đều là các kiểu kêu. Mỗi loài vịt sẽ CÓ một kiểu kêu KHÁC NHAU. Vậy thiết kế mới cho Kiểu kêu như sau:
2_QuackBehavior

Và toàn bộ thiết kế mới sẽ như sau:
3_NewDesign_Composition

Việc thực thi thiết kế mới bằng code cũng khá đơn giản:

interface QuackBehavior {
public void quack();
}
class Quack implements QuackBehavior {
public void quack() {
System.out.println("Quack quack...");
}
}
class Queck implements QuackBehavior {
public void quack() {
System.out.println("Queck queck...");
}
}
class MuteQuack implements QuackBehavior {
public void quack() {
System.out.println("...");
}
}

interface FlyBehavior {
public void fly();
}
class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("Fly fly..");
}
}
class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("???");
}
}

public abstract class Duck {
protected QuackBehavior quackBehavior;
protected FlyBehavior flyBehavior;
public void quack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("I'm swimming");
}
public void fly() {
flyBehavior.fly();
}
public abstract void display();
}

public class MallarDuck extends Duck {
public MallarDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("Look like a MallarDuck");
}
}

public class RedHeadDuck extends Duck {
public RedHeadDuck() {
quackBehavior = new Queck();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("Look like a RedHeadDuck");
}
}

public class RubberDuck extends Duck {
public RubberDuck() {
quackBehavior = new Queck();
flyBehavior = new FlyNoWay();
}
@Override
public void display() {
System.out.println("Look like a RubberDuck");
}
}

public class WoodenDuck extends Duck {
public WoodenDuck() {
quackBehavior = new MuteQuack();
flyBehavior = new FlyNoWay();
}
@Override
public void display() {
System.out.println("Look like a WoodenDuck");
}
}

Ở đây, những con vịt sẽ có những kiểu kêu và kiểu bay khác nhau.

TIGHT COUPLING

Nhưng vẫn còn vấn đề cần giải quyết. Đó là tight coupling. Ở đây, những lớp vịt con lại phụ thuộc vào những đối tượng cụ thể khác như: Queck, FlyWithWings, FlyNoWay, … Để giải quyết nốt vụ Tight coupling. Sẽ tốt hơn nếu các đối tượng vịt sẽ nhận các hành vi cụ thể (bay, kêu) từ đối tượng khởi tạo chúng, hoặc bạn có thể giữ nguyên thiết kế bên trên, và thêm các setter để có thể thay đổi được hành vi của chúng lúc runtime (chẳng hạn như hôm nay vịt ốm thì không thể kêu được). Chúng ta cần sửa lại đoạn chương trình như sau:

public abstract class Duck {
protected QuackBehavior quackBehavior;
protected FlyBehavior flyBehavior;
public Duck(QuackBehavior inQuackBehavior, FlyBehavior inFlyBehavior) {
quackBehavior = inQuackBehavior;
flyBehavior = inFlyBehavior;
}
public void setQuackBehavior(QuackBehavior inQuackBehavior) {
quackBehavior = inQuackBehavior;
}
public void setFlyBehavior(FlyBehavior inFlyBehavior) {
flyBehavior = inFlyBehavior;
}
public void quack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("I'm swimming");
}
public void fly() {
flyBehavior.fly();
}
public abstract void display();
}

Đây class diagram mới. Mối liên hệ composition đã được thay đổi bằng aggregation
4_NewDesign_Agreeation

Như vậy, việc khởi tạo 1 con MallarDuck bây giờ sẽ là:

Duck mallarDuck = new MallarDuck(new Quack(), new FlyWithWings());

Thậm chí chúng ta có thể thay đổi để nó kêu Queck queck bằng cách set lại tiếng kêu cho nó:

mallarDuck.setQuackBehavior(new Queck());

Và khi bạn muốn tiếng kêu Queck queck… sẽ thành Queck queck queck queck… thì việc đơn giản bạn cần làm là tìm lớp Queck và thay đổi cách xử lý của phương thức quack().

Hãy tưởng tượng với những thiết kế ban đầu, cần phải sửa bao nhiêu dòng code, bao nhiêu lớp để làm được những yêu rất đơn giản ở trên???

STRATEGY PATTERN

Chúng ta vừa hoàn tất thiết kế một chương trình đơn giản, bằng cách đi từ những ý tưởng này đến những ý tưởng khác để hoàn thiện chúng. Đó cũng có nghĩa là chúng ta cũng vừa hoàn tất 1 pattern đầu tiên: STRATEGY PATTERN. Mình nghĩ đây là pattern quan trọng nhất trong số các pattern. Nó giúp chúng ta xử lý vấn đề rất quan trọng trong việc lập trình hàng ngày đó là đối phó với những thay đổi. Bằng cách tách rời những thành phần dễ bị thay đổi (hoặc có nhiều cách thể hiện khác nhau) sẽ giúp cho chương trình ít bị biến động, đồng thời nó còn có nhiều tác dụng như một vài ví dụ mình đưa ở trên.

Vì đây là pattern khá quan trọng nên mình viết khá kỹ. Hi vọng các bạn sẽ nắm được tư tưởng này và áp dụng vào thực tế nếu có thể.

Bài viết gốc được đăng tải tại edwardthienhoang.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm ngành cntt hấp dẫn trên TopDev

Những điều cần lưu ý khi học code cơ bản

Những điều cần lưu ý khi học code cơ bản

Bài viết được sự cho phép của tác giả Nguyễn Chí Thức

Để học code cơ bản thành công không phải là điều khó. Tuy nhiên, người học phải có phương pháp học, cách tiếp cận phù hợp khi học code mới có thể đạt hiệu quả. Chính vì vậy, hôm nay uCode sẽ chia sẻ những bí quyết học code để giúp người học tự tin và gặt hái thành quả cao nhất.

1. Trước tiên phải nắm vững kiến thức cơ bản

Để học được bất cứ điều gì, đầu tiên chúng ta phải nắm vững kiến thức cơ bản nhất, căn cốt nhất. Có nghĩa là ta phải học từ dễ đến khó. Hiện nay, nhiều học viên học nhanh quên nhanh, đến khi học nâng cao thì không còn nhớ đến kiến thức gốc. Học như vậy, kết quả chúng ta nhận lại sẽ là con số 0.

Do vậy, chúng tôi khuyên các bạn khi học lập trình cơ bản phải học từ những cái đơn giản nhất trước khi đi lên những tầng kiến thức cao và khó hơn. Cách hiệu quả nhất để các bạn nhớ được kiến thức căn bản nhất là học đi đôi với hành. Học lý thuyết liên hệ với thực tiễn là cách học code đạt hiệu quả cao nhất.

2. Thực hành nhiều lần theo ví dụ

Thực hành nhiều lần theo ví dụ trên mạng là cách học code cơ bản hiệu quả nhất. Mỗi lần làm theo ví dụ là cách để bạn cọ xát, tiến bộ và thành thạo. Tuy nhiên, các bạn không nên làm theo một ách máy móc và nên thuật lại theo cách hiểu của riêng mình. Sau mỗi lần thực hành, các bạn nên chạy thử để xem lỗi sai và tìm cách khắc phục lỗi sai đó.

Với những người bắt đầu học việc làm theo các ví dụ như vậy là hơi khó. Tuy nhiên, bạn chỉ cần làm theo một vài lần, bạn sẽ thấy cực kỳ đơn giản. Theo kinh nghiệm của nhiều người trong ngành, cách này sẽ giúp các bạn rèn luyện kỹ năng code rất tốt. Thực hành nhiều sẽ giúp người học tăng khả năng tư duy logic, hiểu bài nhanh và nhớ mãi.

3. Học code cơ bản từ nhiều tài liệu

Lập trình là môn học không giống với bất kì môn học phổ thông mà các bạn từng học, chỉ áp dụng những công thức có sẵn thì không thể làm được. Bởi vì, viết code mỗi người có một phong cách riêng, cách tiếp cận riêng. Vậy nên, các bạn hãy tìm hiểu và tham khảo nhiều nguồn sách, tài liệu, video, website khác. Từ đó đúc kết và rút ra những kiến thức đúng đắn và quan trọng nhất để áp dụng vào thực hành.

4. Code, code nữa, code mãi

Code, code nữa, code mãi – Đây có lẽ là nguyên tắc vàng mà bạn cần ghi nhớ để học code cơ bản dễ dàng và thực sự muốn trở thành lập trình viên giỏi.

Lập trình là bộ môn đòi hỏi khả năng tư duy độc lập, sáng tạo của mỗi người. Học code thành công là khi bạn thực sự đam mêm, chăm chỉ, tìm tòi và dành hết tâm huyết vào nó. Vậy nên, bạn đừng ngại tìm tòi, sửa những lỗi sai và khắc phục nó. Chỉ cần mỗi ngày bạn dành ra 2 tiếng để code lại những bài tập tại trường cũng như những kiến thức nâng cao khác thì không có gì là không thể.

5. Tuyệt đối không được copy và Paste code

Một thói quen xấu mà nhiều bạn lập trình viên mới học mắc phải là đi copy code trực tiếp trên các trang mạng. Chúng tôi thực sự khuyên các bạn là không nên copy và paste khi mới học lập trình và làm quen với code. Bởi, cách học này hoàn toàn sai lầm và không mang lại hiệu quả cho các bạn. Khi bạn tự học code lại những bài tập đã được code sẽ giúp các bạn nhớ lâu, gõ sai thì có thể chỉnh sửa lại.

Ngoài ra, bạn có xem video hướng dẫn giải bài toán trên mạng, sau đó tập gõ theo để tham khảo. Còn với những bài code ví dụ trên sách, các trang mạng, bạn nên tìm hiểu và làm theo để hiểu chúng kỹ hơn. Trong nhiều trường hợp, có một số ví dụ bạn gõ có thể nó chạy trên máy tính của bạn không giống như trên hướng dẫn. Tuy nhiên, đây chỉ là những trường hợp hy hữu, rất ít xảy ra, nên bạn không cần phải để ý đến điều này. Cách học này sẽ giúp bạn tiếp thu kiến thức nhanh, tạo thói quen kiểm tra code cẩn thận hơn để đạt hiệu quả cao.

6. Nên có người dẫn dắt

Để việc học code đạt kết quả cao, người học nên tìm một khóa học lập trình uy tín. Hoặc một người bạn hoặc là một người thầy có kinh nghiệm để cùng đồng hành và phát triển khả năng. Việc học sẽ đạt hiệu quả hơn khi học từ người khác và có thể tạo ra một cuộc thi để kiểm tra trình độ.

Trên đây là 6 điều mà bất cứ ai cũng cần phải biết trước khi học code cơ bản. uCode hy vọng đó sẽ là kiến thức bổ ích, giúp các bạn học code thành công!

Bài viết gốc được đăng tải tại ucode.vn

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Hướng dẫn Angular 2 cho người mới bắt đầu – Phần I

Hướng dẫn Angular 2 cho người mới bắt đầu – Phần 1

Bài viết được sự cho phép của tác giả Tino Phạm

Phần 1: Cài đặt môi trường phát triển

Qua bài hướng dẫn này ngoài kiến thức sẽ học được về Angular 2, chúng ta cũng sẽ học và tìm hiểu về: NodeJS, npm, Typescript, SystemJS và Visual Studio Code.

Để chuẩn bị học và thực hành một công nghệ mới, việc đầu tiên là chúng ta sẽ cài đặt môi trường. Trong phần này mình sẽ hướng dẫn các bạn cài đặt những thứ cần thiết trước khi bắt đầu thực hành Angular 2.

  Angular - Tự xây dựng module "lazy load images"
  8 lợi thế khi sử dụng Polymer so với Angular và React
  1. Cài đặt NodeJS
    Bạn tải NodeJS về máy tính và tiến hành cài đặt theo các bước rất đơn giản.Tại sao lại phải cài đặt NodeJS nhỉ?Chúng ta sử dụng NodeJS để có thể chạy được Javascript trên máy chủ (Server). Ngoài ra, Node có tích hợp gói npm dùng để quản lý các thư viện Javascript mà chúng ta sẽ sử dụng trong ứng dụng của mình. npm trong Node sẽ giúp bạn cài đặt và quản lý các thư viện Javascript đó.
  2. Cài đặt web server
    Để có thể chạy được ứng dụng web chúng ta cần có một máy chủ (server). Ở đây mình sẽ hướng dẫn các bạn cài đặt và sử dụng live-server. Đây là một máy chủ (server) viết trong Node. Để cài đặt live-server, bạn mở command line (cmd) và gõ lệnh: npm install live-server -g
    Trong lệnh trên có tham số -g nghĩa là chúng ta sẽ cài đặt gói live-server như một biến toàn cục và bạn có thể chạy nó ở bất cứ nơi đâu trong hệ thống và tất cả user trong windows.Tại sao phải dùng live-server, trước giờ tôi quen dùng IIS rồi?Mình sẽ có bài hướng dẫn cấu hình ứng dụng Angular 2 với IIS server sau. Trong bài này, mình dùng live-server vì:

    • live-server nó gọn nhẹ.
    • Nó tự động refresh (update) page mỗi khi chúng ta thay đổi source code. Mình đã từng có bài giới thiệu về gulp với các tính năng tương tự.
    • Nó được tích hợp cùng với Node và bạn có thể cài đặt bằng npm
  3. Cấu hình file package.json
    Đây là file cấu hình mặc định của các dự án phát triển với Node. File package.json lưu lại thông tin dự án của bạn. Ngoài ra, chúng ta sẽ định nghĩa các quy tắc cài đặt và thực thi trong file này cũng như thông tin những library mà chúng ta sử dụng cho dự án.
    OK, để tạo file package.json. Đầu tiên bạn tạo thư mục tên “AngularTest“, sau đó mở command line (cmd) và gõ lệnh: npm init

    • name: test . Đây là tên dự án
    • version: (1.0.0). Đây là phiên bản của dự án
    • description: mô tả về ứng dụng của bạn
    • entry point: (index.js). Đây là file được thực thi đầu tiên
    • test command:
    • git repository:
    • keyword:
    • author: thangpham
    • license: (ISC)

    Cuối cùng nhấn enter để lưu và tạo file package.json. Nếu bạn không muốn nhập các thông tin trên thì bạn chỉ cần nhấn enter cho tới khi xong các yêu cầu và lưu file thôi.

    Đây là nội dung file package.json của chúng ta:

    package-json-1

  4. Cài đặt Typescript
    Mở cmd và gõ lệnh: npm install typescript -g
  5. Cài đặt Angular 2
    Mở cmd và gõ lệnh: npm install angular2 –save

    Sau khi thực hiện xong lệnh này, bạn sẽ thấy thư mục node_modules được tạo ra bên trong thư mục AngularTest và bên trong node_modules sẽ có angular2. Sau này mỗi khi bạn cài đặt thêm bất cứ library nào dùng cho dự án của bạn thì chúng sẽ nằm trong thư mục node_modules.Tham số –save sẽ lưu thông tin package Angular vào file package.json.Ngoài ra, angular 2 yêu cầu chúng ta cài đặt thêm: es6-shim, reflect-metadata, rxjs, zone.js. Bạn gõ lệnh: npm install es6-shim reflect-metadata rxjs zone.js –save

    Và bây giờ file package.json sẽ có nội dung như sau:
    package-json-2
    OK, bạn thấy trong file package.json có item scripts > test nó chỉ show một error message đơn giản. Bây giờ chúng ta sẽ thay dòng “test”: “echo \”Error: no test specified\” && exit 1″ thành “start”: “live-server –port=3000”. Lệnh này giúp bạn chạy live-server với port là 3000.package-json-3

  6. Cài đặt Visual Studio Code
    Bạn tải về Visual Studio Code và cài đặt bình thường. Phiên bản này nhẹ và miễn phí nên chúng ta sẽ dùng nó thôi.

OK, tới đây chúng ta đã cài chuẩn bị xong môi trường để bắt đầu xây dựng ứng dụng sử dụng công nghệ Angular 2 + Typescript và IDEs là Visual Studio Code. Bài sau, chúng ta sẽ bắt đầu làm một project nho nhỏ để hiểu hơn nhé.

Bài viết gốc được đăng tải tại thangphampt.wordpress.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Top 10 điều hay ho khi làm việc Javascript Array

Top 10 điều hay ho khi làm việc Javascript Array

Bài viết được sự cho phép của tác giả Kiên Nguyễn

Javascript array là kiểu dữ liệu cực kì phổ biến. Sử dụng Array khéo léo giúp code dễ hiểu, dễ đọc, lại vừa đỡ tốn công tốn sức. Ngoài ra, với các lập trình viên có kinh nghiệm, các method khi làm việc với array thường được sử dụng linh hoạt, uyển chuyển.

Thường mix lại như sinh tố mà uống vẫn ngon chứ không dở!. Đó chính là điều làm nên sự khác biệt giữa Senior và Junior

Tuyển dụng Javascript lương cao online

  4 ứng dụng của Array.from
  9+ cách để xóa một phần tử ra khỏi JavaScript Array

Bài viết có sử dụng một số từ khóa (keywords) khai báo biến (variables) trong Javascript (var, let, const). Nếu chưa nắm chắc, các bạn có thể tham khảo thêm qua bài viết Var, let, const – 3 quý cô xinh đẹp nhà Javascript.

1. Xóa trùng lặp (duplicate) trong array

Xóa trùng lặp là vấn đề thường gặp trong array. Có rất nhiều nguyên nhân khiến ta loại bỏ đi các giá trị trùng lặp. Do insert nhiều lần, insert trùng lặp, tính toán số lần lặp, …

Để loại bỏ trùng lặp trong Javascript array, có thể sử dụng Set() và Operator (…)

let vehicles = ['bike', 'motobike', 'car', 'airplane', 'motobike']

// Sử dụng Array from và Set
let uniqueVehicle = Array.from(new Set(vehicles));
console.log(uniqueVehicle)
// ['bike', 'motobike', 'car', 'airplane']

// Sử dụng Operator ... và Set
let uniqueVehicle = […new Set(fruits)];
console.log(uniqueVehicle)
// ['bike', 'motobike', 'car', 'airplane']

2. Sử dụng Every và Some khi có thể

Đối với hai function Every và Some thì không phải developer nào cũng biết. Tuy nhiên, sử dụng every và some có thể đặc biệt hữu ích khi thao tác với Javascript Array.

Ví dụ dưới đây kiểm tra tất cả các phần tử trong array có là số dương hay không?. Không cần sử dụng for loop nhé!

const numbers = [1, 2, 3, 4, -5]

// Kiểm tra xem tất cả các phần tử trong array đều dương
// Condition check - điều kiện kiểm tra
const isPositive = (number) => {
return number > 0
}
// Return false, do có -5 < 0
numbers.every(isPositive);

3. Cast tất cả value trong javascript array

Một array có thể có nhiều kiểu data type (String, number, float, …). Javascript lại không ràng buộc chặt chẽ data type các phần tử trong array. Chính vì thế, nếu cần kiểm tra chặt với “===”, cần cast tất cả value về cùng một kiểu

let numbers = [ '1', '5', 8 ]

// Sử dụng map có thể cast toàn bộ value về kiểu chỉ định trong array
numbers = numbers.map(Number) 
// [ 1, 5, 8 ]

4. Tạo array mới mà không sử dụng .map()

Nhắc tới method map tất nhiên sẽ có nhiều bạn đã biết. Tuy nhiên, trường hợp không muốn sử dụng .map. Vẫn còn một phương thức khác để tạo Javascript array là Array.from

Cụ thể có thể xem xét qua ví dụ dưới đây:

var fruits = [
{ kind: 'Apple', delicious: yes },
{ kind: 'Banana', delicious: yes },
{ kind: 'Avocado', delicious: no },
]

// Với array map và method reference, ta có một array như mong muốn
var fruitsArray = Array.from(fruits, ({fruit}) => fruits);
// [ 'Apple', 'Banana', 'Avocado' ]

Nếu chưa biết về method reference, có thể tham khảo qua bài Tuốt tuồn tuột về Java 8 – những thay đổi lớn!

5. Làm rỗng array – make array empty

Làm việt với javascript array tất nhiên sẽ có lúc muốn remove tất cả item trong array.

Tạo tạo quá trời rồi, giờ muốn làm cái array empty đi để sử dụng tiếp. Đơn giản nhưng không phải ai cũng biết.

var fruitsArray = ["banana", "watermelon", "grape"];

fruitsArray.length = 0;
console.log(fruitsArray); 
// Kết quả có ngay array empty []

6. Merge các array với nhau

Dữ liệu sử dụng cho array có thể tới từ các nguồn khác nhau. Tuy nhiên, nếu muốn merge tất cả lại với nhau thì sao?. Đơn giản lắm, chỉ với vài ba dấu chấm thôi (…)

var arrayOne = [1];
var arrayTwo = [2, 3];
var arrayThree = [4, 5, 6];

// Mixing 3 array - nhớ sử dụng ...
var arrayMix = […arrayOne, …arrayTwo, …arrayThree];
console.log(arrayMix); 
// [1, 2, 3, 4, 5, 6]

Đúng nghĩa là dùng vài ba dấu chấm phải không nào?

7. Đảo ngược array

Đã làm việc với Javascript array thì tất nhiên không thể thiếu những lúc muốn đảo ngược value. Chẳng lẽ lại dùng vòng for i– như thời xưa cổ. Không hề phải mệt công như thế.

Chỉ đơn giản sử dụng phương thức reverse()có ngay một array sau khi đã đảo ngược. Tất nhiên, với một dòng duy nhất.

var arrayOne = [1];
var arrayTwo = [2, 3];
var arrayThree = [4, 5, 6];

// Mixing 3 array - nhớ sử dụng ...
var arrayMix = […arrayOne, …arrayTwo, …arrayThree];
console.log(arrayMix); 
// [1, 2, 3, 4, 5, 6]

8. Tổng các phần tử trong array

Tiêu đề đơn giản, bài toán đơn giản, nhưng đôi khi lại là câu hỏi phỏng vấn javascript core. Chỉ implement với một dòng duy nhất.

Anh em biết sử dụng gì không?. Đáp án là reduce!

var numArrayToSum = [1, 2, 3]

// Sử dụng reduce để tính tổng array
var sum = nums.reduce((x, y) => x + y);
console.log(sum); 
// 6

Nhớ sử dụng nha, kẻo lại viết loằng ngoằng tốn thời gian

9. Phương thức .lastIndexOf()

Nếu array có các phần tử trùng lặp với nhau, remove duplicate thì đã đành. Nhưng nếu remove đi thì sao tìm được index.

Trong khi bài toán lại yêu cầu tìm index của giá trị đó trong array?. Ô la, có ngay method lastIndexOf(). Xem xét ví dụ dưới đây:

var nums = [4, 5, 1, 6, 1];
var lastIndexOfOne = nums.lastIndexOf(1);
console.log(lastIndexOfOne); 
// 5 - tìm ra ngay index của 1 trong array - cuối cùng

10. Tạo mock javascript array data

Trường hợp muốn khởi tạo mock data array, hoặc tính toán cộng trừ nhân chia gì đó. Ta muốn fill một loạt 10 quả táo trong array?, có ngay fill method. Muốn bao nhiêu cũng có

var appleArray = new Array(3).fill("Apple");
console.log(appleArray); 
// ['Apple', 'Apple', 'Apple'] - khá tiện lợi chứ
Ù uôi, lắm chiêu trò thế!

11. Tham khảo

Cảm ơn anh em đã đọc bài, nhớ like facebook page để không bỏ lỡ bài viết hay nha!

Bài viết gốc được đăng tải tại kieblog.vn

Có thể bạn quan tâm:

Xem thêm Việc làm it hcm, đà nẵng, hà nội hấp dẫn trên TopDev