THÔNG DỤNG
OOP
ES6
ES(X)
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
Dự án mới của mình là gamehow.net, mời anh em ghé thăm và góp ý ạ.

Cách dùng Import / Export Module trong javascript

Trong bài này chúng ta sẽ tìm hiểu module trong javascript, qua đó bạn cũng sẽ biết cách sử dụng hai từ khóa import và export trong javascript.

Khi bạn xây dựng một ứng dụng nhỏ thì việc đặt mã javascript ở đâu, phân chia cấu trúc file như thế nào cho phù hợp, đó là điều mà ít người quan tâm. Nhưng khi dự án của bạn bự lên thì khác, nếu không phân chia cấu trúc thì rất khó cho việc nâng cấp và bảo trì sau này.

banquyen png
Bài viết này được đăng tại freetuts.net, không được copy dưới mọi hình thức.

Nếu bạn đã từng học qua bộ môn kỹ thuật lập trình cơ bản thì sẽ có khái niệm lập trình hướng module. Đây là kỹ thuật phân chia các file trong dự án một cách khóa học nhất, giúp dự án trở nên sạch sẽ, dễ dàng mở rộng chức năng sau này.

Vậy module là gì mà lại quan trọng đến thế? Và module trong javascript được sử dụng như thế nào? Chúng ta cùng tìm hiểu ngay nhé.

1. Module trong javascript là gì?

Trong javascript, một module là một file javascript bình thường, chỉ đơn giản là file đó sẽ đặt một cái tên có ý nghĩa, và các dòng code bên trong cũng phục vụ cho ý nghĩa đó.

Ví dụ, bạn đang xây dựng ứng dụng quản lý sinh viên thì sẽ tạo ra các module như:

  • Module sinhvien.js, là tập hợp những lệnh dùng để xử lý sinh viên.
  • Module khoa.js, là tập hợp những dòng lệnh dùng để xử lý các khoa của trường.

Việc phân chia thành từng module (tức là từng file) và mỗi module có một công dụng giúp cho quá trình code nhanh hơn, mạch lạc hơn, nhìn chuyên nghiệp hơn.

Chẳng bạn đang quản lý thư viện, bạn sẽ phân chia sách thành nhiều kệ khác nhau, mỗi kệ là tập hợp những cuốn sách cùng chủ đề. Ví dụ như sách lớp 6, 7, 8, 9 sẽ chia làm 4 kệ khác nhau. Mỗi kệ như vậy ta gọi là một module.

Khái niệm module đã xuất hiện từ lâu, nhưng trong javascript thì nó chỉ được công nhận là có tính năng module này kể từ phiên bản ES5 2015. Trước đây, chúng ta vẫn thường tìm những giải pháp khác để hiện thực hóa module trên javascript, điển hình là các thư viện như Module Pattern, CommonJS, Asynchronous Module Definition (AMD).

2. Khai báo module trong Javascript

Để khai báo và sử dụng module thì ta phải quan tâm đến hai từ khóa, thứ nhất là lệnh import trong js và thứ hai là lệnh export trong js.

Giả sử mình có một file tên là greet.js chứa đoạn code dưới đây.

greet.js
// exporting a function
export function greetPerson(name) {
    return `Hello ${name}`;
}

Trong đó từ khóa export dùng để khai báo dữ liệu được chia sẻ, và module khác muốn dùng hàm này thì chỉ việc gọi đến tên hàm là được. Nếu bạn không đặt từ khóa export thì dữ liệu sẽ ở phạm vi cục bộ trong module này.

Ngoài ra, bạn cũng có thể khai báo như sau:

export {
    greetPerson
};

// exporting a function
function greetPerson(name) {
    return `Hello ${name}`;
}

Bây giờ, để sử dụng hàm greetPerson bên trong module greet.js thì có hai trường hợp.

TH1: Nếu dùng trong một file javascript thì sẽ làm như sau:

file_bat_ki.js
// import hàm greetPerson của file greet.js
import { greetPerson } from './greet.js';

// Sau đó có thể sử dụng hàm greetPerson() 
let displayName = greetPerson('Cuong');

console.log(displayName); // Hello Cuong

TH2: Nếu dùng trong file html thì bạn phải khai báo thẻ script với thuộc tính type="module".

<script type="module">
    // import hàm greetPerson của file greet.js
    import { greetPerson } from './greet.js';

    // Sau đó có thể sử dụng hàm greetPerson() 
    let displayName = greetPerson('Cuong');

    console.log(displayName); // Hello Cuong
</script>

