แชร์ตัวแปรระหว่างไฟล์ใน Node.js?


126

นี่คือ 2 ไฟล์:

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

// module.js
name = "foobar";

เมื่อฉันไม่มี "var" มันใช้งานได้ แต่เมื่อฉันมี:

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

ชื่อจะไม่ถูกกำหนดใน main.js

ฉันได้ยินมาว่าตัวแปรทั่วโลกไม่ดีและคุณควรใช้ "var" ก่อนการอ้างอิง แต่นี่เป็นกรณีที่ตัวแปรทั่วโลกดีหรือไม่?

คำตอบ:


184

ตัวแปรทั่วโลกแทบไม่เคยเป็นสิ่งที่ดีเลย (อาจมีข้อยกเว้นหรือสองข้อ ... ) ในกรณีนี้ดูเหมือนว่าคุณต้องการส่งออกตัวแปร "name" ของคุณจริงๆ เช่น,

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

จากนั้นใน 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
ตัวแปรทั่วโลกไม่ดี - ฉันเห็นด้วยอย่างยิ่งกับสิ่งนั้น แต่ฉันอาจจะเป็นได้ว่าโมดูลมีการพึ่งพาตัวแปร มีวิธีส่งตัวแปรนี้ไปยังไฟล์ js อื่นผ่านฟังก์ชัน require หรือไม่?
appsthatmatter

1
@ jjoe64 ไม่แน่ใจว่าฉันทำตามที่คุณหมายถึง คุณสามารถแบ่งปันคุณค่าที่คุณต้องการผ่านexportsวัตถุได้อย่างมีประสิทธิภาพ
jmar777

7
OP กำลังถามว่าสามารถกำหนดตัวแปรใน main.js หรือไม่แล้วใช้ใน module.js ฉันมีข้อกำหนดเดียวกันในการกำหนดเส้นทางที่ใช้ซ้ำแล้วซ้ำเล่า
designermonkey

4
@Designermonkey ในกรณีนี้คุณอาจจะดีกว่าถ้ามีวัตถุ config ที่มีประเภทของค่าเหล่านั้นซึ่งสามารถกำหนดให้ () 'd ลงในไฟล์ที่กำหนดได้ โปรดทราบว่าคุณสามารถทำได้global.foo = 'bar'แล้วเข้าถึงfooได้ทุกที่ที่คุณต้องการ ... แต่อย่างที่ฉันพูดในคำตอบเดิมนั่นแทบไม่เคยเป็นสิ่งที่ดีเลย
jmar777

ขอบคุณสำหรับสิ่งนั้นฉันคิดหาวิธีทำและมันก็ใช้ได้ผลดี ขอบคุณสำหรับการยืนยันว่าฉันมีความคิดที่ถูกต้อง :)
designermonkey

37

ฉันไม่พบสถานการณ์ที่โลกvarเป็นตัวเลือกที่ดีที่สุดแน่นอนว่าคุณสามารถมีได้ แต่ลองดูตัวอย่างเหล่านี้แล้วคุณอาจพบวิธีที่ดีกว่าในการทำสิ่งเดียวกันให้สำเร็จ:

สถานการณ์ที่ 1: ใส่สิ่งต่างๆในไฟล์ config

คุณต้องการค่าบางอย่างที่เหมือนกันในแอปพลิเคชัน แต่จะเปลี่ยนแปลงไปขึ้นอยู่กับสภาพแวดล้อม (การผลิตการพัฒนาหรือการทดสอบ) ประเภทจดหมายตามตัวอย่างที่คุณต้องการ:

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

และ

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

(สร้าง config ที่คล้ายกันสำหรับ dev ด้วย)

ในการตัดสินใจว่าจะโหลดการกำหนดค่าใดให้สร้างไฟล์กำหนดค่าหลัก (จะใช้กับแอปพลิเคชันทั้งหมด)

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

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

และตอนนี้คุณจะได้รับข้อมูลดังนี้:

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

สถานการณ์ที่ 2: ใช้ไฟล์ค่าคงที่

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

และใช้วิธีนี้

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

สถานการณ์ที่ 3: ใช้ฟังก์ชันตัวช่วยเพื่อรับ / ตั้งค่าข้อมูล

ไม่ใช่แฟนตัวยงของคนนี้ แต่อย่างน้อยคุณสามารถติดตามการใช้ 'ชื่อ' (อ้างถึงตัวอย่างของ OP) และทำการตรวจสอบความถูกต้อง

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

