Meneruskan argumen yang diperlukan (saat memuat modul)

114

Apakah mungkin untuk memberikan argumen saat memuat modul menggunakan require?

Saya memiliki modul, login.js yang menyediakan fungsionalitas login. Ini membutuhkan koneksi database, dan saya ingin koneksi database yang sama digunakan di semua modul saya. Sekarang saya mengekspor fungsi login.setDatabase (...) yang memungkinkan saya menentukan koneksi database, dan berfungsi dengan baik. Tetapi saya lebih suka meneruskan database dan persyaratan lainnya ketika saya memuat modul.

var db = ...
var login = require("./login.js")(db);

Saya cukup baru dengan NodeJS dan biasanya mengembangkan menggunakan Java dan Spring Framework, jadi ya ... ini adalah injeksi konstruktor :) Apakah mungkin untuk melakukan sesuatu seperti kode yang saya berikan di atas?

Andreas Selenwall
sumber
Saya juga merekomendasikan untuk melihat jawaban atas pertanyaan ini . Seperti yang ditunjukkan dalam jawaban saya, idiom yang umum adalah meneruskan appobjek ke modul yang diperlukan.
David Weldon
Alih-alih melakukan semua argumen ini dengan meneruskan db, Anda bisa menggunakan implementasi tunggal dan memanggil db.getInstance () jika diperlukan.
wulfgarpro

Jawaban:

237

Berdasarkan komentar Anda dalam jawaban ini , saya melakukan apa yang Anda coba lakukan seperti ini:

module.exports = function (app, db) {
    var module = {};

    module.auth = function (req, res) {
        // This will be available 'outside'.
        // Authy stuff that can be used outside...
    };

    // Other stuff...
    module.pickle = function(cucumber, herbs, vinegar) {
        // This will be available 'outside'.
        // Pickling stuff...
    };

    function jarThemPickles(pickle, jar) {
        // This will be NOT available 'outside'.
        // Pickling stuff...

        return pickleJar;
    };

    return module;
};

Saya menyusun hampir semua modul saya seperti itu. Sepertinya bekerja dengan baik untuk saya.

floatingLomas
sumber
Apakah appargumen itu perlu atau dapatkah saya mengabaikannya? Modul saya tidak akan menggunakan argumen aplikasi ini secara eksplisit, tetapi saya tidak tahu apakah itu diperlukan oleh node.js untuk beberapa hal internal. Jika tidak apa-apa, deklarasi modul saya akan terlihat seperti ini:module.exports = function (db) {
Ulysses Alves
Itu khusus untuk aplikasi Express, jadi jelas tidak perlu.
floatingLomas
@floatingLomas Mekanisme serialisasi dalam python disebut pickle: stackoverflow.com/questions/11218477/…
SadSeven
1
Jadi apa yang terjadi jika Anda mereferensikan modul beberapa kali? Yang pertama require(mymodule)(myargs)akan memberi Anda modul untuk dikerjakan. Namun jika Anda mereferensikannya di tempat lain dari modul lain ?? dalam sistem dasar tampaknya ada cache yang terlibat, tetapi dalam sistem ini, cache akan mengembalikan metode generator kosong pada panggilan berikutnya ke require(), dan jika Anda memberikan args kepada require()(someargs)Anda, Anda akan mendapatkan modul yang berbeda kembali ... mungkin saya hilang sesuatu
Tom H
2
@TomH Dalam hal ini, Anda ingin menyimpannya di cache. Untuk melakukan itu, Anda harus var module;berada di luar fungsi ekspor, dan segera setelah Anda masuk, Anda ingin memeriksa apakah modulesudah ditentukan, dan jika demikian, kembalikan saja (dan jika tidak, inisialisasi). Apakah itu masuk akal?
floatingLomas
37

Saya tidak yakin apakah ini akan tetap berguna bagi orang, tetapi dengan ES6 saya memiliki cara untuk melakukannya yang menurut saya bersih dan berguna.

class MyClass { 
  constructor ( arg1, arg2, arg3 )
  myFunction1 () {...}
  myFunction2 () {...}
  myFunction3 () {...}
}

module.exports = ( arg1, arg2, arg3 ) => { return new MyClass( arg1,arg2,arg3 ) }

Dan kemudian Anda mendapatkan perilaku yang Anda harapkan.

var MyClass = require('/MyClass.js')( arg1, arg2, arg3 )
vovkman.dll
sumber
32

Iya. Dalam loginmodul Anda , cukup ekspor satu fungsi yang mengambil dbargumennya. Sebagai contoh:

module.exports = function(db) {
  ...
};
David Weldon
sumber
1
Saya mencoba ini. Di login.js module.exports = function(app,db) { ... } module.exports.auth = function(req,res) { ... authentication stuff } Itu memanggil fungsi "anonim" dan menetapkan variabel appdan db, tetapi, ketika melakukan ini aplikasi saya tidak akan menemukan authfungsi tersebut. Apa yang saya lakukan salah? Jika saya menghapus fungsi anonim, authfungsi tersebut dapat diakses lagi.
Andreas Selenwall
Seperti segala sesuatu di javascript, exportsadalah sebuah objek. Anda dapat menetapkan properti untuk itu (beberapa ekspor), atau Anda dapat menetapkannya ke sebuah nilai. Sepertinya Anda menetapkan ekspor ke suatu fungsi, tetapi kemudian menetapkan auth sebagai properti dari fungsi yang Anda tetapkan untuk ekspor. Jadi, Anda perlu melakukan var auth = require("./login.js").authyang mungkin bukan yang Anda inginkan. Jika Anda ingin menggunakan pola dari pertanyaan awal, mungkin yang terbaik adalah tetap menggunakan satu nilai ekspor. Jika ini masih tidak masuk akal, saya sarankan untuk memposting inti agar saya dapat melihatnya.
David Weldon
1
Setelah membaca ini lagi, sepertinya Anda telah menetapkan authsebagai properti exportsobjek, dan kemudian di modul Anda menetapkan exportsfungsi (sehingga menimpa tugas sebelumnya). Jika Anda membalik urutan penetapan, Anda seharusnya dapat mengakses authfungsi seperti yang diharapkan. Sekali lagi sulit untuk mengatakannya tanpa benar-benar melihat kodenya.
David Weldon
1
Terima kasih banyak atas bantuan Anda. Apa yang saya tidak sadari adalah persis apa yang Anda tuju dengan require ('login']. Auth. Saya meskipun tidak ada perbedaan dalam var login = require('login')dan var login = require('login')(app), tetapi ada perbedaan besar, tidak ada keajaiban dalam fungsi anonim yang dikembalikan, itu hanya fungsi / objek lain. Alih-alih memiliki a module.exports.auth, fungsi anomim sekarang mengembalikan fungsi autentikasi (di antara yang lain), yaitu return { auth: authFunction, login: loginFunction}. Jadi sekarang ini berhasil. Terima kasih.
Andreas Selenwall