Hướng dẫn dùng turtioal JavaScript

Roger mở ứng dụng Medium, cuộn xuống những bài viết cũ hướng dẫn cách trở nên sáng tạo hơn, cách trở thành nhà kinh doanh thành công… Ngay sau đó, 1 dòng tiêu đề đập ngay vào mắt:

“Quên Angular đi. Quên React đi. Hãy đến với Tupress – 1 framework Javascript tối ưu”

Hmm, Roger tự thấy đây là thời điểm thích hợp để học thêm 1 framework mới khi anh chỉ vừa nghiên cứu Javascript chỉ mới vài tháng. Và sau khi đọc bài viết tràn ngập những cụm từ như “trực quan”, “linh hoạt” và “đa năng”, Roger chính thức bị chinh phục.

Hướng dẫn dùng turtioal JavaScript

Anh mở Macbook, search Google cụm “Tupress tutorial” và chọn kết quả đứng top. Tutorial này sẽ hướng dẫn cách xây dựng ứng dụng two-deux. Khi hoàn thành, ứng dụng này sẽ nhận 1 list danh sách các “số 2” trong Tiếng Anh (2, 2, 2, 2, 2, 2, 2) và chuyển sang tiếng Pháp (le 2, le 2, le 2, le 2, le 2, le 2).

Bước 1 là cài đặt Tupress.

Okie – Roger tự nhủ. Sau đó, anh phải cài Bistup – 1 wrapper nhẹ. Sau đó, anh phải cài Claster – Claster cung cấp 1 layer mỏng, unopinionated của methods và middleware. Dù không hiểu là cái gì nhưng Roger vẫn cứ cài đặt xem sao.

Cuối cùng, anh cài tiếp Pirend – 1 layer microservice RESTful API real-time để implement CRUD & AJAX bằng cách sử dụng JSON. Roger đoán là việc cài đặt này rất quan trọng, nếu không thì chắc không có nhiều từ viết tắt vậy đâu.

Hướng dẫn dùng turtioal JavaScript

Quá trình cài đặt (credit: tutsplus)

Sau khi mọi thứ hoàn tất, Roger rất mong chờ được bắt tay vào viết vài dòng code. Nhưng theo tutorial thì vẫn còn vài bước nữa trước khi anh được làm chuyện đó. Đầu tiên, anh phải install Git, provision 1 database trên nền tảng cloud, tạo 1 RESTful API server, implement các endpoints API, cập nhật dependencies và set up 1 project structure theo component.

“Ehhh” – Roger ca thán. Quá sức phức tạp. Nhưng mình đã cài đặt hàng tá thứ rồi, không thể bỏ được.

Hai tuần sau, cùng với 179 lần search Google, Roger cuối cùng cũng hiểu được cách set up mọi thứ. Anh mở cửa sổ terminal và gõ “tupr start”. Sau đó, Roger mở Chrome và điều hướng đến localhost:3000. Theo tutorial thì anh sẽ được thấy “Tupress hoạt động!”

Nhưng thay đó, lại… chẳng có gì. Hoàn toàn không có gì. Tupress đã không chạy.

Roger thở dài, tiếp tục mở console trong các developer tools của Chrome.

Và đây là những gì diễn ra.

Thật không ổn chút nào… (credit: Stack Overflow)

“Mình chỉ muốn viết vài dòng code và làm 1 ứng dụng đơn giản thôi mà” – Roger kêu thán. Không ngờ mọi việc lại trở nên khó khăn như này.

Nhưng anh vẫn không bỏ cuộc. Anh cut và paste từng console error lên Google, phát hiện trên Stack Overflow là tutorial mà anh xem 1 tháng trước đã sử dụng Tupress version 1.3.2, Bistup version 1.2.1, Claster version 3.7.2 và Pirend version 4.2.1.

Trong khi đó, Roger đã cài những version mới nhất của từng thứ và chúng đã không chạy được cùng nhau. Bên đó, Tupress 5 cũng vừa ra mắt và hoàn toàn khác với Tupress 1 (đã không có Tupress 2,3,4).

