Bagikan variabel antar file di Node.js?

126

Berikut adalah 2 file:

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

// module.js
name = "foobar";

Ketika saya tidak memiliki "var" itu berfungsi. Tetapi ketika saya memiliki:

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

nama tidak akan ditentukan di main.js.

Saya telah mendengar bahwa variabel global buruk dan Anda lebih baik menggunakan "var" sebelum referensi. Tetapi apakah ini kasus di mana variabel global baik?

never_had_a_name
sumber

Jawaban:

184

Variabel global hampir tidak pernah merupakan hal yang baik (mungkin pengecualian atau dua di luar sana ...). Dalam hal ini, sepertinya Anda benar-benar hanya ingin mengekspor variabel "nama" Anda. Misalnya,

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

Kemudian, di 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;
jmar777
sumber
1
variabel global buruk - saya sepenuhnya setuju dengan itu. Tapi saya bisa saja, bahwa modul memiliki ketergantungan pada suatu variabel. Apakah ada cara untuk meneruskan variabel ini ke file js lain melalui fungsi yang diperlukan?
appsthatmatter
1
@ jjoe64 Tidak yakin saya mengikuti apa yang Anda maksud. Anda dapat secara efektif berbagi nilai apa pun yang Anda inginkan melalui exportsobjek.
jmar777
7
OP menanyakan apakah suatu variabel dapat didefinisikan di main.js, dan kemudian digunakan dalam module.js. Saya memiliki persyaratan yang sama untuk mendefinisikan jalur yang digunakan berulang kali.
designermonkey
4
@Designermonkey Dalam hal ini Anda mungkin lebih baik memiliki objek konfigurasi dengan jenis-jenis nilai yang juga dapat membutuhkan () akan menjadi file yang diberikan. Perhatikan bahwa Anda hanya dapat melakukan global.foo = 'bar'dan kemudian mengakses di foomana saja Anda suka ... tapi seperti saya katakan dalam jawaban asli saya, itu hampir tidak pernah merupakan hal yang baik.
jmar777
Terima kasih untuk itu, saya menemukan cara untuk melakukan itu, dan itu berhasil. Terima kasih telah memverifikasi, saya punya ide yang tepat :)
designermonkey
37

Saya tidak dapat menemukan skenario di mana global varadalah pilihan terbaik, tentu saja Anda dapat memilikinya, tetapi lihatlah contoh-contoh ini dan Anda mungkin menemukan cara yang lebih baik untuk mencapai hal yang sama:

Skenario 1: Tempatkan barang-barang di file konfigurasi

Anda memerlukan beberapa nilai yang sama di seluruh aplikasi, tetapi itu berubah tergantung pada lingkungan (produksi, dev atau tes), jenis mailer sebagai contoh, Anda akan perlu:

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

dan

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

(buat konfigurasi serupa untuk dev juga)

Untuk memutuskan konfigurasi mana yang akan dimuat, buat file konfigurasi utama (ini akan digunakan di seluruh aplikasi)

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

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

Dan sekarang Anda bisa mendapatkan data seperti ini:

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

Skenario 2: Gunakan file konstanta

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

Dan gunakan seperti ini

// 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);
...

Skenario 3: Gunakan fungsi pembantu untuk mendapatkan / mengatur data

Bukan penggemar berat yang satu ini, tapi setidaknya Anda dapat melacak penggunaan 'nama' (mengutip contoh OP) dan menempatkan validasi di tempat.

// 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;
};

Dan gunakan itu

// 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();
  ...

Mungkin ada kasus penggunaan ketika tidak ada solusi selain memiliki global var, tetapi biasanya Anda dapat berbagi data di aplikasi Anda menggunakan salah satu skenario ini, jika Anda mulai menggunakan node.js (seperti saya beberapa waktu lalu) coba untuk mengatur cara Anda menangani data di sana karena itu bisa sangat cepat berantakan.

Felipe Pereira
sumber
Saya menyukai Skenario 2, tetapi dapatkah nilai-nilai ini diubah setelah kita bicara membangun? seperti yang paling sering kita lakukan, npm run build. Atau apakah Anda tahu cara untuk dapat mengubah nilai setelah membangun?
Kashif Ullah
@KashifUllah tidak yakin apakah saya dapat menjawab komentar Anda hanya dengan info yang diberikan, Anda mungkin ingin menambahkan pertanyaan baru di situs
Felipe Pereira
16

Jika kita perlu berbagi banyak variabel, gunakan format di bawah ini

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

   module.exports={
    name,
    city,
    company
  }

Pemakaian

  // main.js
    require('./modules');
    console.log(name); // print 'foobar'
Vineeth Bhaskaran
sumber
2
hanya catatan singkat untuk menghilangkan kebingungan yang dapat muncul di tempat pertama: module.exports adalah apa yang harus digunakan! apa pun file js Anda disebut (mis .: global.js). modul adalah objek simpul yang ada dalam lingkup global! [jadi dalam global.js kami menggunakan module.exports = .....]
Mohamed Allal
itu akan berhasil jika Anda menghapus 'let', dan tidak perlu ke "module.exports .."
Ahmad Zahabi
6

Simpan variabel apa pun yang ingin dibagikan sebagai satu objek. Kemudian meneruskannya ke modul yang dimuat sehingga dapat mengakses variabel melalui referensi objek ..

// 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

Di file lain ..

// 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();
    }
}
StefansArya
sumber
1

variabel yang dideklarasikan dengan atau tanpa kata kunci var dilampirkan ke objek global. Ini adalah dasar untuk membuat variabel global dalam Node dengan mendeklarasikan variabel tanpa kata kunci var. Sementara variabel yang dideklarasikan dengan kata kunci var tetap lokal ke modul.

lihat artikel ini untuk pemahaman lebih lanjut - https://www.hacksparrow.com/global-variables-in-node-js.html

criz
sumber
3
Apakah fragmen ini bertentangan? 1) "variabel yang dideklarasikan dengan atau tanpa kata kunci var dilampirkan ke objek global." dan 2) "variabel yang dideklarasikan dengan kata kunci var tetap lokal ke modul."
BaldEagle
1

Dengan pendapat yang berbeda, saya pikir globalvariabel mungkin merupakan pilihan terbaik jika Anda akan mempublikasikan kode Anda npm, karena Anda tidak dapat memastikan bahwa semua paket menggunakan rilis kode Anda yang sama. Jadi jika Anda menggunakan file untuk mengekspor singletonobjek, itu akan menyebabkan masalah di sini.

Anda dapat memilih global, require.mainatau objek lain yang dibagikan di seluruh file.

Tolong beritahu saya jika ada beberapa solusi yang lebih baik.

LCB
sumber