ตัวแปรโกลบอล node.js?


208

ฉันถามที่นี่: node.js ต้องการการสืบทอด?

และได้รับการบอกว่าฉันสามารถตั้งค่าตัวแปรให้เป็นขอบเขตทั่วโลกได้โดยไม่ต้องใส่ค่าต่างๆ

สิ่งนี้ไม่ได้ผลสำหรับฉัน

เช่น:

_ = require('underscore');

ไม่ทำให้ _ พร้อมใช้งานในไฟล์ที่จำเป็น ฉันสามารถตั้งค่าของด่วนapp.setและมีให้ที่อื่นแม้ว่า

มีใครยืนยันได้ไหมว่าสิ่งนี้ควรจะใช้ได้ ขอบคุณ


คุณมีบรรทัดข้างต้นอยู่ที่ไหน
Jan Hančič

3
ฉันคิดว่าคุณไม่ควรเริ่มคำถามใหม่หากคำตอบของคำถามก่อนหน้านี้ใช้ไม่ได้ ค่อนข้างเพิ่มความคิดเห็นที่นั่นและลบแท็กที่ยอมรับ
alienhard

5
เพียงแค่แก้ไขมันทำให้มันปรากฏในรายการคำถามที่ใช้งานในปัจจุบัน
MAK

3
exportsใช้ มันดีกว่ามาก
Emmerman

1
อาจจะไม่ได้ผลเพราะคุณใช้ "เข้มงวด"; ที่ด้านบนของไฟล์ของคุณ มันใช้งานได้สำหรับฉัน
Geza Turi

คำตอบ:


237

คุณสามารถใช้globalเช่น:

global._ = require('underscore')

28
กรุณาให้ข้อมูลเพิ่มเติมหน่อยได้ไหม? เป็นส่วนหนึ่งของจาวาสคริปต์หรือส่วนหนึ่งของโหนดนี้หรือไม่? เป็นรูปแบบที่ดีที่จะติดตามหรือไม่ ในฉันควรทำเช่นนี้หรือฉันควรใช้การตั้งค่าแบบด่วน? ขอบคุณ
Harry

4
ความคิดเห็นก่อนหน้านี้ไม่ถูกต้อง ในเบราว์เซอร์windowเป็นวัตถุทั่วโลก เป็นทรัพย์สินของdocument window
G-Wiz

77
นี่ไม่ใช่รูปแบบที่ดีที่จะติดตาม อย่าทำอย่างนี้ แบบแผนของการใช้ 'ต้องการ' เพื่อแยกโมดูลเป็นความคิดที่ดี คุณไม่ควรละเมิดโดยไม่มีเหตุผลที่ดี ดูคำตอบของฉันด้านล่าง
Dave Dopson

Globals โดยทั่วไปจะต้องหลีกเลี่ยง แต่ถ้าคุณต้องการใช้พวกเขาจริงๆ คำสั่ง 3 รายการด้านล่างนี้เทียบเท่ากันทั้งหมดและจะกำหนด var ให้กับขอบเขตทั่วโลก: GLOBAL._ = require ('ขีดล่าง'); global._ = ต้องการ ('ขีดล่าง'); _ = ต้องการ ('ขีดล่าง');
metaColin

เมื่อโครงการของคุณเริ่มใหญ่ขึ้นเล็กน้อยสิ่งนี้จะกลายเป็นฝันร้ายที่ต้องรักษา โปรดดูวิธีการของฉัน
Oliver Dixon

219

ในโหนดคุณสามารถตั้งค่าตัวแปรส่วนกลางผ่านวัตถุ "global" หรือ "GLOBAL":

GLOBAL._ = require('underscore'); // but you "shouldn't" do this! (see note below)

หรือมากกว่าที่เป็นประโยชน์ ...

GLOBAL.window = GLOBAL;  // like in the browser

จากแหล่งที่มาของโหนดคุณจะเห็นว่าสิ่งเหล่านี้มีนามแฝงซึ่งกันและกัน:

node-v0.6.6/src/node.js:
28:     global = this;
128:    global.GLOBAL = global;

ในรหัสข้างต้น "นี่" เป็นบริบททั่วโลก ด้วยระบบโมดูล commonJS (ซึ่งโหนดใช้) วัตถุ "this" ภายในโมดูล (เช่น "รหัสของคุณ") ไม่ใช่บริบททั่วโลก สำหรับข้อพิสูจน์นี้ดูด้านล่างที่ที่ฉันพ่นวัตถุ "นี่" แล้วก็วัตถุยักษ์ "ทั่วโลก"

