module.exports so với xuất khẩu trong Node.js


725

Tôi đã tìm thấy hợp đồng sau trong mô-đun Node.js:

module.exports = exports = nano = function database_module(cfg) {...}

Tôi tự hỏi whats khác nhau giữa module.exportsexportsvà lý do tại sao cả hai đều sử dụng ở đây.




6
Đã cập nhật liên kết 'cho hậu thế': nodejs.org/docs/latest/api/modules.html#modules_module_exports
Zeke

8
Đó là tất cả về tài liệu tham khảo. Hãy nghĩ về xuất khẩu giống như một đối tượng biến cục bộ trỏ đến module.exports. Nếu bạn ghi đè giá trị xuất khẩu, thì bạn sẽ mất tham chiếu đến module.exports và module.exports là những gì bạn trưng ra dưới dạng giao diện công khai.
Gabriel Llamas

14
Tóm tắt nhanh: cả hai exportsmodule.exportstrỏ đến cùng một đối tượng, trừ khi bạn gán lại một đối tượng. Và cuối cùng module.exportsđược trả lại. Vì vậy, nếu bạn đã gán lại exportscho một chức năng thì đừng mong đợi một chức năng vì nó sẽ không được trả lại. Tuy nhiên nếu bạn đã gán hàm như thế này exports.func = function...thì kết quả sẽ có thuộc tính func với hàm là giá trị. Bởi vì bạn đã thêm tài sản vào đối tượng exportsđược trỏ đến ..
Muhammad Umer

Câu trả lời:


426

Cài đặt module.exportscho phép database_modulehàm được gọi giống như hàm khi required. Đơn giản chỉ cần cài đặt exportssẽ không cho phép xuất hàm vì nút xuất các module.exportstham chiếu đối tượng . Đoạn mã sau sẽ không cho phép người dùng gọi hàm.

module.js

Sau đây sẽ không làm việc.

exports = nano = function database_module(cfg) {return;}

Sau đây sẽ hoạt động nếu module.exportsđược thiết lập.

module.exports = exports = nano = function database_module(cfg) {return;}

bảng điều khiển

var func = require('./module.js');
// the following line will **work** with module.exports
func();

Về cơ bản node.js không xuất đối tượng exportshiện tham chiếu, nhưng xuất các thuộc tính của những gì exportstham chiếu ban đầu. Mặc dù Node.js không xuất các module.exportstham chiếu đối tượng , cho phép bạn gọi nó như một hàm.


Lý do ít quan trọng thứ 2

Họ đặt cả hai module.exportsexportsđể đảm bảo exportskhông tham chiếu đến đối tượng được xuất trước đó. Bằng cách đặt cả hai bạn sử dụng exportsnhư một tốc ký và tránh các lỗi tiềm ẩn sau này trên đường.

Sử dụng exports.prop = true thay vì module.exports.prop = truelưu các ký tự và tránh nhầm lẫn.


8
@ajostergaard: Nó chỉ là tên của thư viện mà ví dụ của OP được lấy từ đó. Trong mô-đun, nó cho phép tác giả viết những thứ như nano.version = '3.3'thay vì module.exports.version = '3.3', đọc rõ hơn một chút. (Lưu ý rằng đó nanolà một biến cục bộ, được khai báo một chút trước khi xuất mô-đun được đặt .)
josh3736

3
@lime - cảm ơn - Tôi rất vui vì điều đó không liên quan vì nếu không, điều đó có nghĩa là tôi đã hoàn toàn hiểu sai mọi thứ. : - | :)
Ostergaard

Này Lime, đây là một câu trả lời khá cũ nhưng tôi hy vọng bạn có thể làm rõ điều gì đó. Nếu tôi được thiết lập module.exportsnhưng không exports , mã của tôi vẫn hoạt động chứ? Cảm ơn vì bất kì sự giúp đỡ!
Asad Saeeduddin

1
@Asad Có chức năng sẽ xuất đúng cách miễn là bạn đặtmodule.exports
Lime

@Liam cảm ơn câu trả lời có giá trị. thêm vài truy vấn - tại mục nhập của server.js, giá trị của module.exports và xuất khẩu là gì? là module.exports dự kiến ​​là null và xuất khẩu được đặt thành một đối tượng trống? Đây có phải là di sản hoặc có một số trường hợp sử dụng hợp lệ để chỉ xuất khẩu và module.exports cho hai đối tượng khác nhau bao giờ không?
Sushil

504