Trong 1 forum về lập trình khác, Roger phát hiện hầu hết dev đều cảm thấy không hài lòng với Bistup vì nó không đủ nhẹ, còn Claster không mỏng như những gì được hứa hẹn. Vì vậy, 1 lập trình viên ở Thụy Sĩ đã làm được 1 phương án thay thế khác (Focrux.js) tốt hơn nhiều.

7 tuần sau, sau khi uninstall và install lại mọi thứ nhiều lần, đọc lại hết trên Stack Overflow, xem từng video Youtube về các frameworks Javascript và đọc 13 quyển của bộ You Don’t Know S**t about Tupress, Roger cuối cùng cũng “giải thoát” hết các lỗi ra khỏi Chrome console.

“Oh yeah,” Roger reo lên.

Anh mở 1 cửa sổ terminal, gõ tupr start và khởi động localhost:3000– tại đây, cuối cùng những gì anh thấy là:

Hướng dẫn dùng turtioal JavaScript

(credit: baserails)

Tham khảo thêm các vị trí tuyển lập trình javascript lương cao tại Topdev

Javascript là ngôn ngữ lập trình phổ biến nhất trên thế giới trong suốt 20 năm qua. Nó cũng là một trong 3 ngôn ngữ chính của website. Vậy người mới bắt đầu nên học từ đâu?

Hàm (function)

Function là một trong những nền tảng cơ bản trong JavaScript. Một function trong JavaScript tương tự như một thủ tục — một tập hợp các câu lệnh thực hiện một tác vụ hoặc tính toán một giá trị, nhưng để một thủ tục đủ điều kiện là một hàm, nó phải nhận một số đầu vào và trả về một đầu ra trong đó có một số mối quan hệ rõ ràng giữa đầu vào và đầu ra. Để sử dụng một hàm, bạn phải xác định nó ở đâu đó trong phạm vi mà bạn muốn gọi nó.

Các loại hàm: Gồm có 5 loại function:

  • declaretion function
  • expression function
  • arrow function
  • anonymous function
  • gennerator function

Declaretion function

Một function (hàm) bao gồm từ khóa function tiếp theo là:

  • Tên của hàm
  • Danh sách các tham số, được đặt trong dấu ngoặc đơn và đực phần cách nhau bằng dấu phẩy.
  • Các câu lệnh javascript xác định hàm, được đặt trong dấu ngoặc nhọn {…}

Ví dụ, đoạn mã sau xác định một hàm đơn giản có tên là square:

Hướng dẫn dùng turtioal JavaScript

Hàm squase nhận một tham số number. Hàm bao gồm câu lệnh trả về tham số của hàm (number) được nhân với chính nó. Câu lệnh return chỉ định nghĩa giá trị được trả về bởi hàm.

Hướng dẫn dùng turtioal JavaScript

Các tham số dạng nguyên thủy (VD: number) được truyền cho hàm theo giá trị, nếu hàm thay đổi giá trị của tham số thì thay đổi này không ảnh hưởng đến biến trên toàn cục hay trong hàm đang được gọi.

Nhưng nếu truyền một đối tượng (tức là giá trị không phải nguyên thủy, VD: array, object) làm tham số của hàm, khi hàm thay đổi thuộc tính của đối tượng thì thay đổi này sẽ ảnh hưởng đến đến toàn cục và sẽ hiển thị được thay đổi đó bên ngoài hàm.

ví dụ:

Hướng dẫn dùng turtioal JavaScript

Expressions function

Ta có thể khai báo hàm như một biểu thức hàm, thay vì khai báo theo kiểu truyền thống.

Một function khai báo theo kiểu expressions function sẽ không cần phải đặt tên hàm.

ví dụ:

Hướng dẫn dùng turtioal JavaScript

Tuy nhiên, một expressions function vẫn có thể được đặt tên, để cho phép hàm tự tham chiếu đến chính nó và cũng giúp dễ dàng xác định hàm trong ngăn xếp của trình biên dịch.

Hướng dẫn dùng turtioal JavaScript

Việc dùng expressions function sẽ thuận tiện hơn khi muốn truyền một hàm làm đối số của một hàm khác.