console.log("\nTHIS:");
console.log(this);
console.log("\nGLOBAL:");
console.log(global);

/* outputs ...

THIS:
{}

GLOBAL:
{ ArrayBuffer: [Function: ArrayBuffer],
  Int8Array: { [Function] BYTES_PER_ELEMENT: 1 },
  Uint8Array: { [Function] BYTES_PER_ELEMENT: 1 },
  Int16Array: { [Function] BYTES_PER_ELEMENT: 2 },
  Uint16Array: { [Function] BYTES_PER_ELEMENT: 2 },
  Int32Array: { [Function] BYTES_PER_ELEMENT: 4 },
  Uint32Array: { [Function] BYTES_PER_ELEMENT: 4 },
  Float32Array: { [Function] BYTES_PER_ELEMENT: 4 },
  Float64Array: { [Function] BYTES_PER_ELEMENT: 8 },
  DataView: [Function: DataView],
  global: [Circular],
  process: 
   { EventEmitter: [Function: EventEmitter],
     title: 'node',
     assert: [Function],
     version: 'v0.6.5',
     _tickCallback: [Function],
     moduleLoadList: 
      [ 'Binding evals',
        'Binding natives',
        'NativeModule events',
        'NativeModule buffer',
        'Binding buffer',
        'NativeModule assert',
        'NativeModule util',
        'NativeModule path',
        'NativeModule module',
        'NativeModule fs',
        'Binding fs',
        'Binding constants',
        'NativeModule stream',
        'NativeModule console',
        'Binding tty_wrap',
        'NativeModule tty',
        'NativeModule net',
        'NativeModule timers',
        'Binding timer_wrap',
        'NativeModule _linklist' ],
     versions: 
      { node: '0.6.5',
        v8: '3.6.6.11',
        ares: '1.7.5-DEV',
        uv: '0.6',
        openssl: '0.9.8n' },
     nextTick: [Function],
     stdout: [Getter],
     arch: 'x64',
     stderr: [Getter],
     platform: 'darwin',
     argv: [ 'node', '/workspace/zd/zgap/darwin-js/index.js' ],
     stdin: [Getter],
     env: 
      { TERM_PROGRAM: 'iTerm.app',
        'COM_GOOGLE_CHROME_FRAMEWORK_SERVICE_PROCESS/USERS/DDOPSON/LIBRARY/APPLICATION_SUPPORT/GOOGLE/CHROME_SOCKET': '/tmp/launch-nNl1vo/ServiceProcessSocket',
        TERM: 'xterm',
        SHELL: '/bin/bash',
        TMPDIR: '/var/folders/2h/2hQmtmXlFT4yVGtr5DBpdl9LAiQ/-Tmp-/',
        Apple_PubSub_Socket_Render: '/tmp/launch-9Ga0PT/Render',
        USER: 'ddopson',
        COMMAND_MODE: 'unix2003',
        SSH_AUTH_SOCK: '/tmp/launch-sD905b/Listeners',
        __CF_USER_TEXT_ENCODING: '0x12D732E7:0:0',
        PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:~/bin:/usr/X11/bin',
        PWD: '/workspace/zd/zgap/darwin-js',
        LANG: 'en_US.UTF-8',
        ITERM_PROFILE: 'Default',
        SHLVL: '1',
        COLORFGBG: '7;0',
        HOME: '/Users/ddopson',
        ITERM_SESSION_ID: 'w0t0p0',
        LOGNAME: 'ddopson',
        DISPLAY: '/tmp/launch-l9RQXI/org.x:0',
        OLDPWD: '/workspace/zd/zgap/darwin-js/external',
        _: './index.js' },
     openStdin: [Function],
     exit: [Function],
     pid: 10321,
     features: 
      { debug: false,
        uv: true,
        ipv6: true,
        tls_npn: false,
        tls_sni: true,
        tls: true },
     kill: [Function],
     execPath: '/usr/local/bin/node',
     addListener: [Function],
     _needTickCallback: [Function],
     on: [Function],
     removeListener: [Function],
     reallyExit: [Function],
     chdir: [Function],
     debug: [Function],
     error: [Function],
     cwd: [Function],
     watchFile: [Function],
     umask: [Function],
     getuid: [Function],
     unwatchFile: [Function],
     mixin: [Function],
     setuid: [Function],
     setgid: [Function],
     createChildProcess: [Function],
     getgid: [Function],
     inherits: [Function],
     _kill: [Function],
     _byteLength: [Function],
     mainModule: 
      { id: '.',
        exports: {},
        parent: null,
        filename: '/workspace/zd/zgap/darwin-js/index.js',
        loaded: false,
        exited: false,
        children: [],
        paths: [Object] },
     _debugProcess: [Function],
     dlopen: [Function],
     uptime: [Function],
     memoryUsage: [Function],
     uvCounters: [Function],
     binding: [Function] },
  GLOBAL: [Circular],
  root: [Circular],
  Buffer: 
   { [Function: Buffer]
     poolSize: 8192,
     isBuffer: [Function: isBuffer],
     byteLength: [Function],
     _charsWritten: 8 },
  setTimeout: [Function],
  setInterval: [Function],
  clearTimeout: [Function],
  clearInterval: [Function],
  console: [Getter],
  window: [Circular],
  navigator: {} }
*/