Mặc dù câu hỏi đã được trả lời và chấp nhận từ lâu, tôi chỉ muốn chia sẻ 2 xu của mình:

Bạn có thể tưởng tượng rằng ngay từ đầu tập tin của bạn có một cái gì đó giống như (chỉ để giải thích):

var module = new Module(...);
var exports = module.exports;

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

Vì vậy, bất cứ điều gì bạn làm chỉ cần ghi nhớ điều đó module.exportsvà KHÔNG exportsđược trả về từ mô-đun của bạn khi bạn yêu cầu mô-đun đó từ một nơi khác.

Vì vậy, khi bạn làm một cái gì đó như:

exports.a = function() {
    console.log("a");
}
exports.b = function() {
    console.log("b");
}

Bạn đang thêm 2 hàm abvào đối tượng cũng có module.exportsđiểm, vì vậy typeofkết quả trả về sẽ là object:{ a: [Function], b: [Function] }

Tất nhiên, đây là kết quả tương tự bạn sẽ nhận được nếu bạn đang sử dụng module.exportstrong ví dụ này thay vì exports.

Đây là trường hợp bạn muốn module.exportshành xử của mình giống như một thùng chứa các giá trị được xuất. Trong khi đó, nếu bạn chỉ muốn xuất một hàm tạo thì có một cái gì đó bạn nên biết về việc sử dụng module.exportshoặc exports; (Hãy nhớ lại rằng nó module.exportssẽ được trả về khi bạn yêu cầu thứ gì đó chứ không phải export).

module.exports = function Something() {
    console.log('bla bla');
}

Bây giờ typeofkết quả trả về là 'function'và bạn có thể yêu cầu nó và ngay lập tức gọi như sau:
var x = require('./file1.js')();bởi vì bạn ghi đè lên kết quả trả về là một hàm.

Tuy nhiên, sử dụng exportsbạn không thể sử dụng một cái gì đó như:

exports = function Something() {
    console.log('bla bla');
}
var x = require('./file1.js')(); //Error: require is not a function

Bởi vì với exports, tham chiếu không trỏ đến đối tượng mà module.exportsđiểm, vì vậy không có mối quan hệ giữa exportsmodule.exportsnữa. Trong trường hợp này module.exportsvẫn trỏ đến đối tượng trống {}sẽ được trả lại.

Câu trả lời được chấp nhận từ một chủ đề khác cũng sẽ giúp: Javascript có vượt qua được tham chiếu không?


2
Giải thích hay nhưng tôi vẫn không hiểu làm thế nào bạn có thể hoàn toàn bỏ qua module.exportsmột mô-đun, ví dụ như trong npmgói này : github.com/tj/consolidate.js/blob/master/lib/consolidate.js
CodyBugstein

4
@Imray giải thích ở đây: JavaScript có vượt qua tham chiếu không? exports.a = function(){}; works, exports = function(){} doesn't work
cirpo

29
oooo cuối cùng câu trả lời này giải thích nó. Về cơ bản xuất khẩu đề cập đến một đối tượng mà bạn có thể thêm các thuộc tính nhưng nếu bạn gán lại nó cho chức năng thì bạn sẽ không còn gắn một thuộc tính với đối tượng ban đầu đó nữa. Bây giờ xuất tham chiếu đến hàm trong khi module.exports vẫn đang trỏ đến đối tượng đó và vì đó là những gì được trả về. Bạn có thể nói xuất khẩu về cơ bản là rác được thu thập.
Muhammad Umer

5
Vì vậy, những gì các điểm sử dụng exports? Tại sao không chỉ luôn luôn sử dụng module.exportsnếu nó chỉ là một sự phân công lại biến? Có vẻ khó hiểu với tôi.
jedd.ahyoung 04/07/2015

1
@ jedd.ahyoung Nó ít rườm rà hơn để viết exports.somethingthay vìmodule.exports.something
Srle 04/07/2015

209

Về cơ bản câu trả lời nằm ở những gì thực sự xảy ra khi một mô-đun được yêu cầu thông qua requirecâu lệnh. Giả sử đây là lần đầu tiên mô-đun được yêu cầu.

Ví dụ:

var x = require('file1.js');

nội dung của file1.js:

module.exports = '123';

Khi câu lệnh trên được thực thi, một Moduleđối tượng được tạo. Hàm constructor của nó là:

function Module(id, parent) {
    this.id = id;
    this.exports = {};
    this.parent = parent;
    if (parent && parent.children) {
        parent.children.push(this);
    }

    this.filename = null;
    this.loaded = false;
    this.children = [];
}

