Mục đích của Node.js module.exports là gì và bạn sử dụng nó như thế nào?


1432

Mục đích của Node.js module.exports là gì và bạn sử dụng nó như thế nào?

Tôi dường như không thể tìm thấy bất kỳ thông tin nào về điều này, nhưng dường như đó là một phần khá quan trọng của Node.js vì tôi thường thấy nó trong mã nguồn.

Theo tài liệu của Node.js :

mô-đun

Một tài liệu tham khảo đến hiện tại module. Đặc biệt module.exports là giống như các đối tượng xuất khẩu. Xem src/node.jsđể biết thêm thông tin.

Nhưng điều này không thực sự có ích.

Chính xác thì module.exportslàm gì, và một ví dụ đơn giản sẽ là gì?

Câu trả lời:


1590

module.exportslà đối tượng thực sự được trả về như là kết quả của một requirecuộc gọi.

Các exportsbiến ban đầu được thiết lập để cùng đối tượng (tức là nó là một cách viết tắt "bí danh"), vì vậy trong các mã mô-đun bạn sẽ thường ghi một cái gì đó như thế này:

let myFunc1 = function() { ... };
let myFunc2 = function() { ... };
exports.myFunc1 = myFunc1;
exports.myFunc2 = myFunc2;

để xuất (hoặc "phơi bày") các hàm phạm vi bên trong myFunc1myFunc2.

Và trong mã gọi bạn sẽ sử dụng:

const m = require('./mymodule');
m.myFunc1();

trong đó dòng cuối cùng cho thấy kết quả của require(thường) chỉ là một đối tượng đơn giản có các thuộc tính có thể được truy cập.

NB: nếu bạn ghi đè lên exportsthì nó sẽ không còn được tham khảo nữa module.exports. Vì vậy, nếu bạn muốn gán một đối tượng mới (hoặc tham chiếu hàm) cho exportsthì bạn cũng nên gán đối tượng mới đó chomodule.exports


Điều đáng chú ý là tên được thêm vào exportsđối tượng không nhất thiết phải giống với tên trong phạm vi nội bộ của mô-đun cho giá trị bạn đang thêm, vì vậy bạn có thể có:

let myVeryLongInternalName = function() { ... };
exports.shortName = myVeryLongInternalName;
// add other objects, functions, as required

theo dõi bởi:

const m = require('./mymodule');
m.shortName(); // invokes module.myVeryLongInternalName

119
Câu trả lời hay - đối với tôi, 'phơi bày' sẽ là một lựa chọn thuật ngữ tốt hơn so với 'xuất khẩu'
UpTheCalet

2
@ApopheniaOverload - bạn có thể thực hiện "export.func1, export.func2, v.v." để có nhiều phương thức được hiển thị từ một tệp.
hellatan

73
Mô-đun yêu cầu phải là var m = quiries ('./ mymodule'); , với dấu chấm và dấu gạch chéo. Bằng cách này, Node.js biết chúng tôi đang sử dụng một mô-đun cục bộ.
Gui Premonsa

7
Hãy chắc chắn sử dụng cú pháp: Yêu cầu ('./ module_name') bởi vì, có thể có một số mô-đun node.js khác có tên và thay vì chọn mô-đun của riêng bạn, nó sẽ chọn mô-đun được cài đặt với node.js
Sazid

3
@UpTheCalet có một truyền thống lâu đời đề cập đến các biểu tượng công khai được mô-đun trình bày là 'xuất khẩu', xuất hiện từ nhiều hệ thống lập trình và nhiều thập kỷ. Đây không phải là một thuật ngữ mới được phát minh bởi các nhà phát triển Node.
Mark Reed

218

Điều này đã được trả lời nhưng tôi muốn thêm một số làm rõ ...

Bạn có thể sử dụng cả hai exportsmodule.exportsđể nhập mã vào ứng dụng của mình như thế này:

var mycode = require('./path/to/mycode');

Trường hợp sử dụng cơ bản bạn sẽ thấy (ví dụ: trong mã ví dụ ExpressJS) là bạn đặt thuộc tính trên exportsđối tượng trong tệp .js mà sau đó bạn nhập bằngrequire()

Vì vậy, trong một ví dụ đếm đơn giản, bạn có thể có:

(counter.js):

var count = 1;

exports.increment = function() {
    count++;
};

exports.getCount = function() {
    return count;
};

... sau đó trong ứng dụng của bạn (web.js hoặc bất kỳ tệp .js nào khác):

var counting = require('./counter.js');

console.log(counting.getCount()); // 1
counting.increment();
console.log(counting.getCount()); // 2

Nói một cách đơn giản, bạn có thể nghĩ các tệp được yêu cầu là các hàm trả về một đối tượng và bạn có thể thêm các thuộc tính (chuỗi, số, mảng, hàm, bất cứ thứ gì) vào đối tượng được trả về bằng cách đặt chúng vào exports.

Đôi khi, bạn sẽ muốn đối tượng được trả về từ một require()cuộc gọi là một chức năng bạn có thể gọi, thay vì chỉ là một đối tượng có thuộc tính. Trong trường hợp đó, bạn cũng cần đặt module.exports, như thế này:

(sayhello.js):

module.exports = exports = function() {
    console.log("Hello World!");
};

(app.js):

var sayHello = require('./sayhello.js');
sayHello(); // "Hello World!"

Sự khác biệt giữa xuất khẩu và module.exports được giải thích tốt hơn trong câu trả lời này ở đây .


Làm thế nào tôi có thể gọi yêu cầu một số mô-đun từ thư mục khác không có thư mục gốc như của tôi?
Igal

@ user301639 bạn có thể sử dụng các đường dẫn tương đối để duyệt qua hệ thống phân cấp tệp. requirebắt đầu liên quan đến thư mục bạn thực hiện node app.js. Tôi khuyên bạn nên đăng câu hỏi mới với mã rõ ràng + ví dụ cấu trúc thư mục để có câu trả lời rõ ràng hơn.
Jed Watson

1
Tôi đã phải điều chỉnh ví dụ module.exports của bạn để làm cho nó hoạt động. tập tin: var sayHello = require('./ex6_module.js'); console.log(sayHello());và mô-đun:module.exports = exports = function() { return "Hello World!"; }
Jason Lydon

1
Tìm thấy ví dụ gia tăng thực sự tốt và tôi đã sử dụng điều này để làm mới tâm trí của mình mỗi khi tôi bị quá tải với những gì tôi đang làm với xuất khẩu.
munkee

module.exports = exports = function(){...}thứ 2 exportschỉ là một biến phải không? Nói cách khác, nó có thể làmodule.exports = abc = function()
Jeb50

60

Lưu ý rằng cơ chế mô-đun NodeJS được dựa trên CommonJS module được hỗ trợ trong việc triển khai nhiều khác như RequireJS , mà còn SproutCore , CouchDB , Wakanda , OrientDB , ArangoDB , RingoJS , TeaJS , SilkJS , curl.js , hoặc thậm chí Adobe Photoshop (thông qua PSLib ). Bạn có thể tìm thấy danh sách đầy đủ các triển khai đã biết ở đây .

Trừ khi mô-đun của bạn sử dụng các tính năng hoặc mô-đun cụ thể của nút, tôi rất khuyến khích bạn sau đó sử dụng exportsthay vì module.exports đó không phải là một phần của tiêu chuẩn CommonJS , và sau đó chủ yếu không được hỗ trợ bởi các triển khai khác.

Một tính năng cụ thể khác của NodeJS là khi bạn gán tham chiếu cho một đối tượng mới exportsthay vì chỉ thêm các thuộc tính và phương thức cho nó như trong ví dụ cuối cùng được cung cấp bởi Jed Watson trong luồng này. Cá nhân tôi sẽ không khuyến khích thực hành này vì điều này phá vỡ sự hỗ trợ tham chiếu vòng tròn của cơ chế mô-đun CommonJS. Sau đó, nó không được hỗ trợ bởi tất cả các triển khai và ví dụ Jed nên được viết theo cách này (hoặc tương tự) để cung cấp một mô-đun phổ quát hơn:

(sayhello.js):

exports.run = function() {
    console.log("Hello World!");
}

(app.js):

var sayHello = require('./sayhello');
sayHello.run(); // "Hello World!"

Hoặc sử dụng các tính năng ES6