Như vậy chúng ta:

  • Sử dụng lệnh import để gọi đến dữ liệu từ một module khác.
  • Sử dụng lệnh export để đặt đằng trước hàm hoặc biến cho phép file khác sử dụng.

Ví dụ như đây là một trường hợp lỗi, vì ta đã gọi đến tên dữ liệu không tồn tại.

<script type="module">
    // import hàm greetPersonABC của file greet.js
    import { greetPersonABC } from './greet.js';
</script>

Nếu bạn muốn import nhiều dữ liệu thì hãy đặt chúng cách nhau bởi dấu phẩy.

Ví dụ ta có file module.js với nội dung như sau:

// exporting variable
export const name = 'JavaScript Program';

// exporting function
export function sum(x, y) {
    return x + y;
}

Để sử dụng nó trong một file khác thì ta sẽ làm như sau:

import { name, sum } from './module.js';

console.log(name);
let add = sum(4, 9);
console.log(add); // 13

3. Đổi tên dữ liệu của module trong javascript

Có một số trường hợp bạn phải thay đổi tên cho thuộc tính và phương thức từ module, bởi vì trong chương trình chính đã tồn tại tên như vây, hoặc tên cũ quá dài nên bạn muốn rút gọn lại. Lúc này, tại file chính bạn có thể thay đổi tên để tránh vấn đề trùng tên (conflict name).

Có hai cách để xử lý vấn đề này. Thứ nhất là rename ngay tại module, và thứ hai là rename trong file chương trình chính.

Đổi tên trong module

Để đổi tên dữ liệu nào đó thì trong module bạn hãy khai báo như sau:

file module.js
// Đổi tên ngay trong module module.js
export {
    function1 as newName1,
    function2 as newName2
};

Trong đó function1 và function là tên gốc, còn newName1 và newName 2 là tên mới.

Lúc này, trong file chương trình bạn sẽ sử dụng cú pháp như sau:

import { newName1, newName2 } from './module.js';

Ví dụ: Mình sẽ đổi tên cho hàm greetPerson trong module greet.js như sau.

File greet.js
export {
    greetPerson as person
};

// exporting a function
function greetPerson(name) {
    return `Hello ${name}`;
}

Lúc này, trong file chương trình ta sẽ gọi như sau:

<script type="module">
    // import hàm greetPerson của file greet.js
    import { Person } from './greet.js';

    // Sau đó có thể sử dụng hàm greetPerson() 
    let displayName = Person('Cuong');

    console.log(displayName); // Hello Cuong
</script>

Đổi tên trong file import

Cách này thường hay sử dụng nhất. Thường thì mỗi người sẽ có một quy tắc khai báo tên biến và tên hàm khác nhau, nên để họ tự đặt lại tên mới là giải pháp tốt nhất.

module.js
// Khai báo export hai hàm
export {
    function1,
    function2
};

Đoạn code trên mình đã khai báo export hai hàm, đó là function1function2.

Bây giờ để sử dụng trong chương trình thì bạn sẽ làm như sau:

main.js
// import và đổi tên luôn
import { function1 as newName1, function2 as newName2 } from './module.js';

Tóm lại: Để đổi tên dữ liệu trong module thì ta sẽ sử dụng từ khóa as.

4. Default export module trong javascript

Default export là cách khai báo một dữ liệu export mặc định, trong trường gọi đến mà không có thì module sẽ trả về dữ liệu default này.

Ví dụ trong file greet.js có nội dung như sau:

greet.js
// default export
export default function greet(name) {
    return `Hello ${name}`;
}

export const age = 23;

Trong đó hàm greet mình đã thiết lập nó là default export. Lúc này trong file chính sẽ gọi đến một dữ liệu trong module greet.js như sau:

import random_name from './greet.js';

Như bạn thấy, random_name không hề tồn tại trong module greet.js. Vì vậy, javascript sẽ lấy default export trả về cho random_name.

<script type="module">
    // import hàm random_name của file greet.js
    import random_name from './greet.js';

    // Sử dụng
    let displayName = random_name('Cuong');

    console.log(displayName); // Hello Cuong
</script>

5. Một vài đặc điểm của module trong Javascript

ES6 ra đời đánh dấu một mốc lịch sử rất lớn của ngôn ngữ javascript. Có nhiều tính năng được bổ sung vào mà trước đây ta mơ ước cũng không có, điển hình là các khái niệm về lập trình hướng đối tượng class, extends, static, và module. Sự nâng cấp luôn tạo ra một giá trị mới hữu ích hơn cái cũ.

Module cũng vậy, nó ra đời nhằm giải quyết sự rườm ra của javascript, nên sẽ có những lợi ích sau đây:

Chế độ strict mode

Strict mode là chế độ biên dịch nghiêm ngặt, bắt buộc mọi thứ phải viết theo đúng chuẩn của javascript.

Bình thường thì bạn có thể chạy một chương trình mà trong đó các câu lệnh không có kết thúc bằng dấu hai chấm, hoặc sử dụng một biến mà không cần phải khai báo, .. đó là vì chế độ strict mode chưa được bật.

Khi sử dụng module thì nó rất nghiêm túc trong việc tuân thủ theo quy tắc này. Vì vậy, bạn hãy tuân thủ theo cú pháp mà javascript đưa ra nhé.

Nếu bạn chưa biết strict mode là gì thì xem tại bài viết Strict Mode trong javascript.

Dữ liệu trong các module là riêng biệt

Nếu bạn sử dụng lênh script để import một file mà không thiết lập thuộc tính module thì dữ liệu ở các module có thể sử dụng lẫn nhau. Nhưng khi bạn sử dụng dạng module thì lại khác, dữ liệu ở mỗi module sẽ tách biệt hoàn toàn.

Ví dụ: Sử dụng thẻ script để import module.

<script type="module" src="user.js"></script>
<script type="module" src="hello.js"></script>

Lúc này hai file user.jshello.js là riêng biệt, không thể sử dụng dữ liệu của nhau.

Thậm chí khi bạn viết trên cùng một file html thì vẫn không sử dụng được của nhau.

<script type="module">
    var a = 12;
</script>

<script type="module">
    alert(a); // biến a chưa được định nghĩa
</script>

Chỉ import một lần

Nếu một module đã import rồi, thì nếu những lần sau bạn vẫn tiếp tục import thì nó sẽ không làm gì cả, bởi dữ liệu của module đó đã được load.

Điều này làm tăng tốc độ xử lý, bởi trình biên dịch sẽ không mất thời gian xử lý cái mà nó đã load.

Ví dụ: Giả sử mình có module alert.js như sau.

alert.js
alert("Module được tải!");

Bây giờ mình sẽ import ở một file khác.

// 1.js
import `./alert.js`; // Module được tải!

// 2.js
import `./alert.js`; // (không hiển thị gì cả)

Lệnh import thứ hai sẽ không làm gì cả, bởi module alert.js đã được load ở lệnh đầu tiên.

Con trỏ this trong module là undefined

Trong mỗi module, con trỏ this sẽ có giá trị là undefined. Lý do module luôn ở chế độ strict mode, mà ở chế độ này thì this là một biến chưa được khai báo.

Ví dụ dưới đây cho thấy nếu bạn sử dụng this trong module thì giá trị của nó là undefined, còn ở trong thẻ script bình thường thì nó là đối tượng windows.

script>
  alert(this); // window
</script>

<script type="module">
  alert(this); // undefined
</script>

Module tải theo dạng defer

Khi load một module thì nó luôn ở dạng defer, tức giống như bạn đặt thêm thuộc tính defer khi load một file javascript. Load theo dạng defer tức là dữ liệu javascript sẽ được load ngầm trong lúc trình duyệt vẫn đang load mã HTML và CSS.

Tóm lại, quy trình load của module sẽ tuân theo quy tắc sau:

  • Module sẽ được load ngầm, không ảnh hưởng đến tốc độ load của HTML.
  • Mã script của js sẽ được biên dịch khi trình duyệt đã load xong HTML nên không ảnh hưởng đến hệ thống DOM. Vì vậy, các đoạn mã trong module luôn luôn truy cập đến các đối tượng HTML cho dù bạn đặt ở đầu file hay cuối file.
  • Thứ tự load vẫn luôn được bảo toàn, file nào load trước thì sẽ được thực thi trường.

Thiết lập async cho module

Có một số trường hợp bạn phải sử dụng load bất đồng bộ async cho các module, ví dụ load những mã quảng cáo hoặc những chương trình không có sử dụng hệ tài nguyên trên website.

Nói qua một chút về load bất đồng bộ async và defer. Nếu defer là load ngầm và sẽ chờ khi toàn bộ mã HTML của trình duyệt đã load xong thì mới biên dịch module. Còn asycn thì khác, trình biên dịch sẽ load script và load đến đâu sẽ biên dịch đến đó.

Ví dụ dưới đây là mình load một module về analytics theo dạng async.

<script async type="module">
    import {counter} from './analytics.js';
    counter.count();
</script>

6. Hai cách dùng export trong javascript

Bây giờ mình sẽ nói thêm một chút về cách dùng lệnh export trong javascript nhé.