** หมายเหตุ: เกี่ยวกับการตั้งค่า "GLOBAL._" var _ = require('underscore');โดยทั่วไปคุณก็ควรจะทำอย่างไร import com.foo.bar;ใช่คุณทำในทุกไฟล์เดียวที่ใช้ขีดเช่นเดียวกับวิธีการในชวาที่คุณทำ สิ่งนี้ทำให้ง่ายต่อการทราบว่าโค้ดของคุณทำอะไรอยู่เนื่องจากการเชื่อมโยงระหว่างไฟล์นั้น 'ชัดเจน' น่ารำคาญเล็กน้อย แต่เป็นสิ่งที่ดี .... นั่นคือการเทศนา

มีข้อยกเว้นสำหรับทุกกฎ ฉันมีหนึ่งอินสแตนซ์ที่แน่นอนที่ฉันต้องการตั้งค่า "GLOBAL._" ฉันกำลังสร้างระบบสำหรับการกำหนดไฟล์ "config" ซึ่งโดยทั่วไปคือ JSON แต่ถูก "เขียนด้วย JS" เพื่อให้มีความยืดหยุ่นมากขึ้น ไฟล์กำหนดค่าดังกล่าวไม่มีคำสั่ง 'ต้องการ' แต่ฉันต้องการให้พวกเขามีการเข้าถึงขีดล่าง (ระบบทั้งหมดถูก predicated บนขีดล่างและแม่แบบขีดล่าง) ดังนั้นก่อนที่จะประเมิน "config" ฉันจะตั้งค่า "GLOBAL._" ดังนั้นใช่ทุกกฎมีข้อยกเว้นอยู่ที่ไหนสักแห่ง แต่คุณควรมีเหตุผลที่ดีกว่าและไม่เพียงแค่ "ฉันเบื่อกับการพิมพ์ 'ต้องการ' ดังนั้นฉันจึงอยากหยุดการประชุม"


7
ความล้มเหลวของการใช้งาน GLOBAL คืออะไร ทำไมฉันต้องมีเหตุผลที่ดีสาปแช่ง? บรรทัดล่างคือแอพของฉันทำงานใช่ไหม
trusktr

26
ในที่สุดใช่ถ้าคุณจัดส่งนั่นคือทั้งหมดที่นับ อย่างไรก็ตามแนวปฏิบัติบางอย่างเรียกว่า "แนวปฏิบัติที่ดีที่สุด" และโดยทั่วไปแล้วการปฏิบัติตามนั้นจะเพิ่มโอกาสในการจัดส่งและ / หรือสามารถรักษาสิ่งที่คุณสร้างไว้ได้ ความสำคัญของการปฏิบัติตาม "แนวปฏิบัติที่ดี" จะเพิ่มขึ้นตามขนาดของโครงการและอายุการใช้งานที่ยาวนาน ฉันได้สร้างแฮ็กที่น่ารังเกียจทุกชนิดไว้ในโครงการระยะสั้นที่เขียนครั้งเดียวอ่านไม่ออก (และ "ผู้พัฒนาเดี่ยว") ในโครงการที่ใหญ่กว่าการตัดมุมแบบนั้นจบลงด้วยการคิดต้นทุนโมเมนตัมของโครงการ
Dave Dopson