Như bạn thấy mỗi đối tượng mô-đun có một thuộc tính có tên exports. Đây là những gì cuối cùng được trả lại như là một phần của require.

Bước tiếp theo của yêu cầu là bọc nội dung của file1.js thành một hàm ẩn danh như dưới đây:

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
});

Và hàm ẩn danh này được gọi theo cách sau, moduleở đây đề cập đến ModuleObject được tạo trước đó.

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
}) (module.exports,require, module, "path_to_file1.js","directory of the file1.js");

Như chúng ta có thể thấy bên trong hàm, exportsđối số chính thức đề cập đến module.exports. Về bản chất, đó là sự tiện lợi được cung cấp cho người lập trình mô-đun.

Tuy nhiên sự thuận tiện này cần phải được thực hiện một cách cẩn thận. Trong mọi trường hợp nếu cố gắng gán một đối tượng mới cho xuất khẩu, đảm bảo chúng tôi thực hiện theo cách này.

exports = module.exports = {};

Nếu chúng ta làm theo cách sai cách , module.exportsvẫn sẽ trỏ đến đối tượng được tạo như một phần của thể hiện mô-đun.

exports = {};

Kết quả là việc thêm bất cứ thứ gì vào đối tượng xuất khẩu ở trên sẽ không có tác dụng với đối tượng module.exports và không có gì sẽ được xuất hoặc trả lại như một phần của yêu cầu.


8
Mất tôi ở đâyexports = module.exports = {};
Giant Elk

2
Tôi nghĩ rằng đây sẽ là câu trả lời tốt nhất, nó giải thích tại sao func()thất bại trong câu trả lời của @ William!
rùa

2
Tôi không thấy bất kỳ lợi thế nào để thêm exports = module.exports = app;vào dòng cuối cùng của mã. Có vẻ như module.exportssẽ được xuất khẩu và chúng tôi sẽ không bao giờ sử dụng exports, vì một lần nữa, nó ở dòng cuối cùng của mã. Vậy, tại sao chúng ta không chỉ đơn giản là thêmmodule.exports = app;
lvarayut

79

Ban đầu, module.exports=exportsrequirehàm trả về đối tượng module.exportstham chiếu.

nếu chúng ta thêm thuộc tính vào đối tượng, giả sử exports.a=1, thì module.exports và export vẫn tham chiếu đến cùng một đối tượng. Vì vậy, nếu chúng ta gọi request và gán mô-đun cho một biến, thì biến đó có thuộc tính a và giá trị của nó là 1;

Nhưng nếu chúng ta ghi đè một trong số chúng, ví dụ, exports=function(){}thì bây giờ chúng khác : xuất khẩu đề cập đến một đối tượng mới và module.exports đề cập đến đối tượng ban đầu. Và nếu chúng tôi yêu cầu tệp, nó sẽ không trả về đối tượng mới, vì module.exports không tham chiếu đến đối tượng mới.

Đối với tôi, tôi sẽ tiếp tục thêm thuộc tính mới hoặc ghi đè cả hai vào một đối tượng mới. Chỉ cần ghi đè một là không đúng. Và hãy nhớ rằng đó module.exportslà ông chủ thực sự.


1
Vâng, đây thực sự là câu trả lời thực sự. Nó ngắn gọn và rõ ràng. Những người khác có thể đúng nhưng đầy đủ các điều khoản ưa thích và không tập trung chính xác vào câu trả lời cho câu hỏi này.
Khoa

Đây là câu trả lời rõ ràng nhất! Trong trường hợp bạn muốn đánh dấu nó, đây là liên kết chính xác: stackoverflow.com/questions/7137397/iêu
lambdarookie

56

exportsmodule.exportsgiống nhau trừ khi bạn gán lại exportstrong mô-đun của mình.

Cách dễ nhất để nghĩ về nó, là nghĩ rằng dòng này hoàn toàn nằm ở đầu mỗi mô-đun.

var exports = module.exports = {};

Nếu, trong mô-đun của bạn, bạn gán lại exports, sau đó bạn gán lại nó trong mô-đun của mình và nó không còn bằng module.exports. Đây là lý do tại sao, nếu bạn muốn xuất một hàm, bạn phải làm:

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

Nếu bạn chỉ đơn giản là giao của bạn function() { ... }đến exports, bạn sẽ được giao lại exportsđể không có điểm thời gian để module.exports.

Nếu bạn không muốn đề cập đến chức năng của mình module.exportsmọi lúc, bạn có thể làm:

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

