các biến toàn cầu của node.js?


208

Tôi hỏi ở đây: node.js yêu cầu kế thừa?

và được cho biết rằng tôi có thể đặt các biến thành phạm vi toàn cầu bằng cách loại bỏ var.

Điều này không làm việc cho tôi.

I E:

_ = require('underscore');

Không làm cho _ có sẵn trên các tập tin cần thiết. Tôi có thể thiết lập với express app.setvà mặc dù nó có sẵn ở nơi khác.

Ai đó có thể xác nhận rằng điều này được cho là để làm việc? Cảm ơn.


Nơi nào bạn có dòng trên?
Jan Hančič

3
Tôi nghĩ bạn không nên bắt đầu một câu hỏi mới nếu câu trả lời cho câu hỏi trước đó của bạn không hoạt động. Thay vì thêm một bình luận ở đó và loại bỏ các thẻ được chấp nhận.
alienhard

5
Chỉ cần chỉnh sửa nó sẽ xuất hiện trong danh sách câu hỏi hiện đang hoạt động.
MAK

3
Sử dụng exports. Nó tốt hơn nhiều.
Emmerman

1
Có thể nó không hoạt động vì bạn đã "sử dụng nghiêm ngặt"; trên đầu tập tin của bạn Nó hoạt động như thế đối với tôi.
Geza Turi

Câu trả lời:


237

Bạn có thể sử dụng globalnhư vậy:

global._ = require('underscore')

28
Bạn có thể cung cấp thêm một chút thông tin xin vui lòng? Đây là một phần của javascript hay một phần của nút? Đó có phải là một mô hình tốt để làm theo? Tôi nên làm điều này hay tôi nên sử dụng bộ chuyển phát nhanh? Cảm ơn
Harry

4
Nhận xét trước đó không chính xác. Trong trình duyệt, windowlà đối tượng toàn cầu. documentlà một tài sản của window.
G-Wiz

77
Đây KHÔNG phải là một mô hình tốt để làm theo. Đừng làm điều này. Quy ước sử dụng 'yêu cầu' để tách các mô-đun được nghĩ ra. Bạn không nên vi phạm nó mà không có lý do chính đáng. Xem phản hồi của tôi dưới đây.
Dave Dopson

Globals thường được tránh, nhưng nếu bạn thực sự muốn sử dụng chúng. 3 câu lệnh dưới đây đều tương đương và sẽ gán một var cho phạm vi toàn cục: GLOBAL._ = quiries ('gạch dưới'); global._ = Yêu cầu ('gạch dưới'); _ = Yêu cầu ('gạch dưới');
metaColin

Khi dự án của bạn bắt đầu trở nên lớn hơn một chút, điều này sẽ trở thành một cơn ác mộng cần duy trì. Xin hãy xem cách tiếp cận của tôi.
Oliver Dixon

219

Trong nút, bạn có thể đặt các biến toàn cục thông qua đối tượng "toàn cầu" hoặc "TOÀN CẦU":

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

hoặc hữu ích hơn ...

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

Từ nguồn nút, bạn có thể thấy rằng chúng được đặt bí danh cho nhau:

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

Trong đoạn mã trên, "cái này" là bối cảnh toàn cầu. Với hệ thống mô-đun commonJS (nút nào sử dụng), đối tượng "này" bên trong mô-đun (nghĩa là "mã của bạn") KHÔNG phải là bối cảnh toàn cầu. Để chứng minh điều này, hãy xem bên dưới nơi tôi phun đối tượng "này" và sau đó là đối tượng "TOÀN CẦU" khổng lồ.

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: {} }
*/

** Lưu ý: liên quan đến cài đặt "GLOBAL._", nói chung bạn chỉ nên làm var _ = require('underscore');. Có, bạn làm điều đó trong mỗi tệp sử dụng dấu gạch dưới, giống như cách bạn làm trong Java import com.foo.bar;. Điều này giúp dễ dàng tìm ra mã của bạn đang làm gì vì các liên kết giữa các tệp là 'rõ ràng'. Hơi khó chịu, nhưng là một điều tốt. .... Đó là lời rao giảng.