ví dụ: 

Khởi tạo hàm map()

Hướng dẫn dùng turtioal JavaScript

Hàm map nhận một hàm được xác định bởi một biểu thức và thực thi nó cho mọi phần tử của mảng nhận được dưới dạng tham số thức hai:

Hướng dẫn dùng turtioal JavaScript

Lưu ý: Trong javascript, một hàm có thể được định nghĩa dựa vào điều kiện, ví dụ:

Hướng dẫn dùng turtioal JavaScript

Arrow function (cú pháp được ra mắt năm 2015 – ES6) 

Là một biểu thức hàm mũi tên, có cú pháp ngắn hơn so với biểu thức hàm. Các arrow function luôn là hàm ẩn danh

Ưu điểm:

Cú pháp hàm ngắn hơn: trong một số mô hình chức năng, các function ngắn hơn được khuyến cáo sử dụng. Ví dụ:

Hướng dẫn dùng turtioal JavaScript

Hàm không có ràng buộc của this

Trong các hàm thông thường, từ khóa this đại diện cho đối tượng là hàm, có thể là cửa sổ, tài liệu, một nút hoặc bất cứ thứ gì.

Với arrow function thì từ khóa this luôn đại diện cho đối tượng đã xác định hàm.

Xem ví dụ để thấy rõ sự khác biệt.

  • Cả 2 ví dụ đều gọi đến một hàm 2 lần, lần đầu tiên khi tải trang và một lần nữa khi người dùng click vào một nút.

VD1:

Hướng dẫn dùng turtioal JavaScript

VD2:

Hướng dẫn dùng turtioal JavaScript

Kết luận: Kết quả cho thấy ví dụ 1 trả về hai đối số khác nhau (windowsbutton), ví dụ 2 trả về đối tượng windows 2 lần, vì windows là chủ sở hữu của hàm.

Anonymous function

Là hàm ẩn danh (hay hàm không tên), cái này không có gì lạ cả.

Cách khai báo:

  • Dùng từ khóa function (trong trường hợp nếu function là tham só truyền vào một function khác thì chúng ta có thể không cần dùng từ khóa function)
  • Danh sách tham số của hàm, được đặt trong dấu ngoặc tròn và cách nhau bằng dấu phẩy.
  • Câu lệnh javascript định nghĩa hàm, được đặt trong dấu ngoặc nhọn {…}.

Vậy đặt ra câu hỏi:

  • Hàm không có tên thì ta làm cách nào để gọi hàm?
  • Anonymous function ra đời để làm gì?

C1: để sử dụng chúng ta có thể dùng cú pháp gán hoặc thêm dấu ngoặc tròn, và xem như đối tượng (hàm) này đã được hình thành và gọi ngay sau đó.

C2: để trả lời cho câu hàm này dùng để làm gì thì ta hãy đi vào ví dụ sau:

Ta có một hàm tính tổng 2 số ở thời điểm chạy và không dùng ở chỗ khác, thay vì định nghĩa ra một hàm riêng biệt và gọi ra thì ta dùng anonymous function ở đó. Vì đoan lệnh đó không được tái sử dụng ở nơi khác.

 Ví dụ:

Hàm bình thường:

Hướng dẫn dùng turtioal JavaScript

Hàm là một tham số của một hàm khác:

Hướng dẫn dùng turtioal JavaScript

Hoặc:

Hướng dẫn dùng turtioal JavaScript

Lại nảy sinh ra câu hỏi: 

Tại sao ta không viết trực tiếp đoạn mã ra và chạy một lần mà lại dùng anonymous function?

Trả lời cho câu hỏi trên: đúng chúng ta có thể không dùng anonymous function vẫn được.

Vấn đề xảy ra khi code của chúng ta nhiều hơn thì chúng ta sẽ khó kiểm soát và khắc phục nếu có vấn đề lỗi xảy ra…

Tóm lại: Anonymous function thường được sử dụng xử lý đoạn mã chỉ cần được gọi ở một chỗ duy nhất, ta có thể viết hàm riêng rồi sau đó truyền vào hàm vào chỗ đó.