Lưu ý rằng đó module.exportslà đối số trái nhất.

Đính kèm thuộc tính exportskhông giống nhau vì bạn không gán lại nó. Đó là lý do tại sao điều này hoạt động

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

9
Đây là cách dễ nhất để hiểu tất cả các câu trả lời!
Adarsh ​​Konchady

2
Đẹp và đơn giản
fibono

1
Cách đơn giản và dễ dàng hơn để hiểu tính năng này.
FilipeCanatto

27

JavaScript chuyển các đối tượng bằng bản sao của một tham chiếu

Đó là một sự khác biệt tinh tế để làm với cách các đối tượng được truyền bằng tham chiếu trong JavaScript.

exportsmodule.exportscả hai đều chỉ vào cùng một đối tượng. exportslà một biến và module.exportslà một thuộc tính của đối tượng mô-đun.

Nói rằng tôi viết một cái gì đó như thế này:

exports = {a:1};
module.exports = {b:12};

exportsmodule.exportsbây giờ chỉ vào các đối tượng khác nhau. Sửa đổi xuất khẩu không còn sửa đổi module.exports.

Khi chức năng nhập kiểm tra module.exportsnó sẽ được{b:12}


6
Imho trả lời hay nhất!
Ông AJ

1
"JavaScript vượt qua tham chiếu" - Số
xehpuk

13

Tôi chỉ thực hiện một số thử nghiệm, hóa ra, bên trong mã mô-đun của nodejs, nó sẽ giống như thế này:

var module.exports = {};
var exports = module.exports;

vì thế:

1:

exports = function(){}; // this will not work! as it make the exports to some other pointer
module.exports = function(){}; // it works! cause finally nodejs make the module.exports to export.

2:

exports.abc = function(){}; // works!
exports.efg = function(){}; // works!

3: nhưng, trong trường hợp này

module.exports = function(){}; // from now on we have to using module.exports to attach more stuff to exports.
module.exports.a = 'value a'; // works
exports.b = 'value b'; // the b will nerver be seen cause of the first line of code we have do it before (or later)

Lyman, đó module.exportslà loại 'thỏa thuận thực sự' mà nút bị tắt nhưng đến một lúc nào đó, bạn sẽ cần thêm tất cả exportsvào module.exportstrừ khi bạn đang sử dụng exports.namespace(trường hợp 2 ở trên), trong trường hợp đó có vẻ giống như Node chạy một extends(module.exports, exports);cách thêm tất cả 'namespace' của exportsđể các module.exportsđối tượng? Nói cách khác, nếu bạn đang sử dụng exportsthì có lẽ bạn muốn thiết lập các thuộc tính trên nó?
Cody

11

Dưới đây là một mô tả hay được viết về các mô-đun nút trong tệp node.js đang hoạt động sách từ ấn phẩm Manning .
Cuối cùng, thứ được xuất trong ứng dụng của bạn là module.exports.
xuất khẩu
được thiết lập đơn giản như một tham chiếu toàn cầu đến module.exports , ban đầu được định nghĩa là một đối tượng trống mà bạn có thể thêm thuộc tính vào. Vì vậy, exports.myFunc chỉ là viết tắt cho module.exports.myFunc .

Kết quả là, nếu xuất khẩu được đặt thành bất kỳ thứ gì khác, nó sẽ phá vỡ tham chiếu giữa module.exportsxuất khẩu . Bởi vì module.exportslà những gì thực sự được xuất khẩu, xuất khẩu sẽ không còn hoạt động như mong đợi. Nó không còn là mô-đun tham chiếu . xuất khẩu nữa. Nếu bạn muốn duy trì liên kết đó, bạn có thể thực hiện xuất lại tham chiếu module.exports như sau:

module.exports = exports = db;

8

Tôi đã trải qua một số thử nghiệm và tôi nghĩ rằng điều này có thể làm sáng tỏ chủ đề này ...

app.js:

var ...
  , routes = require('./routes')
  ...;
...
console.log('@routes', routes);
...

phiên bản của /routes/index.js:

exports = function fn(){}; // outputs "@routes {}"

exports.fn = function fn(){};  // outputs "@routes { fn: [Function: fn] }"

module.exports = function fn(){};  // outputs "@routes function fn(){}"

module.exports.fn = function fn(){};  // outputs "@routes { fn: [Function: fn] }"

Tôi thậm chí đã thêm các tập tin mới:

./routes/index.js:

module.exports = require('./not-index.js');
module.exports = require('./user.js');

