Văn hay trong hiện tại, chữ tốt ở tương lai

Bạn chưa biết rõ về JavaScript đâu (You don't know JS yet) | Chương 2.7

Khám phá bản chất JavaScript từ lịch sử tên gọi, chuẩn ECMAScript và tính đa mô thức. Xóa bỏ lầm tưởng, xây nền tảng vững chắc cho nhà phát triển website.

33 phút đọc.

0 lượt xem.

Mở đầu

Trong chương này, chúng ta sẽ khép lại phần nội dung chính của cuốn sách bằng cách đi sâu vào khám phá một trong những khuôn mẫu thiết kế dùng để tổ chức mã nguồn có tầm ảnh hưởng sâu rộng nhất trong toàn bộ thế giới lập trình: hệ thống khối (module). Giống như những gì chúng ta sắp sửa được chiêm ngưỡng, các hệ thống khối về mặt bản chất được kiến tạo nên từ chính những mảnh ghép mà chúng ta đã vất vả thu thập được từ đầu đến giờ: nó chính là phần thưởng ngọt ngào đền đáp cho những nỗ lực không mệt mỏi của bạn trong việc làm chủ khái niệm phạm vi từ vựng và hiện tượng bao đóng.

Chúng ta đã tiến hành giải phẫu mọi ngóc ngách của phạm vi từ vựng, trải dài từ cái vùng đất bao la của không gian phạm vi toàn cục xuyên thấu xuống tận những không gian phạm vi khối bị lồng ghép sâu nhất, để rồi lặn ngụp trong những sự tinh vi phức tạp của vòng đời biến số. Bước tiếp theo, chúng ta đã biến phạm vi từ vựng thành một bàn đạp vững chắc để có thể nắm bắt được toàn bộ sức mạnh hủy diệt của hiện tượng bao đóng. Hãy cho phép bản thân một khoảnh khắc tĩnh lặng để nhìn lại xem mình đã tiến xa đến nhường nào trên cái chặng đường gian nan này; bạn thực sự đã sải những bước chân khổng lồ trong hành trình thấu hiểu JS ở một đẳng cấp sâu sắc hơn rất nhiều! Chủ đề cốt lõi xuyên suốt toàn bộ cuốn sách này luôn xoay quanh một chân lý: việc thấu hiểu và hoàn toàn làm chủ được khái niệm phạm vi cũng như bao đóng chính là chiếc chìa khóa vàng để có thể cấu trúc và tổ chức lại mã nguồn của chúng ta một cách chuẩn mực nhất, đặc biệt là trong việc đưa ra những quyết định sáng suốt xem nên chôn giấu thông tin ở những biến số nào cho hợp lý. Sứ mệnh tối thượng của chúng ta trong cái chương chốt sổ này là phải cảm nhận được cái cách mà các hệ thống khối đã hiện thân và đại diện cho sự quan trọng của những chủ đề đó như thế nào, qua đó nâng tầm chúng từ những khái niệm lý thuyết trừu tượng khô khan thành những cải tiến vật lý, thực tiễn có khả năng thay đổi cục diện trong việc kiến tạo nên các chương trình phần mềm.

Tính đóng gói và nguyên lý phơi bày tối thiểu (POLE)

Tính đóng gói (encapsulation) thường xuyên được giới hàn lâm xưng tụng như là một trong những nguyên lý rường cột của hệ tư tưởng lập trình hướng đối tượng (OO), thế nhưng bản chất của nó lại mang tính nền tảng và có khả năng ứng dụng phổ quát hơn rất nhiều so với cái khuôn khổ chật hẹp đó. Mục tiêu tối thượng của tính đóng gói là việc gom nhóm hoặc quy tụ về cùng một tọa độ những thông tin (dữ liệu) và hành vi (các hàm điện toán) có chung một sứ mệnh phục vụ cho một mục đích nhất định. Hoàn toàn độc lập với bất kỳ một thứ cú pháp hay cơ chế mã nguồn phức tạp nào, cái linh hồn thực sự của tính đóng gói hoàn toàn có thể được hiện thực hóa ở một mức độ thô sơ và đơn giản như việc sử dụng các tệp tin tách biệt để chứa chấp những mẩu nhỏ của tổng thể chương trình mang chung một mục đích. Nếu chúng ta gom toàn bộ mọi thứ có nhiệm vụ cung cấp năng lượng cho một danh sách các kết quả tìm kiếm và tống cổ chúng vào chung một cái tệp tin duy nhất có tên là danh-sach-tim-kiem.js, thì chúng ta đang thực thi tính đóng gói cho cái phân vùng đó của chương trình.

Cái xu hướng đang lên ngôi gần đây trong giới lập trình front-end hiện đại là việc tổ chức các ứng dụng xoay quanh kiến trúc Thành phần (Component), xu hướng này thậm chí còn đẩy khái niệm đóng gói đi xa hơn nữa đến một cảnh giới cực đoan. Đối với đại đa số lập trình viên, nó mang lại một cảm giác vô cùng thuận tự nhiên khi phải hợp nhất toàn bộ mọi thứ cấu thành nên cái danh sách kết quả tìm kiếm đó—thậm chí là vượt ra khỏi ranh giới của mã nguồn logic, ôm trọn luôn cả phần mã đánh dấu hiển thị (markup) và phần định dạng phong cách (styling)—vào chung một đơn vị logic chương trình duy nhất, một thứ thực thể hữu hình mà chúng ta có thể trực tiếp tương tác. Và sau đó chúng ta sẽ trang trọng dán cho cái tập hợp đó một cái nhãn là thành phần DanhSachTimKiem. Một mục tiêu then chốt khác của tính đóng gói là khả năng nắm quyền sinh sát trong việc kiểm soát mức độ hiển thị của những khía cạnh dữ liệu và chức năng nhất định đã được đóng gói. Hãy đánh thức lại ký ức từ Chương 6 về nguyên lý phơi bày tối thiểu (POLE), một nguyên lý luôn nỗ lực thiết lập một hàng rào phòng ngự chủ động để chống lại muôn vàn cạm bẫy sinh ra từ việc phơi bày không gian phạm vi quá đà; những cạm bẫy này tàn phá cả biến số lẫn các hàm điện toán một cách không thương tiếc.

Trong hệ sinh thái JS, cái cách thức phổ biến nhất mà chúng ta thường hay sử dụng để triển khai việc kiểm soát hiển thị chính là thông qua các cơ chế cơ học của khái niệm phạm vi từ vựng. Tư tưởng chủ đạo ở đây là hãy gom những mảnh ghép chương trình có chung họ hàng lại với nhau, và tiến hành thiết lập các hàng rào giới hạn quyền truy cập bằng mã nguồn một cách có chọn lọc đối với những phân vùng mà chúng ta coi là các chi tiết riêng tư. Những thứ không bị liệt vào danh sách riêng tư thì nghiễm nhiên sẽ được gán mác là công khai, sẵn sàng phơi mình ra cho toàn bộ chương trình truy cập. Hệ lụy tất yếu và thuận tự nhiên nhất sinh ra từ cái nỗ lực này chính là một cấu trúc tổ chức mã nguồn trở nên ưu việt hơn rất nhiều. Công việc xây dựng và bảo trì phần mềm sẽ trở nên nhẹ nhàng như đẩy xe hàng khi chúng ta luôn nắm rõ trong lòng bàn tay xem mọi thứ đang nằm ở cái xó xỉnh nào, với những đường ranh giới và những điểm kết nối hiện ra rõ như ban ngày. Nó đồng thời cũng giúp chúng ta dễ dàng duy trì được tiêu chuẩn chất lượng ở mức cao nếu như chúng ta có thể khôn khéo né tránh được những cái hố tử thần mang tên dữ liệu và chức năng bị phơi bày vô tội vạ. Đó chính là những phần thưởng vô giá và to lớn nhất mà việc tổ chức các chương trình JS thành các hệ thống khối mang lại.

Cấu trúc và phân loại hệ thống khối

Hiểu rõ sự khác biệt giữa hệ thống khối và các cấu trúc nhóm khác là chìa khóa để áp dụng đúng lúc đúng chỗ. Một hệ thống khối thực sự phải kết hợp được tính trạng thái và khả năng kiểm soát truy cập.

Sự khác biệt giữa hệ thống khối, không gian tên và cấu trúc dữ liệu

Một hệ thống khối về bản chất là một bộ sưu tập chứa đựng những dữ liệu và các hàm điện toán có mối quan hệ họ hàng với nhau (trong cái bối cảnh này, các hàm thường được gọi bằng một cái tên sang trọng hơn là phương thức), và nó được định hình bởi một bức tường ranh giới phân định rạch ròi giữa những chi tiết riêng tư bị chôn giấu và những chi tiết công khai được phép truy cập, cái phần công khai này thường được giới chuyên môn gọi bằng một cái tên là API công khai. Một hệ thống khối đồng thời cũng là một thực thể mang trong mình tính trạng thái: nó ôm giữ và duy trì một lượng thông tin nhất định trải dài theo dòng chảy của thời gian, đi kèm theo đó là một bộ sậu các chức năng dùng để thọc tay vào truy cập và cập nhật khối lượng thông tin đó.

Một mối bận tâm ở tầm nhìn vĩ mô hơn của khuôn mẫu hệ thống khối là việc dang tay ôm trọn lấy toàn bộ cái ý niệm về quá trình module hóa ở cấp độ hệ thống thông qua khái niệm liên kết lỏng lẻo (loose-coupling) và hàng tá các tuyệt kỹ kiến trúc chương trình cao siêu khác. Đó là một cái chủ đề vô cùng phức tạp và rối rắm, vượt xa khỏi cái khuôn khổ thảo luận chật hẹp của chúng ta, nhưng chắc chắn là một thứ vô cùng xứng đáng để bạn đầu tư thời gian nghiên cứu sâu hơn ở ngoài phạm vi của cuốn sách này. Để có thể mường tượng ra một bức tranh sắc nét hơn về việc rốt cuộc một hệ thống khối mang hình hài như thế nào, chúng ta hãy cùng nhau đặt lên bàn cân so sánh một vài đặc tính của hệ thống khối với những khuôn mẫu mã nguồn vốn dĩ cực kỳ hữu dụng nhưng lại chưa đủ tuổi để được gọi là hệ thống khối.

Nếu bạn chỉ đơn thuần gom một tập hợp các hàm có họ hàng với nhau lại thành một cục, mà hoàn toàn trống rỗng không có bất kỳ một dữ liệu nào, thì bạn thực sự chưa đạt đến cảnh giới đóng gói như những gì mà khái niệm hệ thống khối hứa hẹn. Cái tên gọi chuẩn xác và phản ánh đúng bản chất hơn rất nhiều cho cái kiểu gom nhóm các hàm phi trạng thái này chính là một không gian tên (namespace). Cái biến Tiện Ích ở đây đích thị là một bộ sưu tập chứa đầy những công cụ hữu ích, thế nhưng tất cả bọn chúng đều chỉ là những hàm điện toán mang tính chất độc lập với trạng thái. Việc gom tụ các chức năng lại với nhau về cơ bản luôn luôn là một thói quen thực hành tốt, nhưng hành động đó không đủ phép màu để biến cái đống này thành một hệ thống khối. Nói một cách chính xác hơn, chúng ta vừa mới nhào nặn ra một cái không gian tên mang tên Tiện Ích và tiến hành sắp xếp các hàm nằm ngoan ngoãn dưới trướng của nó.

Ngay cả trong kịch bản bạn đã chịu khó nhét chung cả dữ liệu lẫn các hàm có tính trạng thái vào cùng một rọ, thế nhưng nếu như bạn lại lười biếng và không thiết lập bất kỳ một hàng rào giới hạn hiển thị nào cho đống hổ lốn đó, thì bạn lại một lần nữa dừng bước ngay trước ngưỡng cửa của khía cạnh POLE trong triết lý đóng gói; và sẽ là một sự khiên cưỡng vô cùng nếu như bạn cứ cố đấm ăn xôi dán cho cái mớ đó cái nhãn hệ thống khối. Hãy cùng xem xét: Bởi vì cái biến bản ghi là một cục dữ liệu hoàn toàn hớ hênh phơi mình ra cho bàn dân thiên hạ truy cập, chứ không hề được chôn giấu cẩn thận đằng sau một cái API công khai nào cả, thế nên cái biến Sinh Viên ở đây thực chất chẳng phải là một hệ thống khối nào sất. Biến Sinh Viên này quả thực có sở hữu cái khía cạnh dữ-liệu-và-chức-năng của tính đóng gói, thế nhưng nó lại đánh rơi mất cái khía cạnh kiểm-soát-hiển-thị. Cái nhãn dán phù hợp và phản ánh đúng bản chất nhất cho thứ này chỉ là một bản sao của một cấu trúc dữ liệu mà thôi.

Đặc điểm cốt lõi của hệ thống khối cổ điển

Để có thể hiện thân và ôm trọn lấy toàn bộ cái tinh thần cốt lõi của khuôn mẫu hệ thống khối, chúng ta không chỉ khát khao đòi hỏi sự hiện diện của tính gom nhóm và tính trạng thái, mà yếu tố mang tính chất sống còn là phải có sự kiểm soát truy cập thông qua mức độ hiển thị (ranh giới giữa riêng tư và công khai). Hãy cùng nhau thực hiện một phép thuật biến hình để nâng cấp cái biến Sinh Viên từ phần trước trở thành một hệ thống khối đích thực. Chúng ta sẽ khởi động bằng một hình thái mà cá nhân tôi thích gọi là hệ thống khối cổ điển, một thứ vốn dĩ đã từng được giới giang hồ xưng tụng bằng cái tên hệ thống khối hé mở (revealing module) khi nó vừa mới chập chững bước ra ánh sáng vào những năm đầu của thập niên 2000.

Biến Sinh Viên giờ đây đã chính thức lột xác trở thành một bản sao của một hệ thống khối. Nó tự hào trình diễn một cái API công khai sở hữu đúng một phương thức duy nhất: lấy tên. Cái phương thức này được ban cho đặc quyền thọc tay vào và truy cập cái đống dữ liệu bản ghi đang bị giấu kín trong bóng tối. Tôi phải lên tiếng gióng một hồi chuông cảnh báo rằng việc cái đống dữ liệu sinh viên được nhét cứng (hard-coded) một cách tường minh vào ngay giữa lòng cái định nghĩa hệ thống khối này hoàn toàn chỉ nhằm mục đích minh họa cho dễ hiểu mà thôi. Một hệ thống khối điển hình trong thế giới thực của chương trình bạn viết ra sẽ phải đón nhận mớ dữ liệu này từ một nguồn cung cấp bên ngoài, đại loại như móc từ cơ sở dữ liệu lên, từ các tệp tin dữ liệu JSON, qua các lời gọi Ajax, v.v. Mớ dữ liệu đó sau đó sẽ được hệ thống tiêm thẳng vào trong cái bản sao của hệ thống khối, thường là thông qua (các) phương thức được phơi bày trên cái API công khai của hệ thống khối đó.

Vậy thì cái hình thái hệ thống khối cổ điển này vận hành bằng cái cơ chế ma quỷ nào? Hãy dồn sự chú ý vào việc cái bản sao của hệ thống khối đã được hệ thống đẻ ra thông qua việc kích nổ chạy cái cấu trúc IIFE mang tên định nghĩa sinh viên. Cái cấu trúc IIFE này sẽ nôn ra một đối tượng (được tôi dán nhãn là API công khai), và cái đối tượng đó lại sở hữu một thuộc tính chứa đựng một sợi dây tham chiếu trỏ thẳng đến cái hàm nội bộ lấy tên. Việc ưu ái dán cái nhãn API công khai cho cái đối tượng đó hoàn toàn chỉ là một sở thích cá nhân mang tính phong cách của riêng tôi. Cái đối tượng đó hoàn toàn có quyền mang bất kỳ cái tên quái quỷ nào mà bạn thích (JS hoàn toàn không thèm đếm xỉa đến chuyện đó), hoặc thậm chí bạn có thể chơi ngông bằng cách nôn thẳng cái đối tượng đó ra luôn mà chẳng thèm gán nó vào bất kỳ một cái biến nội bộ có tên nào cả. Những mổ xẻ sâu hơn về cái sự lựa chọn này sẽ xuất hiện ở Phụ lục A. Từ góc nhìn của thế giới bên ngoài, khi cái lời gọi Sinh Viên.lấy tên được phát động, nó thực chất đang kích nổ cái hàm nội bộ đã bị phơi bày này, và nhờ phép màu nào đó, cái hàm này vẫn duy trì được quyền truy cập vào cái biến nội bộ bản ghi thông qua sức mạnh của bao đóng. Bạn tuyệt đối không bị ép buộc phải nôn ra một cái đối tượng mang trong mình một cái hàm với tư cách là một trong những thuộc tính của nó. Bạn hoàn toàn có quyền nôn thẳng ra một cái hàm luôn cho nhẹ nợ, để thay thế hoàn toàn cho vị trí của cái đối tượng. Cách làm đó vẫn đáp ứng hoàn hảo toàn bộ những yêu cầu cốt lõi khắt khe nhất của một hệ thống khối cổ điển.

Nhờ vào cái cơ chế vận hành vi diệu của phạm vi từ vựng, cái hành động định nghĩa các biến số và các hàm nằm lọt thỏm bên trong cái hàm định nghĩa hệ thống khối vòng ngoài của bạn đã tự động biến toàn bộ mớ đó theo mặc định trở thành những tài sản riêng tư bất khả xâm phạm. Chỉ duy nhất những cái thuộc tính nào được bạn ưu ái đắp thêm vào cái đối tượng API công khai được nôn ra từ cái hàm đó thì mới có cơ may được xuất khẩu ra thế giới bên ngoài để cho bàn dân thiên hạ xài chùa. Việc viện đến sức mạnh của một cấu trúc IIFE như một lời khẳng định ngầm rằng chương trình của chúng ta từ đầu đến cuối sẽ chỉ bao giờ cần đến đúng một cái bản sao trung tâm duy nhất của cái hệ thống khối đó, một thứ thường được giới giang hồ gọi bằng cái thuật ngữ độc bản (singleton). Và quả thực là như vậy, cái ví dụ cụ thể này quá đỗi đơn giản đến mức chúng ta hoàn toàn không thể bới móc ra được một lý do hợp lý nào để phải cần đến nhiều hơn đúng một cái bản sao của hệ thống khối Sinh Viên.

Nhưng giả sử như chúng ta đang khát khao muốn nhào nặn ra một hệ thống khối mang trong mình cái khả năng hỗ trợ đẻ ra nhiều bản sao trong chương trình, thì chúng ta chỉ cần thực hiện một đường quyền biến hóa nho nhỏ cho cái đoạn mã: Thay vì bắt cái hàm định nghĩa sinh viên phải khoác lên mình cái vỏ bọc của một cấu trúc IIFE, chúng ta sẽ gỡ bỏ nó và chỉ định nghĩa nó như một cái hàm độc lập bình thường, một cái thứ mà trong cái ngữ cảnh này thường được giang hồ xưng tụng bằng cái tên hàm nhà máy sản xuất hệ thống khối (module factory). Sau đó, chúng ta sẽ triệu hồi cái nhà máy sản xuất hệ thống khối này ra chạy, qua đó nặn ra một cái bản sao của hệ thống khối mà chúng ta đã dán cho nó cái nhãn toàn thời gian. Cái bản sao hệ thống khối này sẽ kéo theo sự ra đời của một cái bản sao mới toanh cho cái không gian phạm vi nội bộ, và hệ lụy tất yếu là nó cũng sẽ đẻ ra một cái bao đóng hoàn toàn mới mà cái hàm lấy tên sẽ dùng để đè lên cái biến bản ghi. Lời gọi hàm toàn thời gian.lấy tên giờ đây sẽ có nhiệm vụ kích nổ cái phương thức trực thuộc đúng cái bản sao cụ thể đó.

Vậy để chốt hạ lại cho cái định nghĩa rốt cuộc thứ gì mới đủ tư cách làm nên một hệ thống khối cổ điển:

– Bắt buộc phải có sự hiện diện của một không gian phạm vi bao bọc bên ngoài, thường là được sinh ra từ một cái hàm nhà máy sản xuất hệ thống khối đã từng được hệ thống gọi ra chạy ít nhất một lần.

– Cái không gian phạm vi nội bộ nằm bên trong hệ thống khối bắt buộc phải che giấu ít nhất một mẩu thông tin đóng vai trò đại diện cho trạng thái của cái hệ thống khối đó.

– Hệ thống khối bắt buộc phải nôn ra trên cái API công khai của nó một sợi dây tham chiếu trỏ đến ít nhất là một cái hàm, và cái hàm đó lại phải thực hiện hành vi bao đóng đè lên cái trạng thái bị giấu kín của hệ thống khối (để đảm bảo rằng cái trạng thái đó thực sự được bảo tồn nguyên vẹn).

Khả năng rất cao là bạn sẽ còn va chạm với vô số những cái biến thể dị hợm khác của cái triết lý hệ thống khối cổ điển này, và chúng ta sẽ cùng nhau xẻ thịt chúng một cách chi tiết hơn trong Phụ lục A.

Định dạng hệ thống khối hiện đại

Sự phát triển của JavaScript đã mang đến những chuẩn mực mới cho hệ thống khối, từ CommonJS trong Node.js đến ES Modules (ESM) hiện đại. Mỗi định dạng có những quy tắc và cú pháp riêng để quản lý tính riêng tư và xuất nhập khẩu.

CommonJS: Tiêu chuẩn hệ thống khối dựa trên tệp

Quay ngược lại Chương 4, chúng ta đã từng vén màn giới thiệu về cái định dạng hệ thống khối CommonJS, một thứ vũ khí được Node cực kỳ sủng ái. Trái ngược hoàn toàn với cái định dạng hệ thống khối cổ điển vừa mới được mổ xẻ ở phần trước, nơi mà bạn hoàn toàn có quyền tự do ném cái nhà máy sản xuất hệ thống khối hay cấu trúc IIFE vào nằm chung mâm với bất kỳ một cái đống mã nguồn thập cẩm nào khác, kể cả là chung mâm với các hệ thống khối khác, thì định dạng hệ thống khối CommonJS lại bị trói buộc chặt chẽ vào cấu trúc tệp tin (file-based); một hệ thống khối chỉ được phép cư ngụ trong một tệp tin duy nhất. Hãy cùng nhau xào xáo lại cái ví dụ hệ thống khối của chúng ta để ép nó phải tuân thủ nghiêm ngặt cái định dạng đó.

Các định danh bản ghi và lấy tên hiện tại đang nằm chễm chệ ở cái không gian phạm vi cấp cao nhất của cái hệ thống khối này, thế nhưng đó lại hoàn toàn không phải là cái không gian phạm vi toàn cục (như những gì đã được bóc trần ở Chương 4). Vì lẽ đó, toàn bộ mọi thứ ngự trị ở đây theo mặc định đều là tài sản riêng tư thuộc quyền sở hữu của riêng cái hệ thống khối đó. Để có thể phơi bày một thứ gì đó ra cái API công khai của một hệ thống khối CommonJS, nhiệm vụ của bạn là phải đắp thêm một cái thuộc tính vào cái đối tượng trống rỗng đang được hệ thống dâng tận miệng mang tên xuất hệ thống khối (module.exports). Trong một vài cái xó xỉnh chứa những đoạn mã di sản cổ đại, rất có thể bạn sẽ đụng độ với những sợi dây tham chiếu chỉ trỏ trơ trọi vào mỗi cái chữ xuất (exports), thế nhưng để bảo vệ sự trong sáng và khả năng đọc hiểu của mã nguồn, bạn phải luôn luôn tập thói quen định danh cái sợi dây tham chiếu đó một cách đầy đủ bằng cái tiền tố module.. Vì mục đích duy trì một phong cách viết mã thanh lịch, tôi luôn có sở thích gom toàn bộ cái đống xuất của mình vứt lên tuốt trên đầu và ném cái phần triển khai chi tiết của hệ thống khối xuống tuốt dưới đáy. Nhưng sự thật là mấy cái lệnh xuất này hoàn toàn có quyền nằm lổm ngổm ở bất kỳ cái tọa độ nào cũng được. Lời khuyên xương máu của tôi là bạn nên gom chung tất cả chúng lại thành một cục, ném lên đỉnh hoặc dìm xuống đáy của cái tệp tin đều được.

Có một vài nhà phát triển lại mắc phải một cái thói quen tai hại là đi đè bẹp và thay thế luôn cái đối tượng xuất mặc định, kiểu như thế này: Cái cách tiếp cận này ẩn chứa vô vàn những cái bẫy dị hợm, bao gồm cả những hành vi điên rồ ngoài sức tưởng tượng nếu như lỡ có nhiều cái hệ thống khối kiểu vậy lại đi phụ thuộc vòng tròn vào nhau. Chính vì những rủi ro đó, tôi kịch liệt phản đối việc bạn đi thay máu cho cái đối tượng đó. Nếu như cái tham vọng của bạn là muốn ném ra cùng một lúc hàng tá thứ xuất, và muốn lợi dụng cái cú pháp định nghĩa bằng đối tượng trực tiếp, thì bạn hoàn toàn có thể chơi theo kiểu này để thay thế. Cái cơ chế ma thuật đang diễn ra ở đây là việc hệ thống đang tiến hành định nghĩa một cái đối tượng trực tiếp { .. } chứa đựng toàn bộ cái API công khai cho hệ thống khối của bạn, và ngay sau đó cái phương thức gán đối tượng (Object.assign) sẽ lao vào thực hiện một cuộc sao chép nông toàn bộ mớ thuộc tính đó và dán thẳng lên cái đối tượng module.exports đang tồn tại sẵn, thay vì thô bạo đè bẹp nó. Đây là một sự thỏa hiệp hoàn hảo giữa sự tiện lợi và một hành vi hệ thống khối an toàn hơn rất nhiều.

Để có thể lôi cổ một cái bản sao hệ thống khối khác vào nhét chung vào cái hệ thống khối/chương trình hiện tại của bạn, hãy triệu hồi cái phương thức yêu cầu (require) của Node. Giả định rằng cái hệ thống khối này đang nằm phủ bụi ở cái tọa độ đường dẫn /path/to/student.js, thì đây sẽ là cái con đường để chúng ta thọc tay vào nó. Cái biến Sinh Viên giờ đây đã ôm trọn một sợi dây tham chiếu trỏ thẳng đến cái API công khai của cái hệ thống khối ví dụ của chúng ta. Các hệ thống khối CommonJS mang trong mình cái bản chất hành vi của những bản sao độc bản (singleton instances), một nét tương đồng đến kỳ lạ với cái phong cách định nghĩa hệ thống khối bằng cấu trúc IIFE đã được phơi bày trước đó. Bất chấp việc bạn có rảnh rỗi gọi lệnh yêu cầu (require) đè lên cùng một cái hệ thống khối bao nhiêu ngàn lần đi chăng nữa, thì thứ mà bạn thu về cũng chỉ thuần túy là những sợi dây tham chiếu nhái lại trỏ đến cùng một cái bản sao hệ thống khối dùng chung duy nhất đó mà thôi.

Lệnh yêu cầu (require) là một thứ vũ khí hoạt động theo nguyên tắc được ăn cả ngã về không; nó sẽ nuốt trọn và trả về một sợi dây tham chiếu trỏ đến toàn bộ cái API công khai đã được phơi bày của cái hệ thống khối đó. Để có thể thực hiện một pha truy cập một cách hiệu quả và chỉ nhắm vào một bộ phận cấu thành nên cái API đó, cái tuyệt kỹ thường được giới giang hồ sử dụng trông sẽ như thế này. Hoàn toàn tương đồng với cái định dạng hệ thống khối cổ điển, những cái phương thức đã được hệ thống xuất khẩu công khai ra cái API của một hệ thống khối CommonJS đều là những kẻ ôm giữ các bao đóng đè lên những chi tiết nội tạng bí mật của hệ thống khối đó. Đó chính là cái cơ chế quyền năng giúp duy trì được cái trạng thái độc bản của hệ thống khối một cách bền bỉ xuyên suốt toàn bộ vòng đời sống sót của chương trình. Trong những cái câu lệnh yêu cầu của Node, những cái đường dẫn không mang tính chất tuyệt đối sẽ ngầm định tự động gắn thêm cái đuôi tệp tin .js và bắt đầu lùng sục trong cái ổ node_modules.

ESM: Cú pháp xuất nhập khẩu chuẩn hóa

Định dạng ESM chia sẻ khá nhiều nét tương đồng với cái định dạng CommonJS. ESM cũng là một kẻ cuồng tín với cấu trúc tệp tin, và các bản sao hệ thống khối của nó cũng là những kẻ độc bản thứ thiệt, với toàn bộ mọi thứ bên trong theo mặc định đều bị dán nhãn riêng tư. Một cái điểm khác biệt mang tính chất bước ngoặt là toàn bộ các tệp tin ESM đều bị hệ thống mặc định ép phải chạy ở chế độ nghiêm ngặt (strict-mode), mà hoàn toàn không cần phải lạy lục van xin bằng cách nhét cái chỉ thị _use strict_ lên trên đỉnh đầu. Tuyệt đối không có bất kỳ một con đường lách luật nào để bạn có thể định nghĩa ra một cái ESM chạy ở chế độ lỏng lẻo (non-strict-mode).

Thay vì sử dụng cái đối tượng module.exports như trong CommonJS, ESM lại trình làng một cái từ khóa xuất (export) mới toanh dùng để phơi bày một thứ gì đó ra cái API công khai của hệ thống khối. Từ khóa nhập (import) cũng oai vệ bước ra chiếm lấy cái ngai vàng của câu lệnh yêu cầu (require). Hãy cùng nhau xào xáo lại cái tệp students.js để ép nó phải quy phục cái định dạng ESM. Cái điểm khác biệt duy nhất hiện diện ở đây chính là cái câu lệnh xuất lấy tên. Y hệt như trước đây, những cái câu lệnh xuất này hoàn toàn có quyền ngang nhiên xuất hiện lổm ngổm ở bất kỳ ngóc ngách nào xuyên suốt cái tệp tin, thế nhưng có một đạo luật thép là từ khóa xuất bắt buộc phải nằm chễm chệ ở cái không gian phạm vi cấp cao nhất; nó vĩnh viễn không được phép lọt thỏm vào bên trong bụng của bất kỳ một khối mã hay một cái hàm nào khác.

ESM cung cấp cho chúng ta một rổ những sự biến tấu dị hợm về cái cách thức mà các câu lệnh xuất có thể được cấu hình. Bất chấp một sự thật là cái từ khóa xuất đang trơ trẽn đứng chắn ngay trước mặt cái từ khóa hàm ở đây, thì cái hình thái này về bản chất vẫn là một khai báo hàm và chỉ tình cờ được hệ thống xuất khẩu đi mà thôi. Nói một cách hàn lâm hơn, cái định danh lấy tên này đã được kéo lên theo kiểu của hàm (xem Chương 5), thế nên nó nghiễm nhiên được quyền tự do tung hoành xuyên suốt toàn bộ không gian phạm vi của cái hệ thống khối đó. Một sự biến tấu hợp pháp khác: Cái này được giới giang hồ xưng tụng bằng một cái tên mỹ miều là xuất mặc định (default export), và nó mang trong mình một cái hệ tư tưởng ngữ nghĩa hoàn toàn khác biệt so với những cái đám xuất khẩu còn lại. Chốt lại vấn đề, một cái xuất mặc định về cơ bản chỉ là một cái lối đi tắt dành cho những kẻ đang có ý định tiêu thụ cái hệ thống khối đó khi chúng sử dụng lệnh nhập, nó quăng cho họ một cái thứ cú pháp cụt lủn và tiện lợi hơn rất nhiều khi mà thứ duy nhất chúng khát khao chỉ là đúng cái thành viên API mặc định duy nhất này. Những cái thứ xuất khẩu không mang cái nhãn mặc định thì sẽ bị gom chung vào cái đám gọi là xuất có tên (named exports).

Từ khóa nhập (import)—cũng giống y hệt như xuất (export), nó bị giáng một cái vòng kim cô là chỉ được phép vác mặt ra ở cái tầng cao nhất của một cái ESM, tuyệt đối cấm tiệt việc chui rúc vào bên trong bất kỳ một khối mã hay một cái hàm nào—đồng thời cũng sở hữu một bộ sưu tập khổng lồ những sự biến tấu trong cú pháp. Cái hình thái đầu tiên được vinh danh là nhập có tên (named import). Như những gì đập thẳng vào mắt bạn, cái hình thái này thực chất chỉ thọc tay vào và moi ra đúng những cái thành viên API công khai đã được chỉ đích danh từ một cái hệ thống khối (và lạnh lùng ngó lơ toàn bộ những cái thứ không được xướng tên một cách tường minh), sau đó nó sẽ hốt toàn bộ mớ định danh đó và ném thẳng vào cái không gian phạm vi tầng cao nhất của cái hệ thống khối hiện hành. Cái kiểu nhập khẩu này sẽ gợi lại một cảm giác vô cùng quen thuộc đối với những tín đồ đã từng quen xài cái trò nhập khẩu gói (package) trong những cái ngôn ngữ kiểu như Java. Hàng tá các thành viên API có thể bị nhồi nhét chung vào bên trong cái bộ ngoặc nhọn { .. }, phân tách nhau bằng những cái dấu phẩy. Một cái trò nhập có tên cũng hoàn toàn có khả năng bị đổi tên bằng cách mượn sức của từ khóa như (as).

Nếu như lấy tên tình cờ lại là một cái xuất mặc định của cái hệ thống khối đó, thì chúng ta có thể lôi cổ nó vào theo kiểu này. Cái điểm khác biệt duy nhất bóc trần ở đây là việc chúng ta đã thẳng tay vứt bỏ cái cặp ngoặc { } đang bao bọc lấy cái ràng buộc nhập khẩu. Nếu như bạn đang nổi máu muốn chơi trò trộn lẫn một cái nhập mặc định chung mâm với những cái đám nhập có tên khác. Đặt lên bàn cân so sánh, một sự biến tấu mang tính chất kinh thiên động địa khác của lệnh nhập được gắn mác là nhập không gian tên (namespace import). Một điều rành rành hiển nhiên là, cái dấu _ mang một quyền năng tối thượng có khả năng nhập khẩu tuốt luốt mọi thứ đã được xuất khẩu ra cái API đó, bất kể là mặc định hay có tên, và sau đó nó sẽ nhét gọn toàn bộ cái mớ hỗn độn đó vào chung dưới một cái định danh không gian tên duy nhất đúng như những gì đã được thiết lập. Cái cách tiếp cận này phô diễn một sự tương đồng đến rợn người so với cái hình thái của các hệ thống khối cổ điển từng thống trị phần lớn chiều dài lịch sử của JS. Tính đến cái khoảnh khắc mà những dòng chữ này được gõ ra, các trình duyệt web hiện đại đã dang tay ôm trọn và hỗ trợ cho cái định dạng ESM được vài năm nay rồi, thế nhưng cái sự hỗ trợ (gọi là có vẻ) ổn định của Node dành cho ESM thì lại là một câu chuyện khá mới mẻ, và nó đã phải trải qua một quá trình tiến hóa đẫm máu kéo dài trong một khoảng thời gian khá lâu. Cuộc tiến hóa này gần như chắc chắn sẽ còn tiếp diễn trong vòng một năm tới hoặc thậm chí là lâu hơn nữa; sự kiện ES6 chính thức mang ESM cấy ghép vào JS thực sự đã kích nổ vô số những mối lo ngại nhức nhối về khả năng tương thích đối với quá trình giao tiếp (interop) của Node với những cái hệ thống khối CommonJS cổ lỗ sĩ. Hãy luôn cập nhật tình hình bằng cách soi kỹ tài liệu ESM của Node để không bỏ lỡ bất kỳ một tình tiết mới nhất nào: https://nodejs.org/api/esm.html.

Lời kết hành trình

Bất chấp việc bạn đang tôn thờ cái định dạng hệ thống khối cổ điển (trên trình duyệt hay trên Node), định dạng CommonJS (trên Node), hay cái định dạng ESM tân tiến (trên trình duyệt hay trên Node), thì hệ thống khối vẫn vĩnh viễn là một trong những thứ vũ khí mang sức mạnh hủy diệt và hiệu quả bậc nhất để bạn có thể kiến tạo cấu trúc và tổ chức lại toàn bộ hệ thống chức năng cũng như dữ liệu cho cái chương trình của mình. Khuôn mẫu hệ thống khối chính là cái đích đến chốt hạ cho cuộc hành trình mà chúng ta đã dấn thân trong suốt cuốn sách này, một cuộc hành trình nhằm mục đích lĩnh hội cái cách mà chúng ta có thể sử dụng những bộ luật thép của phạm vi từ vựng để sắp đặt các biến số và các hàm vào đúng cái tọa độ sinh ra là để dành cho chúng. POLE chính là cái tư thế phòng ngự riêng tư theo mặc định vô cùng chủ động mà chúng ta luôn luôn phải khắc cốt ghi tâm, nhằm đảm bảo một sự chắc chắn tuyệt đối rằng chúng ta sẽ né tránh được thảm họa phơi bày quá đà và chỉ đành phải tương tác với một cái bề mặt API công khai nhỏ bé và chật hẹp nhất có thể.

Và nằm ẩn sâu bên dưới những cái hệ thống khối đó, cái phép màu chịu trách nhiệm gồng gánh và duy trì toàn bộ trạng thái hệ thống khối của chúng ta không gì khác chính là những cái bao đóng đang điên cuồng bòn rút sức mạnh từ hệ thống phạm vi từ vựng. Vậy là toàn bộ cái khối lượng văn bản chính đã chính thức khép lại. Xin gửi đến bạn một lời chúc mừng nồng nhiệt nhất vì đã sống sót qua một cuộc hành trình dài đến như vậy! Như những gì tôi đã lặp đi lặp lại không biết bao nhiêu lần xuyên suốt cuốn sách, đây thực sự là một cái thời điểm vàng để bạn bấm nút tạm dừng, lùi lại một bước để tĩnh tâm suy ngẫm, và bắt tay vào việc thực hành những cái thứ cao siêu mà chúng ta vừa mới nhét vào đầu. Khi bạn đã cảm thấy tinh thần thực sự sảng khoái và đôi chân đã sẵn sàng bước tiếp, hãy mạnh dạn lật sang phần phụ lục, nơi sẽ đưa bạn lặn sâu hơn nữa vào những cái ngóc ngách tăm tối nhất của những chủ đề này, và đồng thời cũng sẽ ném cho bạn những cái bài tập thực hành hóc búa để thử thách và rèn rũa lại toàn bộ những thứ mà bạn đã lĩnh hội được.

Chuyên mục kyle-simpson

Chuyên mục thu-vien

Tiểu sử nhà thơ Nguyễn Khoa Điềm

Tiểu sử nhà thơ Nguyễn Khoa Điềm

Khoa Điềm từng làm báo Vùng lên của sinh viên Huế cùng với Trần Vàng Sao. Ban đầu, việc viết thơ của ông chỉ nhằm đáp ứng yêu cầu của tòa soạn, cần có một.

Tiểu sử nhà thơ Nguyễn Khoa Điềm
Tiểu sử nhà văn Nam Cao

Tiểu sử nhà văn Nam Cao

Sang và tổng Cao Đà quê ông, thể hiện sự gắn bó sâu sắc với mảnh đất quê hương.Cuộc đời của nhà văn Nam Cao là hành trình vất vả của một con người tài năng.

Tiểu sử nhà văn Nam Cao
Tiểu sử nhà văn Nguyễn Thành Long

Tiểu sử nhà văn Nguyễn Thành Long

Có được một tác phẩm sống mãi cùng năm tháng cũng đã là quý giá.Trong bối cảnh văn học Việt Nam sau 1945, Nguyễn Thành Long được xếp vào nhóm những nhà văn.

Tiểu sử nhà văn Nguyễn Thành Long
Tiểu sử nhà văn Hoàng Phủ Ngọc Tường

Tiểu sử nhà văn Hoàng Phủ Ngọc Tường

Lâm Thị Mỹ Dạ. Đây là minh chứng rõ ràng cho sự ghi nhận của cộng đồng văn học và nhà nước đối với những đóng góp của ông.Giải thưởng Hội Nhà văn Việt Nam.

Tiểu sử nhà văn Hoàng Phủ Ngọc Tường
Tiểu sử nhà thơ Xuân Quỳnh

Tiểu sử nhà thơ Xuân Quỳnh

Quỳnh vượt xa ranh giới của một nhà thơ thông thường, bà đã trở thành một hiện tượng văn hóa cultural phenomenon, một biểu tượng của tình yêu và phẩm chất.

Tiểu sử nhà thơ Xuân Quỳnh
Tiểu sử nhà văn Tô Hoài

Tiểu sử nhà văn Tô Hoài

Bắc, Tây Bắc.Năm 1950, ông về công tác ở Hội Văn nghệ Việt Nam, từng làm Thư ký Tòa soạn Tạp chí Văn nghệ. Những trải nghiệm trong thời kỳ kháng chiến khôn.

Tiểu sử nhà văn Tô Hoài
Tiểu sử nhà thơ Chế Lan Viên

Tiểu sử nhà thơ Chế Lan Viên

Lan Viên là một trong những nhà thơ được độc giả yêu mến nhất, thơ ông được truyền tụng rộng rãi qua nhiều thế hệ. Điều này không chỉ vì giá trị nghệ thuật.

Tiểu sử nhà thơ Chế Lan Viên
Tiểu sử nhà thơ Tố Hữu

Tiểu sử nhà thơ Tố Hữu

Qua gần một thế kỷ kể từ khi những tác phẩm đầu tiên của ông ra đời, thơ Tố Hữu vẫn giữ được sức sống mãnh liệt, vẫn được đông đảo độc giả yêu mến và các n.

Tiểu sử nhà thơ Tố Hữu
Tiểu sử nhà thơ Thanh Hải

Tiểu sử nhà thơ Thanh Hải

Thông qua những tác phẩm của mình, ông đã chứng minh rằng thơ ca không nhất thiết phải hào hùng, rầm rộ mới có thể thể hiện được tinh thần yêu nước và ý th.

Tiểu sử nhà thơ Thanh Hải
Tiểu sử nhà văn Nguyễn Thi

Tiểu sử nhà văn Nguyễn Thi

Cô gái đất dừa, Sen trong đồng, Ở xã Trung Nghĩa và một số tác phẩm còn đang viết dở dang được rút từ di cảo. Vị trí trong lịch sử văn họcNguyễn Thi đã trở.

Tiểu sử nhà văn Nguyễn Thi
Tiểu sử nhà thơ Huy Cận

Tiểu sử nhà thơ Huy Cận

Trần Huy Liệu vào Huế dự lễ thoái vị của vua Bảo Đại một sự kiện mang tính biểu tượng quan trọng trong lịch sử dân tộc.Sau Cách mạng tháng Tám, Huy Cận đảm.

Tiểu sử nhà thơ Huy Cận
Tiểu sử nhà văn Nguyễn Minh Châu

Tiểu sử nhà văn Nguyễn Minh Châu

Minh Châu đều trở thành những gợi ý đáng suy nghĩ và có tầm triết lý. Nhận xét này chỉ ra điều quý giá trong nghệ thuật của Nguyễn Minh Châu khả năng biến.

Tiểu sử nhà văn Nguyễn Minh Châu

Theo dõi hành trình

Hãy để lại thông tin, khi có gì mới thì Nhà văn sẽ gửi thư đến bạn để cập nhật. Cam kết không gửi email rác.

Họ và tên

Email liên lạc

Đôi dòng chia sẻ