48
โดยเฉพาะอย่างยิ่งกับ GLOBAL ปัญหาคือหนึ่งในความสามารถในการอ่าน หากโปรแกรมของคุณใช้ตัวแปรทั่วโลกอย่างชัดเจนหมายความว่าเพื่อให้เข้าใจรหัสฉันต้องเข้าใจสถานะรันไทม์แบบไดนามิกของแอปทั้งหมด นี่คือเหตุผลที่โปรแกรมเมอร์เขียนโปรแกรมยากมาก ฉันแน่ใจว่ามีหลายวิธีในการใช้อย่างมีประสิทธิภาพ แต่เราเพิ่งเห็นพวกเขาถูกทารุณกรรมโดยผู้เขียนโปรแกรมรุ่นเยาว์ถึงผลิตภัณฑ์
Dave Dopson

2
เหตุใดคุณจึงไม่สามารถกำหนดค่าของคุณใน.jsไฟล์ปกติและการโทรrequireก่อนที่จะส่งออกการกำหนดค่าได้
Azat

4
@Jackie - en.wikipedia.org/wiki/Singleton_pattern หากสิ่งที่คุณทำแผนที่เป็นรูปแบบซิงเกิลมันอาจสมเหตุสมผล การเชื่อมต่อฐานข้อมูลอาจเป็นแบบซิงเกิลเมื่อ: 1) การตั้งค่ามีราคาแพง 2) คุณต้องการเพียงการเชื่อมต่อที่จะตั้งค่าครั้งเดียว 3) วัตถุการเชื่อมต่อมีอายุการใช้งานนานและจะไม่เข้าสู่สถานะล้มเหลวในกรณีที่เครือข่ายสะดุด 4) วัตถุการเชื่อมต่อเป็น thread-safe / สามารถแชร์โดยผู้โทรหลายคน
Dave Dopson

78

โซลูชันอื่น ๆ ที่ใช้คำสำคัญ GLOBAL เป็นฝันร้ายที่จะรักษา / อ่านได้ (+ เนมสเปซมลพิษและข้อบกพร่อง) เมื่อโครงการเริ่มใหญ่ขึ้น ฉันเคยเห็นข้อผิดพลาดนี้หลายครั้งและมีความยุ่งยากในการแก้ไข

ใช้ไฟล์ JS จากนั้นใช้โมดูลส่งออก

ตัวอย่าง:

globals.js

var Globals = {
    'domain':'www.MrGlobal.com';
}

module.exports = Globals;

จากนั้นหากคุณต้องการใช้สิ่งเหล่านี้ให้ใช้งาน

var globals = require('globals'); //<< globals.js path
globals.domain //<< Domain.

12
ฉันไม่รักยูนิคอร์นแน่นอน แต่ชอบแนวทางของคุณ ขอบคุณ
Jonatas Walker

แล้วการเปลี่ยนแปลงglobals.domainล่ะ
Fizzix

1
@iLoveUnicorns ขอบคุณที่ตอบกลับ ฉันจะพิจารณาทางเลือกอื่น ๆ เช่น 'เซสชันด่วน' เนื่องจากฉันต้องการใช้เป็นหลักในการจัดเก็บข้อมูลผู้ใช้ที่เข้าสู่ระบบ
Fizzix

11
ในขณะที่ในความคิดของฉันเป็นวิธีที่ดีกว่านี้มันไม่ได้สร้างกลมและไม่ตอบคำถามที่ถาม มันเป็นวิธีการทางเลือกและฉันมักจะสนับสนุนสิ่งเหล่านั้นเสมออย่างไรก็ตามคำพูดที่ยั่วยุของคำว่า "นี่เป็นคำตอบที่ถูกต้องเพียงข้อเดียวของหัวข้อนี้" ไม่ได้อยู่ที่นี่ stackoverflow.com/help/be-nice
Thor84no

2
นี่อาจเป็นวิธีที่ดีกว่า แต่ถ้าคุณพยายามเรียกใช้สคริปต์ที่เขียนจากภายนอกซึ่งอาศัยสิ่งที่อยู่ในเนมสเปซส่วนกลางสิ่งนี้จะไม่ช่วยคุณ IOW นี่ไม่ตอบคำถาม
binki

12

สิ่งที่เกี่ยวกับ namespace ทั่วโลกเช่น global.MYAPI = {}

global.MYAPI._ = require('underscore')