./routes/not-index.js:

exports = function fn(){};

./routes/user.js:

exports = function user(){};

Chúng tôi nhận được đầu ra "@routes {}"


./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');

./routes/not-index.js:

exports = function fn(){};

./routes/user.js:

exports = function user(){};

Chúng tôi nhận được đầu ra "@routes {fn: {}, user: {}}"


./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');

./routes/not-index.js:

exports.fn = function fn(){};

./routes/user.js:

exports.user = function user(){};

Chúng tôi nhận được đầu ra "@routes {user: [Function: user]}" Nếu chúng tôi thay đổi user.js thành { ThisLoadedLast: [Function: ThisLoadedLast] }, chúng tôi sẽ nhận được đầu ra "@routes {ThisLoadedLast: [Function: ThisLoadedLast]}".


Nhưng nếu chúng ta sửa đổi ./routes/index.js ...

./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.ThisLoadedLast = require('./user.js');

./routes/not-index.js:

exports.fn = function fn(){};

./routes/user.js:

exports.ThisLoadedLast = function ThisLoadedLast(){};

... chúng tôi nhận được "@routes {fn: {fn: [Function: fn]}, ThisLoadedLast: {ThisLoadedLast: [Function: ThisLoadedLast]}}"

Vì vậy, tôi sẽ đề nghị luôn luôn sử dụng module.exports trong định nghĩa mô-đun của bạn.

Tôi hoàn toàn không hiểu những gì đang diễn ra bên trong với Node, nhưng vui lòng bình luận nếu bạn có thể hiểu rõ hơn về điều này vì tôi chắc chắn rằng nó sẽ giúp ích.

- Mã hóa hạnh phúc


Tôi nghĩ rằng chúng phức tạp không cần thiết và khó hiểu. Nó nên minh bạch và trực quan.
ngungo

Tôi đồng ý. Nó có thể hữu ích cho việc đặt tên là một số trường hợp, nhưng nói chung sẽ không tạo ra hoặc phá vỡ bất cứ điều gì.
Cody

4

Điều này cho thấy cách thức require()hoạt động ở dạng đơn giản nhất, được trích từ Eloquent JavaScript

Vấn đề Không thể cho mô-đun xuất trực tiếp một giá trị ngoài đối tượng xuất, chẳng hạn như hàm. Ví dụ, một mô-đun có thể chỉ muốn xuất hàm tạo của loại đối tượng mà nó xác định. Ngay bây giờ, nó không thể làm điều đó bởi vì yêu cầu luôn sử dụng exportsđối tượng mà nó tạo làm giá trị xuất.

Giải pháp Cung cấp các mô-đun với một biến khác module, đó là một đối tượng có thuộc tính exports. Thuộc tính này ban đầu chỉ vào đối tượng trống được tạo bởi yêu cầu nhưng có thể được ghi đè bằng một giá trị khác để xuất một cái gì đó khác.

function require(name) {
  if (name in require.cache)
    return require.cache[name];
  var code = new Function("exports, module", readFile(name));
  var exports = {}, module = {exports: exports};
  code(exports, module);
  require.cache[name] = module.exports;
  return module.exports;
}
require.cache = Object.create(null);

Tôi đã phải tạo lại điều này trong Node và thử nghiệm một vài thứ cho đến khi tôi nhận được, tôi mút. Về cơ bản, hàm bên trong được tạo cho mô-đun thậm chí không bao giờ trả về đối tượng xuất. Vì vậy, đối tượng "xuất khẩu" không thực sự được gán lại trong mô-đun, ví dụ nếu bạn cố gắng viết export = "đây là một chuỗi" trực tiếp. Đối tượng chỉ tồn tại như một tài liệu tham khảo. Đây là hành vi tôi không nghĩ rằng tôi thực sự đã chọn đúng cho đến bây giờ.
danielgormly

4

Đây là kết quả của

console.log("module:");
console.log(module);

console.log("exports:");
console.log(exports);

console.log("module.exports:");
console.log(module.exports);

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

Cũng thế:

if(module.exports === exports){
    console.log("YES");
}else{
    console.log("NO");
}

//YES

Lưu ý: Đặc tả CommonJS chỉ cho phép sử dụng biến xuất khẩu để hiển thị các thành viên công cộng. Do đó, mẫu xuất khẩu được đặt tên là mẫu duy nhất thực sự tương thích với đặc tả CommonJS. Việc sử dụng module.exports là một tiện ích mở rộng được cung cấp bởi Node.js để hỗ trợ phạm vi các mẫu định nghĩa mô-đun rộng hơn.