(sayhello.js):

Object.assign(exports, {
    // Put all your public API here
    sayhello() {
        console.log("Hello World!");
    }
});

(app.js):

const { sayHello } = require('./sayhello');
sayHello(); // "Hello World!"

PS: Có vẻ như Appcelerator cũng thực hiện các mô-đun CommonJS, nhưng không có hỗ trợ tham chiếu vòng tròn (xem: mô-đun Appcelerator và CommonJS (tham chiếu bộ đệm và tham chiếu vòng tròn) )


35

Một số điều bạn phải cẩn thận nếu bạn gán tham chiếu cho một đối tượng mới exportsvà / hoặc modules.exports:

1. Tất cả các thuộc tính / phương thức trước đây được gắn vào bản gốc exportshoặc module.exportstất nhiên bị mất vì đối tượng đã xuất bây giờ sẽ tham chiếu một thuộc tính mới khác

Điều này là hiển nhiên, nhưng nếu bạn thêm một phương thức đã xuất ở đầu mô-đun hiện có, hãy chắc chắn rằng đối tượng đã xuất bản gốc không tham chiếu đến một đối tượng khác ở cuối

exports.method1 = function () {}; // exposed to the original exported object
exports.method2 = function () {}; // exposed to the original exported object

module.exports.method3 = function () {}; // exposed with method1 & method2

var otherAPI = {
    // some properties and/or methods
}

exports = otherAPI; // replace the original API (works also with module.exports)

2. Trong trường hợp một trong exportshoặc module.exportstham chiếu một giá trị mới, chúng không tham chiếu đến cùng một đối tượng nữa

exports = function AConstructor() {}; // override the original exported object
exports.method2 = function () {}; // exposed to the new exported object

// method added to the original exports object which not exposed any more
module.exports.method3 = function () {}; 

3. Hậu quả rắc rối. Nếu bạn thay đổi tham chiếu thành cả hai exportsmodule.exports, khó có thể nói API nào được hiển thị (có vẻ như là module.exportsthắng)

// override the original exported object
module.exports = function AConstructor() {};

// try to override the original exported object
// but module.exports will be exposed instead
exports = function AnotherConstructor() {}; 

29

thuộc tính module.exports hoặc đối tượng xuất khẩu cho phép mô-đun chọn những gì sẽ được chia sẻ với ứng dụng

nhập mô tả hình ảnh ở đây

Tôi có một video trên module_export có sẵn ở đây


18

Khi chia mã chương trình của bạn cho nhiều tệp, module.exportsđược sử dụng để xuất bản các biến và hàm cho người tiêu dùng của mô-đun. Cuộc require()gọi trong tệp nguồn của bạn được thay thế bằng module.exportstải tương ứng từ mô-đun.

Ghi nhớ khi viết mô-đun

  • Tải mô-đun được lưu trữ, chỉ có cuộc gọi ban đầu mới đánh giá JavaScript.
  • Có thể sử dụng các biến và hàm cục bộ bên trong một mô-đun, không phải mọi thứ đều cần được xuất.
  • Các module.exportsđối tượng cũng có sẵn như tốc exportský. Nhưng khi trả về một chức năng duy nhất, luôn luôn sử dụng module.exports.

sơ đồ mô-đun xuất khẩu

Theo: "Mô-đun Phần 2 - Mô-đun viết" .


9

liên kết giới thiệu là như thế này:

exports = module.exports = function(){
    //....
}

các thuộc tính của exportshoặc module.exports, chẳng hạn như các hàm hoặc biến, sẽ được hiển thị bên ngoài

có một điều bạn phải chú ý hơn: không overridexuất khẩu.

tại sao ?

bởi vì xuất chỉ là tham chiếu của module.exports, bạn có thể thêm các thuộc tính vào xuất, nhưng nếu bạn ghi đè xuất, liên kết tham chiếu sẽ bị hỏng.

ví dụ tốt :

exports.name = 'william';

exports.getName = function(){
   console.log(this.name);
}

ví dụ xấu :

exports = 'william';

exports = function(){
     //...
}

Nếu bạn chỉ muốn chỉ hiển thị một hàm hoặc biến, như thế này:

// test.js
var name = 'william';