Có một ngoại lệ cho mọi quy tắc. Tôi đã có chính xác MỘT trường hợp cần thiết để đặt "GLOBAL._". Tôi đã tạo ra một hệ thống để xác định các tệp "cấu hình" về cơ bản là JSON, nhưng được "viết bằng JS" để cho phép linh hoạt hơn một chút. Các tệp cấu hình như vậy không có câu lệnh 'yêu cầu', nhưng tôi muốn chúng có quyền truy cập vào dấu gạch dưới (hệ thống ENTIRE được cung cấp trên các mẫu gạch dưới và gạch dưới), vì vậy trước khi đánh giá "cấu hình", tôi sẽ đặt "GLOBAL._". Vì vậy, yeah, đối với mọi quy tắc, có một ngoại lệ ở đâu đó. Nhưng tốt hơn hết là bạn nên có một lý do chính đáng và không chỉ là "tôi cảm thấy mệt mỏi khi gõ" yêu cầu "nên tôi muốn nghỉ ngơi theo quy ước".


7
Những nhược điểm của việc sử dụng GLOBAL là gì? Tại sao tôi cần một lý do chính đáng? Điểm mấu chốt là ứng dụng của tôi hoạt động, phải không?
trusktr

26
cuối cùng, vâng, nếu bạn vận chuyển, đó là tất cả những gì được tính. Tuy nhiên, một số thực tiễn nhất định được gọi là "thực tiễn tốt nhất" và việc tuân theo chúng thường làm tăng tỷ lệ vận chuyển của bạn và / hoặc có thể duy trì những gì bạn đã xây dựng. Tầm quan trọng của việc tuân theo "thực hành tốt" tăng theo quy mô của dự án và đó là tuổi thọ. Tôi đã xây dựng tất cả các loại hack khó chịu vào các dự án có thời gian ngắn viết một lần, không bao giờ đọc (và "nhà phát triển đơn lẻ"). Trong một dự án lớn hơn, việc cắt góc đó kết thúc với chi phí cho động lực dự án của bạn.
Dave Dopson

48
Cụ thể, với GLOBAL, vấn đề là một trong những điều dễ đọc. Nếu chương trình của bạn sử dụng bừa bãi các biến toàn cục, điều đó có nghĩa là để hiểu mã, tôi phải hiểu trạng thái thời gian chạy động của toàn bộ ứng dụng. Đây là lý do tại sao các lập trình viên là tinh ranh của toàn cầu. Tôi chắc chắn có hàng tá cách để sử dụng chúng một cách hiệu quả, nhưng chúng ta hầu như chỉ thấy chúng bị các lập trình viên cơ sở lạm dụng để làm xấu sản phẩm.
Dave Dopson

2
Tại sao bạn không thể đặt cấu hình của mình vào một .jstệp thông thường và gọi requiretrước khi xuất cấu hình?
Azat

4
@Jackie - vi.wikipedia.org/wiki/Singleton_potype . nếu những gì bạn đang làm bản đồ cho mẫu Singleton, thì nó có thể có ý nghĩa. Các kết nối DB có thể là singletons khi: 1) thiết lập tốn kém, 2) bạn chỉ muốn kết nối được thiết lập một lần, 3) đối tượng kết nối tồn tại lâu và sẽ không rơi vào trạng thái thất bại trong trường hợp trục trặc mạng, 4) đối tượng kết nối là an toàn luồng / có thể được chia sẻ bởi nhiều người gọi khác nhau.
Dave Dopson

78

Các giải pháp khác sử dụng từ khóa GLOBAL là một cơn ác mộng để duy trì / khả năng đọc (+ ô nhiễm không gian tên và lỗi) khi dự án trở nên lớn hơn. Tôi đã thấy lỗi này nhiều lần và gặp khó khăn khi sửa nó.

Sử dụng tệp JS sau đó sử dụng mô-đun xuất.

Thí dụ:

globalals.js

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

module.exports = Globals;

Sau đó, nếu bạn muốn sử dụng chúng, sử dụng yêu cầu.

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

12
Tôi chắc chắn không yêu Unicorns nhưng thích cách tiếp cận của bạn. Cảm ơn.
Jonatas Walker

Điều gì về việc thay đổi globals.domainmặc dù?
Fizzix

1
@iLoveUnicorns cảm ơn bạn đã trả lời. Tôi sẽ xem xét các lựa chọn thay thế, chẳng hạn như 'phiên nhanh' vì tôi chủ yếu cần nó để lưu trữ dữ liệu người dùng đã đăng nhập.
Fizzix