4
var a = {},md={};

// Thứ nhất, xuất khẩu và module.exports trỏ cùng một đối tượng trống

exp = a;//exports =a;
md.exp = a;//module.exports = a;

exp.attr = "change";

console.log(md.exp);//{attr:"change"}

// Nếu bạn trỏ exp tới đối tượng khác thay vì trỏ thuộc tính của nó sang đối tượng khác. Md.bao sẽ là đối tượng trống {}

var a ={},md={};
exp =a;
md.exp =a;

exp = function(){ console.log('Do nothing...'); };

console.log(md.exp); //{}

4

Từ các tài liệu

Biến xuất có sẵn trong phạm vi cấp tệp của mô-đun và được gán giá trị của module.exports trước khi mô-đun được ước tính.

Nó cho phép một lối tắt, để module.exports.f = ... có thể được viết ngắn gọn hơn như export.f = .... Tuy nhiên, hãy lưu ý rằng giống như bất kỳ biến nào, nếu một giá trị mới được gán cho xuất khẩu, thì đó là không còn bị ràng buộc với module.exports:

Nó chỉ là một biến trỏ đến module.exports.


4

Tôi thấy liên kết này hữu ích để trả lời câu hỏi trên.

http://timnew.me/blog/2012/04/20/exports-vs-module-exports-in-node-js/

Để thêm vào các bài viết khác Hệ thống mô-đun trong nút không

var exports = module.exports 

trước khi thực thi mã của bạn. Vì vậy, khi bạn muốn xuất = foo, có lẽ bạn muốn làm module.exports = export = foo nhưng sử dụng export.foo = foo sẽ ổn


liên kết git bị hỏng
Jesse Hattabaugh

Liên kết hiện đã được sửa.
Paweł Gościcki

3

"Nếu bạn muốn gốc của xuất mô-đun của bạn là một hàm (chẳng hạn như hàm tạo) hoặc nếu bạn muốn xuất một đối tượng hoàn chỉnh trong một nhiệm vụ thay vì xây dựng một thuộc tính tại một thời điểm, hãy gán nó cho module.exports thay vì xuất khẩu. " - http://nodejs.org/api/modules.html


3

module.exportsexportscả hai đều trỏ đến cùng một đối tượng trước khi mô-đun được ước tính.

Bất kỳ thuộc tính nào bạn thêm vào module.exports đối tượng sẽ có sẵn khi mô-đun của bạn được sử dụng trong mô-đun khác bằng cách sử dụng requirecâu lệnh. exportslà một phím tắt có sẵn cho cùng một điều. Ví dụ:

module.exports.add = (a, b) => a+b

tương đương với văn bản:

exports.add = (a, b) => a+b

Vì vậy, sẽ ổn thôi miễn là bạn không gán giá trị mới cho exportsbiến. Khi bạn làm một cái gì đó như thế này:

exports = (a, b) => a+b 

vì bạn đang gán một giá trị mới cho exportsnó không còn tham chiếu đến đối tượng được xuất và do đó sẽ vẫn là cục bộ cho mô-đun của bạn.

Nếu bạn đang dự định gán một giá trị mới module.exportsthay vì thêm các thuộc tính mới vào đối tượng ban đầu được cung cấp, có lẽ bạn nên xem xét thực hiện như được đưa ra dưới đây:

module.exports = exports = (a, b) => a+b

Trang web Node.js có một lời giải thích rất tốt về điều này.


2

1.
xuất khẩu -> sử dụng như tiện ích đơn lẻ 2. xuất khẩu mô-đun -> sử dụng làm đối tượng logic như dịch vụ, mô hình, v.v.


2

Hãy tạo một mô-đun với 2 cách:

Một chiều

var aa = {
    a: () => {return 'a'},
    b: () => {return 'b'}
}

module.exports = aa;

Cách thứ hai

exports.a = () => {return 'a';}
exports.b = () => {return 'b';}

Và đây là cách yêu cầu () sẽ tích hợp mô-đun.

Cách thứ nhất:

function require(){
    module.exports = {};
    var exports = module.exports;

    var aa = {
        a: () => {return 'a'},
        b: () => {return 'b'}
    }
    module.exports = aa;

    return module.exports;
}

Cách thứ hai

function require(){
    module.exports = {};
    var exports = module.exports;

    exports.a = () => {return 'a';}
    exports.b = () => {return 'b';}

    return module.exports;
}

2

tại sao cả hai được sử dụng ở đây

