Chúng ta có thể gắn nhãn bất kỳ khai báo nào là đã xuất bằng cách đặt ____0_______0 trước nó, có thể là một biến, hàm hoặc một lớp
Chẳng hạn, ở đây tất cả các lần xuất đều hợp lệ
// 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; } }
Không có dấu chấm phẩy sau lớp/hàm xuất
Xin lưu ý rằng // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!0 trước một lớp hoặc một hàm không làm cho nó trở thành một biểu thức hàm. Nó vẫn là một khai báo hàm, mặc dù đã được xuất
Hầu hết các hướng dẫn về kiểu JavaScript không khuyên dùng dấu chấm phẩy sau khi khai báo hàm và lớp
Đó là lý do tại sao không cần dấu chấm phẩy ở cuối // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!2 và // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!3
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end
Ngoài ra, chúng ta có thể đặt riêng // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!0
Ở đây trước tiên chúng tôi khai báo, sau đó xuất
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables
…Hoặc, về mặt kỹ thuật, chúng ta cũng có thể đặt hàm // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!0 ở trên
Thông thường, chúng tôi đặt một danh sách những gì cần nhập trong dấu ngoặc nhọn // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!6, như thế này
// 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!
Nhưng nếu có nhiều thứ để nhập, chẳng hạn, chúng ta có thể nhập mọi thứ dưới dạng đối tượng bằng cách sử dụng // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!7
// 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');
Thoạt nhìn, “nhập mọi thứ” có vẻ là một điều thú vị, viết ngắn gọn, tại sao chúng ta phải liệt kê rõ ràng những gì chúng ta cần nhập?
Vâng, có một vài lý do
- Liệt kê rõ ràng những gì cần nhập cho tên ngắn hơn. // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!8 thay vì // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!9
- Danh sách nhập rõ ràng cung cấp tổng quan tốt hơn về cấu trúc mã. những gì được sử dụng và ở đâu. Nó làm cho mã hỗ trợ và tái cấu trúc dễ dàng hơn
Đừng ngại nhập quá nhiều
Các công cụ xây dựng hiện đại, chẳng hạn như webpack và các công cụ khác, kết hợp các mô-đun lại với nhau và tối ưu hóa chúng để tăng tốc độ tải. Họ cũng loại bỏ nhập khẩu không sử dụng
Chẳng hạn, nếu bạn // 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');0 từ một thư viện mã khổng lồ, sau đó chỉ sử dụng một vài phương pháp, thì những phương pháp không sử dụng sẽ được đưa vào gói tối ưu hóa
Chúng tôi cũng có thể sử dụng // 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');1 để nhập dưới các tên khác nhau
Chẳng hạn, hãy nhập // 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');2 vào biến cục bộ // 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');3 cho ngắn gọn và nhập // 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');4 dưới dạng // 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');5
// 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!
Cú pháp tương tự tồn tại cho // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!0
Hãy xuất các hàm dưới dạng // 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');3 và // 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');5
// 📁 say.js ... export {sayHi as hi, sayBye as bye};
Bây giờ // 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');3 và // 📁 main.js import * as say from './say.js'; say.sayHi('John'); say.sayBye('John');5 là tên chính thức của người ngoài, được sử dụng trong nhập khẩu
// 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!
Trong thực tế, chủ yếu có hai loại mô-đun
- Các mô-đun chứa thư viện, gói chức năng, như // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!1 ở trên
- Các mô-đun khai báo một thực thể duy nhất, e. g. một mô-đun // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!2 chỉ xuất khẩu // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!3
Hầu hết, cách tiếp cận thứ hai được ưu tiên hơn, để mọi “thứ” nằm trong mô-đun của chính nó
Đương nhiên, điều đó đòi hỏi rất nhiều tệp, vì mọi thứ đều cần có mô-đun riêng, nhưng đó hoàn toàn không phải là vấn đề. Trên thực tế, việc điều hướng mã trở nên dễ dàng hơn nếu các tệp được đặt tên hợp lý và được cấu trúc thành các thư mục
Các mô-đun cung cấp một cú pháp // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!4 (“xuất mặc định”) đặc biệt để làm cho cách “một thứ cho mỗi mô-đun” trông đẹp hơn
Đặt // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!4 trước thực thể xuất khẩu
// 📁 user.js export default class User { // just add "default" constructor(name) { this.name = name; } }
Có thể chỉ có một // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!4 mỗi tệp
…Và sau đó nhập nó mà không cần dấu ngoặc nhọn
// 📁 main.js import User from './user.js'; // not {User}, just User new User('John');
Nhập khẩu không có dấu ngoặc nhọn trông đẹp hơn. Một sai lầm phổ biến khi bắt đầu sử dụng các mô-đun là hoàn toàn quên dấu ngoặc nhọn. Vì vậy, hãy nhớ rằng, // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!7 cần dấu ngoặc nhọn cho xuất khẩu có tên và không cần chúng cho xuất khẩu mặc định
Named exportDefault export// 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!8// 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!9// 📁 say.js ... export {sayHi as hi, sayBye as bye};0// 📁 say.js ... export {sayHi as hi, sayBye as bye};1Về mặt kỹ thuật, chúng tôi có thể có cả xuất khẩu mặc định và được đặt tên trong một mô-đun duy nhất, nhưng trên thực tế, mọi người thường không kết hợp chúng. Một mô-đun có tên xuất khẩu hoặc tên mặc định
Vì có thể có nhiều nhất một lần xuất mặc định cho mỗi tệp nên thực thể được xuất có thể không có tên
Chẳng hạn, đây là tất cả các bản xuất mặc định hoàn toàn hợp lệ
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end0
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end1
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end2
Không nêu tên cũng không sao, vì mỗi tệp chỉ có một // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!4 nên // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!7 không có dấu ngoặc nhọn biết nhập cái gì
Nếu không có // 📁 say.js ... export {sayHi as hi, sayBye as bye};4, quá trình xuất như vậy sẽ báo lỗi
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end3
Trong một số trường hợp, từ khóa // 📁 say.js ... export {sayHi as hi, sayBye as bye};4 được sử dụng để tham chiếu xuất mặc định
Ví dụ: để xuất một hàm riêng biệt với định nghĩa của nó
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end4
Hoặc, một tình huống khác, giả sử một mô-đun // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!2 xuất một thứ "mặc định" chính và một vài thứ được đặt tên (hiếm khi xảy ra trường hợp này, nhưng nó sẽ xảy ra)
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end5
Dưới đây là cách nhập tệp xuất mặc định cùng với tệp được đặt tên
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end6
Và, cuối cùng, nếu nhập mọi thứ // 📁 say.js ... export {sayHi as hi, sayBye as bye};7 làm đối tượng, thì thuộc tính // 📁 say.js ... export {sayHi as hi, sayBye as bye};4 chính xác là xuất mặc định
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end7
Xuất khẩu được đặt tên là rõ ràng. Họ đặt tên chính xác những gì họ nhập, vì vậy chúng tôi có thông tin đó từ họ;
Xuất khẩu được đặt tên buộc chúng tôi phải sử dụng chính xác đúng tên để nhập
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end8
…Trong khi xuất mặc định, chúng tôi luôn chọn tên khi nhập
export function sayHi(user) { alert(`Hello, ${user}!`); } // no ; at the end9
Vì vậy, các thành viên trong nhóm có thể sử dụng các tên khác nhau để nhập cùng một nội dung và điều đó không tốt
Thông thường, để tránh điều đó và giữ cho mã nhất quán, có một quy tắc là các biến được nhập phải tương ứng với tên tệp, e. g
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables0
Tuy nhiên, một số nhóm coi đó là nhược điểm nghiêm trọng của việc xuất mặc định. Vì vậy, họ thích luôn sử dụng xuất khẩu có tên. Ngay cả khi chỉ một thứ duy nhất được xuất, thì nó vẫn được xuất dưới tên, không có // 📁 say.js ... export {sayHi as hi, sayBye as bye};4
Điều đó cũng làm cho việc tái xuất (xem bên dưới) dễ dàng hơn một chút
Cú pháp “Tái xuất” // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!0 cho phép nhập đồ và xuất ngay (có thể dưới tên khác), như thế này
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables1
Tại sao điều đó lại cần thiết?
Hãy tưởng tượng, chúng ta đang viết một “gói”. một thư mục có nhiều mô-đun, với một số chức năng được xuất ra bên ngoài (các công cụ như NPM cho phép chúng tôi xuất bản và phân phối các gói như vậy, nhưng chúng tôi không phải sử dụng chúng) và nhiều mô-đun chỉ là “người trợ giúp”, cho nội bộ
Cấu trúc tập tin có thể như thế này
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables2
Chúng tôi muốn hiển thị chức năng của gói thông qua một điểm vào duy nhất
Nói cách khác, một người muốn sử dụng gói của chúng tôi, chỉ nên nhập từ “tệp chính” // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!1
Như thế này
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables3
“Tệp chính”, // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!1 xuất tất cả chức năng mà chúng tôi muốn cung cấp trong gói của mình
Ý tưởng là những người bên ngoài, những lập trình viên khác sử dụng gói của chúng tôi, không nên can thiệp vào cấu trúc bên trong của nó, hãy tìm kiếm các tệp bên trong thư mục gói của chúng tôi. Chúng tôi chỉ xuất những gì cần thiết trong // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!1 và giấu phần còn lại khỏi những con mắt tò mò
Vì chức năng được xuất thực tế nằm rải rác trong gói, chúng tôi có thể nhập nó vào // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!1 và xuất từ nó
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables4
Giờ đây, người dùng gói của chúng tôi có thể // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!5
Cú pháp // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!0 chỉ là một ký hiệu ngắn hơn cho việc nhập-xuất đó
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables5
Sự khác biệt đáng chú ý của // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!7 so với // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!8 là các mô-đun tái xuất không có sẵn trong tệp hiện tại. Vì vậy, bên trong ví dụ trên của // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!1, chúng ta không thể sử dụng các hàm // 📁 user.js export default class User { // just add "default" constructor(name) { this.name = name; } }0 đã tái xuất
Xuất mặc định cần xử lý riêng khi xuất lại
Giả sử chúng ta có // 📁 main.js import {sayHi as hi, sayBye as bye} from './say.js'; hi('John'); // Hello, John! bye('John'); // Bye, John!2 với // 📁 user.js export default class User { // just add "default" constructor(name) { this.name = name; } }2 và muốn xuất lại nó
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables6
Chúng ta có thể gặp hai vấn đề với nó
// 📁 user.js export default class User { // just add "default" constructor(name) { this.name = name; } }3 sẽ không hoạt động. Điều đó sẽ dẫn đến một lỗi cú pháp
Để xuất lại xuất mặc định, chúng ta phải viết // 📁 user.js export default class User { // just add "default" constructor(name) { this.name = name; } }4, như trong ví dụ trên
// 📁 user.js export default class User { // just add "default" constructor(name) { this.name = name; } }5 tái xuất chỉ xuất khẩu có tên, nhưng bỏ qua mặc định
Nếu chúng tôi muốn xuất lại cả xuất có tên và xuất mặc định, thì cần có hai câu lệnh
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables7
Những điều kỳ lạ khi xuất lại một bản xuất mặc định là một trong những lý do tại sao một số nhà phát triển không thích xuất mặc định và thích những cái được đặt tên
Đây là tất cả các loại // 📁 main.js import {sayHi, sayBye} from './say.js'; sayHi('John'); // Hello, John! sayBye('John'); // Bye, John!0 mà chúng tôi đã đề cập trong bài viết này và các bài viết trước
Bạn có thể tự kiểm tra bằng cách đọc chúng và nhớ lại ý nghĩa của chúng
- Trước khi khai báo một lớp/hàm/…
- // 📁 user.js export default class User { // just add "default" constructor(name) { this.name = name; } }7
- Xuất khẩu độc lập
- // 📁 user.js export default class User { // just add "default" constructor(name) { this.name = name; } }8
- tái xuất
- // 📁 user.js export default class User { // just add "default" constructor(name) { this.name = name; } }9
- // 📁 main.js import User from './user.js'; // not {User}, just User new User('John');0 (mặc định không tái xuất)
- // 📁 main.js import User from './user.js'; // not {User}, just User new User('John');1 (mặc định tái xuất)
Nhập khẩu
- Nhập xuất khẩu có tên
- // 📁 main.js import User from './user.js'; // not {User}, just User new User('John');2
- Nhập xuất mặc định
- // 📁 main.js import User from './user.js'; // not {User}, just User new User('John');3
- // 📁 main.js import User from './user.js'; // not {User}, just User new User('John');4
- Nhập tất cả
- // 📁 main.js import User from './user.js'; // not {User}, just User new User('John');5
- Nhập mô-đun (mã của mô-đun chạy), nhưng không chỉ định bất kỳ hoạt động xuất nào của mô-đun cho các biến
- // 📁 main.js import User from './user.js'; // not {User}, just User new User('John');6
Chúng ta có thể đặt các câu lệnh // 📁 main.js import * as say from './say.js'; say.hi('John'); // Hello, John! say.bye('John'); // Bye, John!8 ở đầu hoặc cuối tập lệnh, điều đó không thành vấn đề
Vì vậy, về mặt kỹ thuật mã này là tốt
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables8
Trong thực tế, việc nhập thường ở đầu tệp, nhưng điều đó chỉ để thuận tiện hơn
Xin lưu ý rằng câu lệnh nhập/xuất không hoạt động nếu bên trong // 📁 main.js import User from './user.js'; // not {User}, just User new User('John');8
Nhập có điều kiện, như thế này, sẽ không hoạt động
// 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); } function sayBye(user) { alert(`Bye, ${user}!`); } export {sayHi, sayBye}; // a list of exported variables9
…Nhưng nếu chúng ta thực sự cần nhập một thứ gì đó có điều kiện thì sao?