Gennerator function (cú pháp ra mắt trong bản ES6 – 2015)

Generator function là một trong những chức năng không còn mới đối với lập trình viên Javascript. Từ phiên bản ECMAScript 2015 (ES6) nó đã được nhà phát triển đưa vào sử dụng bằng cú pháp khai báo “function*”, và tất nhiên là trả về một Generator object.

Cú pháp:

Hướng dẫn dùng turtioal JavaScript

Giải thích: Trong đó thì name: tên hàm. param: tham số đầu vào của hàm, tối đa 255 tham số. statements: phần thân chứa nội dung của hàm.

=> Gennerator function: đây là phần quan trọng nhưng rất ít được dùng, với loại function này mình sẽ chia sẻ ở một series khác!

Phạm vi của function

Các biến được định nghĩa bên trong một hàm không thể được truy cập từ bất kỳ đâu bên ngoài hàm, bởi vì biến chỉ được xác định trong phạm vi của hàm. Tuy nhiên, một hàm có thể truy cập tất cả các biến và hàm được xác định bên trong phạm vi mà nó được định nghĩa.

Nói cách khác, một hàm được xác định trong phạm vi toàn cục có thể truy cập tất cả các biến được xác định trong phạm vi toàn cục. Một hàm được định nghĩa bên trong một hàm khác cũng có thể truy cập vào tất cả các biến được xác định trong hàm cha của nó và bất kỳ biến nào khác mà hàm cha có quyền truy cập.

Hướng dẫn dùng turtioal JavaScript

Phạm vi và ngăn xếp của function

Đệ quy: Một hàm có thể gọi lại chính nó. có 3 cách để một hàm tham chiều đến chính nó.

  • Gọi thông qua tên function
  • arguments.callee
  • Một biến trong phạm vi trỏ đến hàm.

Hướng dẫn dùng turtioal JavaScript

Trong hàm thì tất cả các phần sau đây đều tương đương:

  • bar()
  • arguments.callee()
  • foo()

Một hàm gọi chính nó được gọi là một hàm đệ quy. Theo một số cách, đệ quy tương tự như một vòng lặp. Cả hai đều thực thi cùng một mã nhiều lần và cả hai đều yêu cầu một điều kiện (để tránh vòng lặp vô hạn, hay đúng hơn là đệ quy vô hạn trong trường hợp này).

Ví dụ, vòng lặp sau …

Hướng dẫn dùng turtioal JavaScript

… có thể được chuyển đổi thành một khai báo hàm đệ quy, theo sau là lời gọi hàm đó:

Hướng dẫn dùng turtioal JavaScript

Tuy nhiên, một số thuật toán không thể là các vòng lặp đơn giản. Ví dụ: lấy tất cả các nút của cấu trúc cây (chẳng hạn như DOM ) dễ dàng hơn thông qua đệ quy:

Hướng dẫn dùng turtioal JavaScript

So với hàm loop, bản thân mỗi lệnh gọi đệ quy tạo ra nhiều lệnh gọi đệ quy ở đây.

Có thể chuyển đổi bất kỳ thuật toán đệ quy nào sang thuật toán không đệ quy, nhưng logic thường phức tạp hơn nhiều và làm như vậy đòi hỏi phải sử dụng một ngăn xếp.

Trên thực tế, bản thân đệ quy sử dụng một ngăn xếp: ngăn xếp hàm. Hành vi giống như ngăn xếp có thể được nhìn thấy trong ví dụ sau:

Hướng dẫn dùng turtioal JavaScript

Các hàm và hàm đóng lồng nhau

Bạn có thể lồng một hàm trong một hàm khác. Hàm lồng nhau (bên trong) là riêng cho hàm chứa (bên ngoài) của nó.

Nó cũng tạo thành một sự đóng cửa . Bao đóng là một biểu thức (phổ biến nhất là một hàm) có thể có các biến tự do cùng với một môi trường liên kết các biến đó (“đóng” biểu thức).

Vì một hàm lồng nhau là một bao đóng, điều này có nghĩa là một hàm lồng nhau có thể “kế thừa” các đối số và biến của hàm chứa nó. Nói cách khác, hàm bên trong chứa đựng phạm vi của hàm bên ngoài.