Tôi tin rằng họ chỉ muốn làm rõ điều đó module.exports, exportsnanotrỏ đến cùng một hàm - cho phép bạn sử dụng một trong hai biến để gọi hàm trong tệp. nanocung cấp một số bối cảnh cho những gì chức năng làm.

exports sẽ không được xuất khẩu (chỉ module.exports ý chí), vậy tại sao lại phải ghi đè như vậy?

Sự đánh đổi bằng lời nói hạn chế rủi ro của các lỗi trong tương lai, chẳng hạn như sử dụng exportsthay vì module.exportstrong tệp. Nó cũng cung cấp làm rõ rằng module.exportsexportstrên thực tế chỉ đến cùng một giá trị.


module.exports đấu với exports

Miễn là bạn không gán lại module.exportshoặc exports(và thay vào đó thêm giá trị cho đối tượng mà cả hai đề cập đến), bạn sẽ không gặp vấn đề gì và có thể sử dụng một cách an toànexports để ngắn gọn hơn.

Khi gán một trong hai đối tượng không phải là đối tượng, giờ đây chúng chỉ đến các vị trí khác nhau có thể gây nhầm lẫn trừ khi bạn cố ý muốn module.exports trở thành một cái gì đó cụ thể (chẳng hạn như một hàm).

Đặt exportsthành một đối tượng không có ý nghĩa nhiều vì bạn sẽ phải đặt module.exports = exportsở cuối để có thể sử dụng nó trong các tệp khác.

let module = { exports: {} };
let exports = module.exports;

exports.msg = 'hi';
console.log(module.exports === exports); // true

exports = 'yo';
console.log(module.exports === exports); // false

exports = module.exports;
console.log(module.exports === exports); // true

module.exports = 'hello';
console.log(module.exports === exports); // false

module.exports = exports;
console.log(module.exports === exports); // true

Tại sao gán module.exportscho một chức năng?

Súc tích hơn! So sánh ví dụ thứ 2 ngắn hơn bao nhiêu:

helloWorld1.js: module.exports.hello = () => console.log('hello world');

app1.js: let sayHello = require('./helloWorld1'); sayHello.hello; // hello world

helloWorld2.js: module.exports = () => console.log('hello world');

app2.js: let sayHello = require('./helloWorld2'); sayHello; // hello world


2

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

Mỗi tệp bạn tạo là một mô-đun. mô-đun là một đối tượng. Nó có tài sản gọi làexports : {} là đối tượng trống theo mặc định.

bạn có thể tạo các hàm / phần mềm trung gian và thêm vào đối tượng xuất khẩu trống này, chẳng hạn như exports.findById() => { ... } sau đórequire bất cứ nơi nào trong ứng dụng và sử dụng của bạn ...

bộ điều khiển / user.js

exports.findById = () => {
    //  do something
}

yêu cầu trong Rout.js để sử dụng:

const {findyId} = './controllers/user'

2

Để hiểu sự khác biệt, trước tiên bạn phải hiểu Node.js làm gì với mọi mô-đun trong thời gian chạy. Node.js tạo chức năng bao bọc cho mọi mô-đun:

 (function(exports, require, module, __filename, __dirname) {

 })()

Lưu ý param đầu tiên exportslà một đối tượng trống và param thứ ba modulelà một đối tượng có nhiều thuộc tính và một trong các thuộc tính được đặt tên exports. Đây là những gì exportsđến từ và những gì module.exportsđến từ. Cái trước là một đối tượng biến, và cái sau là một thuộc tính của moduleđối tượng.

Trong mô-đun, Node.js tự động thực hiện việc này ngay từ đầu: module.exports = exportscuối cùng trả vềmodule.exports .

Vì vậy, bạn có thể thấy rằng nếu bạn gán lại một số giá trị cho exportsnó, nó sẽ không có bất kỳ ảnh hưởng nào module.exports. (Đơn giản vì exportschỉ vào một đối tượng mới khác, nhưng module.exportsvẫn giữ đối tượng cũ exports)

let exports = {};
const module = {};
module.exports = exports;

exports = { a: 1 }
console.log(module.exports) // {}

Nhưng nếu bạn cập nhật các thuộc tính của exports, nó chắc chắn sẽ có hiệu lực module.exports. Bởi vì cả hai đều chỉ đến cùng một đối tượng.

let exports = {};
const module = {};
module.exports = exports;

exports.a = 1;
module.exports.b = 2;
console.log(module.exports) // { a: 1, b: 2 }