และใช้มัน

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

อาจมีกรณีการใช้งานเมื่อไม่มีวิธีแก้ปัญหาอื่นนอกจากการมี global varแต่โดยปกติคุณสามารถแชร์ข้อมูลในแอปของคุณโดยใช้สถานการณ์เหล่านี้หากคุณเริ่มใช้ node.js (เหมือนที่เคยเป็นมาก่อน) ลอง เพื่อจัดระเบียบวิธีจัดการข้อมูลตรงนั้นเพราะอาจทำให้ยุ่งได้อย่างรวดเร็ว


ฉันชอบสถานการณ์ที่ 2 แต่ค่าเหล่านี้สามารถเปลี่ยนแปลงได้หลังจากที่เราพูดถึงการสร้างหรือไม่ เช่นเดียวกับที่เราทำบ่อยที่สุด npm รัน build หรือคุณรู้วิธีที่จะสามารถเปลี่ยนค่าหลังจากสร้างหรือไม่?
Kashif Ullah

@KashifUllah ไม่แน่ใจว่าฉันสามารถตอบความคิดเห็นของคุณได้ด้วยข้อมูลที่ให้มาหรือไม่คุณอาจต้องการเพิ่มคำถามใหม่ในเว็บไซต์
Felipe Pereira

16

หากเราต้องการแชร์ตัวแปรหลายตัวให้ใช้รูปแบบด้านล่าง

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

   module.exports={
    name,
    city,
    company
  }

การใช้

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

2
เพียงบันทึกสั้น ๆ เพื่อขจัดความสับสนที่อาจเกิดขึ้นในจุดแรก: module.exports คือสิ่งที่ควรใช้! สิ่งที่เรียกว่าไฟล์ js ของคุณ (เช่น global.js) โมดูลคือวัตถุโหนดที่มีอยู่ในขอบเขตส่วนกลาง! [ดังนั้นภายใน global.js เราใช้ module.exports = ..... ]
Mohamed Allal

มันจะประสบความสำเร็จถ้าคุณลบ 'let' และไม่จำเป็นต้อง "module.exports .. "
Ahmad Zahabi

6

บันทึกตัวแปรใด ๆ ที่ต้องการแชร์เป็นออบเจ็กต์เดียว จากนั้นส่งไปยังโมดูลที่โหลดเพื่อให้สามารถเข้าถึงตัวแปรผ่านการอ้างอิงวัตถุ ..

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

ในไฟล์อื่น ..

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

ตัวแปรที่ประกาศโดยมีหรือไม่มีคีย์เวิร์ด var ติดอยู่กับอ็อบเจ็กต์ส่วนกลาง นี่เป็นพื้นฐานสำหรับการสร้างตัวแปรส่วนกลางในโหนดโดยการประกาศตัวแปรโดยไม่มีคีย์เวิร์ด var ในขณะที่ตัวแปรที่ประกาศด้วยคีย์เวิร์ด var ยังคงอยู่ในโมดูล

ดูบทความนี้เพื่อความเข้าใจเพิ่มเติม - https://www.hacksparrow.com/global-variables-in-node-js.html


3
เศษเหล่านี้ขัดแย้งหรือไม่? 1) "ตัวแปรที่ประกาศโดยมีหรือไม่มีคีย์เวิร์ด var ติดอยู่กับ global object" และ 2) "ตัวแปรที่ประกาศด้วยคีย์เวิร์ด var ยังคงอยู่ในโมดูล"
BaldEagle

1

ด้วยความเห็นที่แตกต่างฉันคิดว่าglobalตัวแปรอาจเป็นตัวเลือกที่ดีที่สุดหากคุณกำลังจะเผยแพร่รหัสของคุณnpmเพราะคุณไม่สามารถมั่นใจได้ว่าแพ็คเกจทั้งหมดใช้รหัสรุ่นเดียวกัน ดังนั้นหากคุณใช้ไฟล์ในการส่งออกsingletonวัตถุจะทำให้เกิดปัญหาที่นี่

คุณสามารถเลือกglobal, require.mainหรือวัตถุอื่นใดที่มีการใช้ร่วมกันในไฟล์

โปรดบอกฉันว่ามีวิธีแก้ไขที่ดีกว่านี้หรือไม่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.