Đầu tiên, nếu muốn export một hàm hoặc biến thì bạn chỉ cần đặt lệnh export phía trước hàm và biến đó là được.

// export an array
export let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

// export a constant
export const MODULES_BECAME_STANDARD_YEAR = 2015;

// export a class
export class User {
  constructor(name) {
    this.name = name;
  }
}

Lưu ý là bạn không cần đặt dấu chấm phẩy đằng sau function hoặc class.

Thứ hai, bạn có thể sử dụng từ khóa export riêng biệt để khai báo dữ liệu.

// say.js
function sayHi(user) {
  alert(`Hello, ${user}!`);
}

function sayBye(user) {
  alert(`Bye, ${user}!`);
}

export {sayHi, sayBye}; // a list of exported variables

Như bạn thấy, mình đã viết hai function bình thường, sau đó đặt nó trong lệnh export.

Thứ ba, bạn có thể đặt lại tên cho dữ liệu ngay lệnh export bằng cách sử dụng từ khóa as.

export {sayHi as hi, sayBye as bye};

7. Hai cách dùng lệnh import trong javascript

Tương tự, chúng ta cũng sẽ có một số cách dùng lệnh import trong js như sau.

Thứ nhất, để import một vài dữ liệu thôi thì ta sử dụng cú pháp sau.

import {sayHi, sayBye} from './say.js';

Các dữ liệu sẽ được ngăn cách bởi dấy phẩy.

Thứ hai, nếu bạn muốn import toàn bộ dữ liệu thì hãy sử dụng dấu sao *.

import * as say from './say.js';

Thứ ba, nếu bạn muốn đổi tên của dữ liệu trong lệnh import thì làm như sau.

import {sayHi as hi, sayBye as bye} from './say.js';

8. Lời kết

Như vậy là chúng ta đã tìm hiểu xong cách sử dụng module trong javascript. Qua bài này bạn cũng học thêm được hai từ khóa, đó là export và import trong js. Đây là bài khá quan trọng, sau này khi học sang các thư viện hoặc framework khác thì gặp lại khái niệm module rất nhiều.

Cùng chuyên mục:

Cách gộp hai object javascript lại với nhau

Cách gộp hai object javascript lại với nhau

Cách lấy chiều dài của object trong Javascript

Cách lấy chiều dài của object trong Javascript

Hướng dẫn giải phương trình bậc 1 bằng Javascript

Hướng dẫn giải phương trình bậc 1 bằng Javascript

Cách dùng nextSibling trong javascript

Cách dùng nextSibling trong javascript

Cách dùng insertAdjacentHTML trong javascript

Cách dùng insertAdjacentHTML trong javascript

Cách dùng innerHTML trong Javascript

Cách dùng innerHTML trong Javascript

Cách dùng insertBefore trong javascript

Cách dùng insertBefore trong javascript

Cách dùng insertAfter trong Javascript

Cách dùng insertAfter trong Javascript

Cách dùng parentNode trong Javascript

Cách dùng parentNode trong Javascript

Cách dùng parentElement trong Javascript

Cách dùng parentElement trong Javascript

Tính tổng các phần tử trong mảng javascript

Tính tổng các phần tử trong mảng javascript

Tính tổng hai số bằng Javascript (cộng hai số)

Tính tổng hai số bằng Javascript (cộng hai số)

Cách gán giá trị cho thẻ input trong javascript

Cách gán giá trị cho thẻ input trong javascript

Để gán giá trị cho thẻ input thì ta có hai cách, thứ nhất là…

Cách kiểm tra số nguyên âm trong javascript

Cách kiểm tra số nguyên âm trong javascript

Cách kiểm tra số nguyên dương trong javascript

Cách kiểm tra số nguyên dương trong javascript

Hàm closure trong javascript

Hàm closure trong javascript

Closure là một khái niệm không phải ai cũng ..

Biểu thức chính quy RegEx trong Javascript

Biểu thức chính quy RegEx trong Javascript

Bài này chúng ta sẽ tìm hiểu đến chuỗi và cách sử dụng biểu thức…

Cơ chế hoạt động của hoisting trong Javascript

Cơ chế hoạt động của hoisting trong Javascript

Hoisting là vấn đề liên quan đến cách khai báo biến trong Javascript. Nó liên…

Cấp độ private / protected của class trong Javascript

Cấp độ private / protected của class trong Javascript

Cách dùng static trong Javascript (thuộc tính và phương thức tĩnh)

Cách dùng static trong Javascript (thuộc tính và phương thức tĩnh)

Trong bài này chúng ta sẽ tìm hiểu cách sử dụng từ ..

Top