Cũng lưu ý rằng nếu bạn gán lại giá trị khác module.exports, thì có vẻ như vô nghĩa đối với các exportscập nhật. Mọi cập nhật trên exportsđều bị bỏ qua vì module.exportstrỏ đến một đối tượng khác.

let exports = {};
const module = {};
module.exports = exports;

exports.a = 1;
module.exports = {
  hello: () => console.log('hello')
}
console.log(module.exports) // { hello: () => console.log('hello')}

0

trong nút js, tệp module.js được sử dụng để chạy module.load system.every khi nút thực thi một tệp, nó sẽ bọc nội dung tệp js của bạn như sau

'(function (exports, require, module, __filename, __dirname) {',+
     //your js file content
 '\n});'

bởi vì gói này bên trong mã nguồn của bạn, bạn có thể truy cập vào xuất, yêu cầu, mô-đun, v.v. Cách tiếp cận này được sử dụng vì không có cách nào khác để có được các chức năng được ghi trong tệp js sang tệp khác.

sau đó nút thực hiện chức năng được bọc này bằng c ++. tại thời điểm đó, đối tượng xuất khẩu được chuyển vào hàm này sẽ được điền.

bạn có thể thấy bên trong chức năng xuất và tham số chức năng này. thực sự xuất khẩu là một thành viên công cộng của chức năng xây dựng mô-đun.

nhìn vào đoạn mã sau

sao chép mã này vào b.js

console.log("module is "+Object.prototype.toString.call(module));
console.log("object.keys "+Object.keys(module));
console.log(module.exports);
console.log(exports === module.exports);
console.log("exports is "+Object.prototype.toString.call(exports));
console.log('----------------------------------------------');
var foo = require('a.js');
console.log("object.keys of foo: "+Object.keys(foo));
console.log('name is '+ foo);
foo();

sao chép mã này vào a.js

exports.name = 'hello';
module.exports.name = 'hi';
module.exports.age = 23;
module.exports = function(){console.log('function to module exports')};
//exports = function(){console.log('function to export');}

bây giờ chạy bằng nút

đây là đầu ra

module is [object Object]
object.keys id,exports,parent,filename,loaded,children,paths
{}
true

xuất khẩu là [đối tượng đối tượng]

object.keys của foo: name is function () {console.log ('function to module export')} chức năng để xuất mô-đun

bây giờ xóa dòng nhận xét trong a.js và nhận xét dòng trên dòng đó và xóa dòng cuối cùng của b.js và chạy.

trong thế giới javascript, bạn không thể gán lại đối tượng đã truyền dưới dạng tham số nhưng bạn có thể thay đổi thành viên công khai của hàm khi đối tượng của hàm đó được đặt làm tham số cho hàm khác

nhớ nhé

sử dụng module.exports trên và chỉ khi bạn muốn có được một chức năng khi bạn sử dụng yêu cầu từ khóa. trong ví dụ trên, chúng tôi var foo = quiries (a.js); bạn có thể thấy chúng ta có thể gọi foo là một hàm;

đây là cách tài liệu nút giải thích nó "Đối tượng xuất khẩu được tạo bởi hệ thống Mô-đun. Đôi khi điều này không được chấp nhận, nhiều người muốn mô-đun của họ là một thể hiện của một số lớp. Để thực hiện việc này, hãy gán đối tượng xuất khẩu mong muốn cho module.exports."


0
  1. Cả hai module.exportsexportschỉ đến cùng function database_module(cfg) {...}.

    1| var a, b;
    2| a = b = function() { console.log("Old"); };
    3|     b = function() { console.log("New"); };
    4|
    5| a(); // "Old"
    6| b(); // "New"

    Bạn có thể thay đổi btrên dòng 3 thành a, đầu ra ngược lại. Kết luận là:

    ablà độc lập.

  2. Vì vậy, module.exports = exports = nano = function database_module(cfg) {...}tương đương với:

    var f = function database_module(cfg) {...};
    module.exports = f;
    exports = f;

    Giả sử ở trên là module.js, được yêu cầu bởi foo.js. Những lợi ích của module.exports = exports = nano = function database_module(cfg) {...}bây giờ là rõ ràng:

    • Trong foo.js, vì module.exportsrequire('./module.js'):

      var output = require('./modules.js')();
    • Trong moduls.js: Bạn có thể sử dụng exportsthay vì module.exports.

Vì vậy, bạn sẽ hạnh phúc nếu cả hai exportsmodule.exportschỉ vào cùng một điều.

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.