module.exports = function(){
    console.log(name);
}   

// index.js
var test = require('./test');
test();

mô-đun này chỉ hiển thị một chức năng và thuộc tính của tên là riêng tư cho bên ngoài.


6

Có một số mô-đun mặc định hoặc hiện có trong node.js khi bạn tải xuống và cài đặt node.js như http, sys, v.v.

Vì chúng đã có trong node.js, khi chúng tôi muốn sử dụng các mô-đun này, về cơ bản chúng tôi thích nhập các mô-đun , nhưng tại sao? bởi vì chúng đã có mặt trong node.js. Nhập giống như lấy chúng từ node.js và đưa chúng vào chương trình của bạn. Và sau đó sử dụng chúng.

Trong khi Xuất khẩu hoàn toàn ngược lại, bạn đang tạo mô-đun bạn muốn, giả sử mô-đun add.js và đưa mô-đun đó vào node.js, bạn thực hiện bằng cách xuất nó.

Trước khi tôi viết bất cứ điều gì ở đây, hãy nhớ, module.exports.additionTwo là giống như exports.additionTwo

Huh, đó là lý do, chúng tôi thích

exports.additionTwo = function(x)
{return x+2;};

Cẩn thận với con đường

Hãy nói rằng bạn đã tạo một mô-đun thêm.js,

exports.additionTwo = function(x){
return x + 2;
};

Khi bạn chạy nó trên dấu nhắc lệnh NODE.JS của bạn:

node
var run = require('addition.js');

Điều này sẽ báo lỗi

Lỗi: Không thể tìm thấy mô-đun add.js

Điều này là do quá trình node.js không thể thêm.j.j vì chúng tôi không đề cập đến đường dẫn. Vì vậy, chúng ta có thể thiết lập đường dẫn bằng cách sử dụng NODE_PATH

set NODE_PATH = path/to/your/additon.js

Bây giờ, điều này sẽ chạy thành công mà không có bất kỳ lỗi nào !!

Một điều nữa, bạn cũng có thể chạy tệp thêm.js bằng cách không đặt NODE_PATH, quay lại dấu nhắc lệnh nodejs của bạn:

node
var run = require('./addition.js');

Vì chúng tôi đang cung cấp đường dẫn ở đây bằng cách nói nó trong thư mục hiện tại ./nên nó cũng sẽ chạy thành công.


1
Là xuất khẩu hay xuất khẩu?
rudrasiva86

Cảm ơn sự giúp đỡ :)
Jumpman

3

Một mô-đun đóng gói mã liên quan thành một đơn vị mã. Khi tạo một mô-đun, điều này có thể được hiểu là di chuyển tất cả các chức năng liên quan vào một tệp.

Giả sử có một tệp Hello.js bao gồm hai hàm

sayHelloInEnglish = function() {
  return "Hello";
};
sayHelloInSpanish = function() {
  return "Hola";
};

Chúng tôi chỉ viết một hàm khi tiện ích của mã nhiều hơn một cuộc gọi.

Giả sử chúng ta muốn tăng tiện ích của hàm thành một tệp khác, nói World.js, trong trường hợp này, xuất một tệp thành hình ảnh có thể lấy được bởi module.exports.

Bạn chỉ có thể xuất cả hai hàm theo mã được đưa ra dưới đây

var anyVariable={
 sayHelloInEnglish = function() {
      return "Hello";
    };
  sayHelloInSpanish = function() {
      return "Hola";
    }; 
}
module.export=anyVariable;

Bây giờ bạn chỉ cần yêu cầu tên tệp vào World.js inorder để sử dụng các hàm đó

var world= require("./hello.js");

Cảm ơn Nếu nó đã giúp bạn vui lòng chấp nhận câu trả lời của tôi :)
Chaianu Madane

1
Đến bữa tiệc muộn một chút :)
Ben Taliadoros

@BenTaliadoros tôi cũng nghĩ anh ấy đến trễ và tôi cũng nghĩ đối tượng anyVariable của anh ấy có nhiều lỗi. dòng trên phương thức sayHelloInSp Biến không nên kết thúc bằng dấu chấm phẩy (;) và hàm sayHelloInSp Biến = sai. Tất cả mọi thứ đều sai với đối tượng này. tôi sẽ chỉnh sửa câu trả lời của anh ấy
thần thánh