11
Mặc dù điều này theo tôi là một cách tiếp cận tốt hơn, nó không tạo ra toàn cầu và không trả lời câu hỏi được hỏi. Đó là một cách tiếp cận khác và tôi luôn khuyến khích những người đó, tuy nhiên, những tuyên bố rất khó hiểu như "Đây là câu trả lời đúng duy nhất về chủ đề này" đơn giản là không thuộc về nơi này. stackoverflow.com/help/be-nice
Thor84no

2
Đây có thể là một cách tiếp cận tốt hơn, nhưng nếu bạn đang cố chạy các tập lệnh được tác giả bên ngoài dựa vào thứ gì đó trong không gian tên toàn cầu, thì điều này không giúp ích gì cho bạn. IOW, điều này không trả lời câu hỏi.
b Liệu

12

Một không gian tên toàn cầu như thế nào global.MYAPI = {}

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

Chỉnh sửa sau khi nhận xét của camilo-martin : Tất cả các áp phích khác nói về mô hình xấu liên quan. Vì vậy, để cuộc thảo luận đó sang một bên, cách tốt nhất để có một biến được xác định trên toàn cầu (câu hỏi của OP) là thông qua các không gian tên.

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


3
Đó là những gì requiredành cho! Bạn có thể sử dụng các không gian tên, nhưng đừng sử dụng global.foo = global.foo || {}tất cả các tệp hoặc một cái gì đó. Yêu cầu tệp xác định không gian tên. Làm điều đó cho các em.
Camilo Martin

@ camilo-martin Xin chào, 1) Bằng cách xác định toàn cầu.MYAPI._ bạn không cần xác định nó trong tất cả các tệp, đó là lý do của toàn cầu. 2) Điều này không có gì phải có với trẻ em. Ngay cả khi tất cả nói rằng đó là mô hình xấu, điều đó phụ thuộc vào lập trình viên và tình huống được đưa ra về cách anh ta sử dụng capabiltiy của ngôn ngữ này.
Igor Parra

2
Có, nhưng giả sử bạn khai báo một số chức năng của một không gian tên trong một tệp riêng biệt. Sau đó, bạn đang yêu cầu một tệp để sử dụng đối tượng, ngược lại và đi ngược lại với CommonJS và CommonSense. Nếu bạn sẽ yêu cầu công cụ, có mã người dùng yêu cầu không gian tên và không được yêu cầu bởi không gian tên. Lưu ý Tôi không nói bất cứ điều gì chống lại không gian tên, chỉ là có những quy ước về việc ai gọi ai vì lý do. Và ở phía máy khách, bạn không có nút nào; hãy xem liên kết mà bạn đề cập đang thực hiện mọi thứ theo một cách nhất định (thông qua toàn cầu) bởi vì đó là về trình duyệt chứ không phải nút.
Camilo Martin

1
Đáng buồn là URL bạn chỉ đăng tải hoạt động nếu bạn bỏ qua các dấu gạch chéo;)
sai khiến được

10

Bạn chỉ có thể sử dụng các đối tượng toàn cầu.

var X = ['a', 'b', 'c'];
global.x = X;

console.log(x);
//['a', 'b', 'c']

5

Tôi đồng ý rằng việc sử dụng không gian tên toàn cầu / TOÀN CẦU để thiết lập mọi thứ toàn cầu là thực tiễn xấu và hoàn toàn không sử dụng nó trong lý thuyết ( về lý thuyết là từ hoạt động). Tuy nhiên (vâng, chính thức) Tôi sử dụng nó để thiết lập các lớp Lỗi tùy chỉnh:

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

global.MyError = [Function of MyError];

Có, điều cấm kỵ ở đây, nhưng nếu trang web / dự án của bạn sử dụng các lỗi tùy chỉnh ở khắp nơi, về cơ bản bạn sẽ cần xác định nó ở mọi nơi hoặc ít nhất là ở đâu đó để:

  1. Xác định lớp Error ở vị trí đầu tiên
  2. Trong kịch bản mà bạn đang ném nó
  3. Trong kịch bản mà bạn đang bắt nó

Xác định lỗi tùy chỉnh của tôi trong không gian tên toàn cầu giúp tôi tránh được rắc rối khi yêu cầu thư viện lỗi khách hàng của mình. Hình ảnh ném một lỗi tùy chỉnh trong đó lỗi tùy chỉnh không được xác định.

Ngoài ra, nếu điều này là sai thì xin vui lòng cho tôi biết vì tôi chỉ mới bắt đầu làm điều này gần đây

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.