แก้ไขหลังจากความคิดเห็นของ camilo-martin : โปสเตอร์อื่น ๆ ทั้งหมดพูดถึงลวดลายที่ไม่ดีที่เกี่ยวข้อง วิธีที่ดีที่สุดที่จะกำหนดตัวแปรทั่วโลก (คำถามของ OP) คือผ่านเนมสเปซ

@tip: http://thanpol.as/javascript/development-using-namespaces


3
นั่นคือสิ่งที่requireมีไว้สำหรับ! ไม่เป็นไรที่จะใช้เนมสเปซ แต่อย่าไปglobal.foo = global.foo || {}กับไฟล์ทั้งหมดหรืออะไรเลย ต้องการไฟล์ที่กำหนดเนมสเปซ ทำเพื่อเด็ก ๆ
Camilo Martin

@ camilo-martin สวัสดี 1) การกำหนด global.MYAPI._ คุณไม่จำเป็นต้องกำหนดไว้ในไฟล์ทั้งหมดนั่นคือเหตุผลของการเป็นโกลบอล 2) สิ่งนี้ไม่ได้อยู่กับลูก แม้ว่าทุกคนบอกว่ามันเป็นรูปแบบที่ไม่ดี แต่ก็ขึ้นอยู่กับโปรแกรมเมอร์และสถานการณ์ที่ได้รับว่าเขาใช้ capabiltiy ของภาษานี้ได้อย่างไร
Igor Parra

2
ใช่ แต่สมมติว่าคุณประกาศฟังก์ชั่นบางอย่างของเนมสเปซในไฟล์แยกต่างหาก จากนั้นคุณต้องใช้ไฟล์เพื่อใช้วัตถุซึ่งอยู่ข้างหลังและข้ามกับ CommonJS และ CommonSense เช่นกัน หากคุณต้องการสิ่งต่าง ๆ ให้ใช้รหัสผู้ใช้กำหนดเนมสเปซและไม่จำเป็นต้องใช้กับเนมสเปซ หมายเหตุฉันไม่ได้พูดอะไรกับ namespaces เพียงว่ามีการประชุมว่าใครโทรหาใครด้วยเหตุผล และในฝั่งไคลเอ็นต์คุณไม่มีโหนดใดที่มี เห็นลิงค์ที่คุณพูดถึงกำลังทำสิ่งต่าง ๆ ในลักษณะที่แน่นอน (ผ่านทั่วโลก) เพราะมันเกี่ยวกับเบราว์เซอร์และไม่ใช่โหนด
Camilo Martin

1
น่าเศร้าที่ URL ที่คุณโพสต์นั้นจะใช้งานได้หากคุณไม่ใช้เครื่องหมายทับต่อท้าย;)
สิทธิ์


5

ผมเห็นว่าการใช้ทั่วโลก / namespace โลกสำหรับการตั้งค่าอะไรทั่วโลกคือการปฏิบัติที่ไม่ดีและไม่ได้ใช้มันเลยในทางทฤษฎี ( ในทางทฤษฎีเป็นคำผ่าตัด) อย่างไรก็ตาม (ใช่ผู้ปฏิบัติการ) ฉันใช้เพื่อตั้งค่าคลาสข้อผิดพลาดที่กำหนดเอง:

// Some global/config file that gets called in initialisation

global.MyError = [Function of MyError];

ใช่ต้องห้ามที่นี่ แต่ถ้าไซต์ / โครงการของคุณใช้ข้อผิดพลาดที่กำหนดเองทั่วทั้งสถานที่โดยทั่วไปคุณจะต้องกำหนดมันทุกที่หรืออย่างน้อยก็เพื่อ:

  1. กำหนดคลาสข้อผิดพลาดในสถานที่แรก
  2. ในบทที่คุณกำลังขว้างมัน
  3. ในสคริปต์ที่คุณจับได้

การกำหนดข้อผิดพลาดที่กำหนดเองของฉันในเนมสเปซส่วนกลางช่วยให้ฉันไม่ต้องยุ่งยากในการหาไลบรารีข้อผิดพลาดของลูกค้า การถ่ายภาพการขว้างข้อผิดพลาดที่กำหนดเองซึ่งข้อผิดพลาดที่กำหนดเองนั้นไม่ได้กำหนดไว้

นอกจากนี้หากผิดโปรดแจ้งให้เราทราบเพราะฉันเพิ่งเริ่มทำสิ่งนี้เมื่อเร็ว ๆ นี้

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