1
chỉnh sửa bị vô hiệu hóa. Những gì khác đã làm alphadogg chỉnh sửa trong câu trả lời này ??
thần thánh

Chỉ cần định dạng. Trừ khi có một số điều es6 điên rồ mà tôi chưa gặp, và tôi chắc chắn không phải vậy, thì nó hoàn toàn không hợp lệ
Ben Taliadoros

2

Mục đích là:

Lập trình mô-đun là một kỹ thuật thiết kế phần mềm, nhấn mạnh việc tách chức năng của chương trình thành các mô-đun độc lập, có thể hoán đổi cho nhau, sao cho mỗi mô-đun chứa mọi thứ cần thiết để chỉ thực hiện một khía cạnh của chức năng mong muốn.

Wikipedia

Tôi tưởng tượng việc viết một chương trình lớn mà không có mã mô-đun / tái sử dụng trở nên khó khăn. Trong nodejs, chúng ta có thể tạo các chương trình mô-đun bằng cách module.exportsxác định những gì chúng ta phơi bày và soạn chương trình của chúng tôi require.

Hãy thử ví dụ này:

fileLog.js

function log(string) { require('fs').appendFileSync('log.txt',string); }

module.exports = log;

stdoutLog.js

function log(string) { console.log(string); }

module.exports = log;

chương trình

const log = require('./stdoutLog.js')

log('hello world!');

hành hình

$ nút chương trình.js

Chào thế giới!

Bây giờ hãy thử trao đổi ./stdoutLog.js cho ./fileLog.js .


1

Mục đích của một hệ thống mô-đun là gì?

Nó hoàn thành những điều sau đây:

  1. Giữ các tập tin của chúng tôi từ đầy hơi đến kích thước thực sự lớn. Có các tệp có ví dụ 5000 dòng mã trong đó thường rất khó xử lý trong quá trình phát triển.
  2. Thực thi tách mối quan tâm. Việc mã của chúng tôi được chia thành nhiều tệp cho phép chúng tôi có tên tệp phù hợp cho mọi tệp. Bằng cách này, chúng tôi có thể dễ dàng xác định những gì mọi mô-đun làm và nơi để tìm thấy nó (giả sử chúng tôi đã thực hiện một cấu trúc thư mục hợp lý vẫn là trách nhiệm của bạn).

Có các mô-đun giúp dễ dàng tìm thấy các phần nhất định của mã giúp mã của chúng tôi dễ bảo trì hơn.

Làm thế nào nó hoạt động?

NodejS sử dụng hệ thống mô-đun CommomJS hoạt động theo cách sau:

  1. Nếu một tệp muốn xuất một cái gì đó, nó phải khai báo nó bằng module.exportcú pháp
  2. Nếu một tệp muốn nhập một cái gì đó, nó phải khai báo nó bằng require('file')cú pháp

Thí dụ:

test1.js

const test2 = require('./test2');    // returns the module.exports object of a file

test2.Func1(); // logs func1
test2.Func2(); // logs func2

test2.js

module.exports.Func1 = () => {console.log('func1')};

exports.Func2 = () => {console.log('func2')};

Những điều hữu ích khác cần biết:

  1. Các mô-đun đang được lưu trữ . Khi bạn đang tải cùng một mô-đun trong 2 tệp khác nhau, mô-đun chỉ phải được tải một lần. Lần thứ hai a require()được gọi trên cùng một mô-đun, nó được kéo từ bộ đệm.
  2. Các mô-đun được tải đồng bộ . Hành vi này là bắt buộc, nếu nó không đồng bộ, chúng tôi không thể truy cập đối tượng được truy xuất require()ngay lập tức.

-3
let test = function() {
    return "Hello world"
};
exports.test = test;

4
Đây là ví dụ tương tự như trong đoạn trích đầu tiên trong câu trả lời được chấp nhận ( return "Hello world"không có sự khác biệt), nhưng không có bất kỳ lời giải thích nào. Hãy chắc chắn trước khi trả lời rằng câu trả lời của bạn sẽ thêm một cái gì đó vào chủ đề.
barbsan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.