Tóm lại:

  • Hàm bên trong chỉ có thể được truy cập từ các câu lệnh trong hàm bên ngoài.
  • Hàm bên trong tạo thành một bao đóng: hàm bên trong có thể sử dụng các đối số và biến của hàm bên ngoài, trong khi hàm bên ngoài không thể sử dụng các đối số và biến của hàm bên trong.

Ví dụ sau cho thấy các hàm lồng nhau:

Hướng dẫn dùng turtioal JavaScript

Vì hàm bên trong tạo thành một bao đóng, bạn có thể gọi hàm bên ngoài và chỉ định các đối số cho cả hàm bên ngoài và bên trong:

Hướng dẫn dùng turtioal JavaScript

Bảo tồn các biến

Lưu ý cách x được bảo quản khi inside được trả lại. Một bao đóng phải bảo toàn các đối số và biến trong tất cả các phạm vi mà nó tham chiếu. Vì mỗi cuộc gọi cung cấp các đối số có khả năng khác nhau, một bao đóng mới được tạo cho mỗi lệnh gọi tới outside. Bộ nhớ chỉ có thể được giải phóng khi inside không còn truy cập được.

Điều này không khác với việc lưu trữ các tham chiếu trong các đối tượng khác, nhưng thường ít rõ ràng hơn vì người ta không đặt trực tiếp các tham chiếu và không thể kiểm tra chúng.

Nhiều hàm lồng nhau

Các hàm có thể được lồng ghép nhiều lần. Ví dụ:

  • Một hàm (A) chứa một hàm (B), chính nó chứa một hàm (C).
  • Cả hai chức năng B và C biểu mẫu đóng ở đây. Vì vậy, B có thể truy cập A, và C có thể truy cập B.
  • Ngoài ra, vì C có thể truy cập B mà có thể truy cập A, C cũng có thể truy cập A.

Do đó, các bao đóng có thể chứa nhiều phạm vi; chúng chứa một cách đệ quy phạm vi của các hàm chứa nó. Đây được gọi là chuỗi phạm vi. (Lý do nó được gọi là “chuỗi” sẽ được giải thích sau.)

Hãy xem xét ví dụ sau:

Hướng dẫn dùng turtioal JavaScript

Trong ví dụ này, C truy cập B’s y và A’ x.

Điều này có thể được thực hiện bởi vì:

  1. B tạo thành một bao đóng bao gồm A (tức là, B có thể truy cập A các đối số và biến của).
  2. Chỉnh thành một sự đóng cửa bao gồm B.
  3. Bởi vì B bao gồm của bao gồm A, bao Ccủa bao gồm A, C có thể truy cập các đối số và biến của cả B và A ‘. Nói cách khác, C chuỗi các phạm vi của B và A, theo thứ tự mà.

Tuy nhiên, điều ngược lại là không đúng. A không thể truy cập C, vì A không thể truy cập bất kỳ đối số hoặc biến nào của B, C là biến của. Vì vậy, C vẫn còn riêng tư cho duy nhất B.

Xung đột tên

Khi hai đối số hoặc biến trong phạm vi của một bao đóng có cùng tên, sẽ xảy ra xung đột về tên . Nhiều phạm vi lồng nhau được ưu tiên hơn. Vì vậy, phạm vi bên trong nhất được ưu tiên cao nhất, trong khi phạm vi ngoài cùng có mức độ ưu tiên thấp nhất. Đây là chuỗi phạm vi. Đầu tiên trên chuỗi là phạm vi bên trong nhất và cuối cùng là phạm vi bên ngoài nhất. Hãy xem xét những điều sau:

Hướng dẫn dùng turtioal JavaScript

Cuộc xung đột tên xảy ra tại báo cáo kết quả return x * 2và là giữa inside’s tham số x và outside’ biến s x. Chuỗi phạm vi ở đây là {inside, outside, toàn cầu đối tượng}. Do đó, inside’s x được ưu tiên hơn outside’ s x, và 20 (inside’s x) được trả về thay vì 10 (outside’ s x).