Chia sẻ biến giữa các tệp trong Node.js?


126

Dưới đây là 2 tệp:

// main.js
require('./modules');
console.log(name); // prints "foobar"

// module.js
name = "foobar";

Khi tôi không có "var" thì nó hoạt động. Nhưng khi tôi có:

// module.js
var name = "foobar";

Tên sẽ không được xác định trong main.js.

Tôi đã nghe nói rằng các biến toàn cục là xấu và bạn nên sử dụng "var" trước các tham chiếu. Nhưng đây có phải là một trường hợp mà các biến toàn cầu là tốt?

Câu trả lời:


184

Các biến toàn cầu hầu như không bao giờ là một điều tốt (có thể là một ngoại lệ hoặc hai ngoại lệ ...). Trong trường hợp này, có vẻ như bạn thực sự chỉ muốn xuất biến "tên" của mình. Ví dụ,

// module.js
var name = "foobar";
// export it
exports.name = name;

Sau đó, trong main.js ...

//main.js
// get a reference to your required module
var myModule = require('./module');

// name is a member of myModule due to the export above
var name = myModule.name;

1
biến toàn cầu là xấu - tôi hoàn toàn đồng ý với điều đó. Nhưng tôi có thể, rằng mô-đun có một phụ thuộc vào một biến. Có cách nào để chuyển biến này sang tệp js khác thông qua hàm yêu cầu không?
appsthatmatter

1
@ jjoe64 Không chắc tôi làm theo ý bạn. Bạn có thể chia sẻ hiệu quả bất kỳ giá trị nào bạn muốn thông qua exportsđối tượng.
jmar777

7
OP đang hỏi liệu một biến có thể được xác định trong tệp main.js không, và sau đó được sử dụng trong module.js. Tôi có cùng một yêu cầu để xác định các đường dẫn được sử dụng nhiều lần.
designermonkey

4
@Designermonkey Trong trường hợp đó, có lẽ bạn nên có một đối tượng cấu hình với các loại giá trị cũng có thể được yêu cầu () 'vào một tệp nhất định. Lưu ý rằng bạn chỉ có thể làm global.foo = 'bar'và sau đó truy cập foobất cứ nơi nào bạn muốn ... nhưng như tôi đã nói trong câu trả lời ban đầu của mình, đó gần như không bao giờ là một điều tốt.
jmar777

Cảm ơn vì điều đó, tôi đã tìm ra cách để làm điều đó, và nó có tác dụng. Cảm ơn bạn đã xác minh tôi đã có ý tưởng đúng :)
designermonkey

37

Tôi không thể tìm thấy một kịch bản trong đó toàn cầu varlà lựa chọn tốt nhất, tất nhiên bạn có thể có một kịch bản , nhưng hãy xem các ví dụ này và bạn có thể tìm thấy một cách tốt hơn để thực hiện tương tự:

Kịch bản 1: Đặt nội dung trong tệp cấu hình

Bạn cần một số giá trị giống nhau trên ứng dụng, nhưng nó thay đổi tùy thuộc vào môi trường (sản xuất, phát triển hoặc thử nghiệm), loại thư như ví dụ, bạn cần:

// File: config/environments/production.json
{
    "mailerType": "SMTP",
    "mailerConfig": {
      "service": "Gmail",
      ....
}

// File: config/environments/test.json
{
    "mailerType": "Stub",
    "mailerConfig": {
      "error": false
    }
}

(tạo một cấu hình tương tự cho dev quá)

Để quyết định cấu hình nào sẽ được tải, hãy tạo một tệp cấu hình chính (điều này sẽ được sử dụng trên tất cả các ứng dụng)

// File: config/config.js
var _ = require('underscore');

module.exports = _.extend(
    require(__dirname + '/../config/environments/' + process.env.NODE_ENV + '.json') || {});

bây giờ bạn có thể lấy dữ liệu như thế này:

// File: server.js
...
var config = require('./config/config');
...
mailer.setTransport(nodemailer.createTransport(config.mailerType, config.mailerConfig));

Kịch bản 2: Sử dụng tệp hằng

// File: constants.js
module.exports = {
  appName: 'My neat app',
  currentAPIVersion: 3
};

Và sử dụng nó theo cách này

// File: config/routes.js

var constants = require('../constants');

module.exports = function(app, passport, auth) {
  var apiroot = '/api/v' + constants.currentAPIVersion;
...
  app.post(apiroot + '/users', users.create);
...

Kịch bản 3: Sử dụng chức năng trợ giúp để nhận / đặt dữ liệu

Không phải là một fan hâm mộ lớn của cái này, nhưng ít nhất bạn có thể theo dõi việc sử dụng 'tên' (trích dẫn ví dụ của OP) và đặt các xác nhận vào vị trí.

// File: helpers/nameHelper.js

var _name = 'I shall not be null'

exports.getName = function() {
  return _name;
};

exports.setName = function(name) {
  //validate the name...
  _name = name;
};

Và sử dụng nó

// File: controllers/users.js

var nameHelper = require('../helpers/nameHelper.js');

exports.create = function(req, res, next) {
  var user = new User();
  user.name = req.body.name || nameHelper.getName();
  ...

Có thể có trường hợp sử dụng khi không có giải pháp nào khác ngoài việc có toàn cầu var, nhưng thông thường bạn có thể chia sẻ dữ liệu trong ứng dụng của mình bằng một trong những tình huống này, nếu bạn đang bắt đầu sử dụng node.js (như cách đây của tôi trước đây) để tổ chức cách bạn xử lý dữ liệu ở đó vì nó có thể trở nên lộn xộn rất nhanh.


Tôi thích Kịch bản 2, nhưng những giá trị này có thể được thay đổi sau khi chúng tôi nói chuyện xây dựng không? Giống như hầu hết chúng ta thường làm, npm chạy xây dựng. Hoặc bạn có biết một số cách để có thể thay đổi giá trị sau khi xây dựng?
Kashif Ullah

@KashifUllah không chắc chắn nếu tôi có thể trả lời nhận xét của bạn chỉ với thông tin được cung cấp, bạn có thể muốn thêm một câu hỏi mới trong trang web
Felipe Pereira

16

Nếu chúng ta cần chia sẻ nhiều biến, hãy sử dụng định dạng dưới đây

//module.js
   let name='foobar';
   let city='xyz';
   let company='companyName';

   module.exports={
    name,
    city,
    company
  }

Sử dụng

  // main.js
    require('./modules');
    console.log(name); // print 'foobar'

2
chỉ là một ghi chú nhanh để bỏ qua sự nhầm lẫn có thể phát sinh tại vị trí đầu tiên: module.exports là những gì nên được sử dụng! bất cứ thứ gì tệp js của bạn được gọi (ví dụ: global.js). mô-đun là một đối tượng nút tồn tại trong phạm vi toàn cầu! [vì vậy trong global.js, chúng tôi sử dụng module.exports = .....]
Mohamed Allal

nó sẽ thành công nếu bạn xóa 'let' và không cần "module.exports .."
Ahmad Zahabi

6

Lưu bất kỳ biến nào muốn được chia sẻ dưới dạng một đối tượng. Sau đó chuyển nó đến mô-đun được tải để nó có thể truy cập vào biến thông qua tham chiếu đối tượng ..

// main.js
var myModule = require('./module.js');
var shares = {value:123};

// Initialize module and pass the shareable object
myModule.init(shares);

// The value was changed from init2 on the other file
console.log(shares.value); // 789

Trên tập tin khác ..

// module.js
var shared = null;

function init2(){
    console.log(shared.value); // 123
    shared.value = 789;
}

module.exports = {
    init:function(obj){
        // Save the shared object on current module
        shared = obj;

        // Call something outside
        init2();
    }
}

1

một biến được khai báo có hoặc không có từ khóa var được gắn vào đối tượng toàn cục. Đây là cơ sở để tạo các biến toàn cục trong Node bằng cách khai báo các biến mà không có từ khóa var. Trong khi các biến được khai báo với từ khóa var vẫn là cục bộ cho một mô-đun.

xem bài viết này để hiểu thêm - https://www.hacksparrow.com/global-variables-in-node-js.html


3
Những mảnh vỡ này có mâu thuẫn không? 1) "một biến được khai báo có hoặc không có từ khóa var được gắn vào đối tượng toàn cục." và 2) "các biến được khai báo với từ khóa var vẫn là cục bộ cho một mô-đun."
BaldEagle

1

Với một ý kiến ​​khác, tôi nghĩ các globalbiến có thể là lựa chọn tốt nhất nếu bạn định xuất bản mã của mình npm, vì bạn không thể chắc chắn rằng tất cả các gói đang sử dụng cùng một bản phát hành mã của bạn. Vì vậy, nếu bạn sử dụng một tệp để xuất một singletonđối tượng, nó sẽ gây ra vấn đề ở đây.

Bạn có thể chọn global, require.mainhoặc bất kỳ các đối tượng khác được chia sẻ trên các file.

Xin vui lòng cho tôi biết nếu có một số giải pháp tốt hơn.

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.