express.js 中的全局函数?

Posted

技术标签:

【中文标题】express.js 中的全局函数?【英文标题】:Global function in express.js? 【发布时间】:2013-05-23 05:35:24 【问题描述】:

如何在 express.js 中定义一个全局函数,没有require 我可以调用它

【问题讨论】:

为什么不想用这个函数创建模块? 【参考方案1】:

如何”很简单:

    global.fnName = function() return "hi"; ; // Andreas Hultgren's answer

但是你不需要global 前缀; global 对象的问题是...

    fnName = function() return "hi"; ; // i.e. don't do: var name = function() ... ;
    console.log(fnName());         // this prints "hi"
    console.log(global.fnName());  // this also prints "hi" - it was assigned to global.

“没有require”是一个单独的考虑因素:如果您不使用require,则无法保证您的“全局变量”会在您需要它们时被声明。它强制执行依赖项的加载顺序等。

我为什么是”和“它是否正确”现在是您应该考虑的隐藏问题。 javascript 中接受全局变量 ...

... 应该为具有系统范围相关性的对象保留,并且应该为它们命名以避免歧义并将命名冲突的风险降至最低 - Angus Croll, Namespacing in Javascript

global 确实是全球性的:它被您拉入应用程序的每个插件或库的每个作者使用,而不仅仅是您。 全局变量之间的命名冲突会破坏您的应用程序。这同样适用于 node.js。

全局变量也被认为是as a code smell。在下面的详细部分中,您将看到使用全局变量会很快陷入困境,它们应该真正被视为推动您走向依赖注入和/或命名空间和模块的东西。

Node.js 和 express - 全局变量和函数

这里有一个很好的规则:如果您将其上传到网络服务器,或与其他人共享,请不要使用全局变量。

global 在微小的“星期六下午”应用程序in node.js with express.js 中是允许的,但如果它们被采用到生产环境中,往往会在以后引起问题。因此:

模块和exports 是最佳实践。 还应该使用注入来减少 javascript 文件之间的耦合。但在所有情况下,您通常都需要 require 以确保它们在您需要时存在:

对于与视图数据相关的任何内容,您真的应该考虑 app.locals 数据和/或 middleware functions。

// call this as a function with an input object to merge 
//  the new properties with any existing ones in app.locals
app.locals.(
  sayHello: function()  return "hi"; 
);    

// now you can also use this in a template, like a jade template
=sayHello()

如果您为配置设置目的创建全局变量/函数,则以下有关命名空间的 cmets 仍然适用,并且出现了一些约定,例如 config.json 文件(仍然使用require)用于全局访问的设置。

全局变量 - 简单案例

在 javascript 中声明一个全局变量很简单,对于一个函数来说,这个过程也没有什么不同。只需省略 var 关键字,这通常会在声明中强制使用本地范围:

// app.js
blah = "boo";
sayHello = function(string toWho)  return "hello " + toWho; 
getVersion = function()  return "0.0.0.1"; 

// routes/main.js
console.log(blah);                     // logs: "boo"
console.log(global.blah);              // logs: "boo"
console.log(sayHello("World"));        // logs: "hello World"
console.log(global.sayHello("World")); // logs: "hello World"
console.log(getVersion());             // logs: "0.0.0.1"

但是,如果您的项目中的两个独立插件使用全局 getVersion 函数怎么办 - 您如何获得正确的版本号?另外,您如何确保getVersion 在您需要它之前就已经存在,或者根本就存在?

为什么我们需要require

引用nodejitsu docs内置的require function ...

... 是包含存在于单独文件中的模块的最简单方法。 require 的基本功能是读取一个 javascript 文件,执行该文件,然后继续返回 exports 对象

所以”,你可能会问,“require 只是确保包含来自另一个文件的module?何必呢?”那:你可以创建一个whole folder a module,让你的代码更容易组织和测试测试,它会识别file modules的各种扩展,而不仅仅是.js,它在various folders as well中的will look。当然,it caches 也是如此。

所以,既然require 找到了您的模块,它会确保执行其中的代码,并将您创建的对象放入“命名空间”中:

// module file ./myModule.js
exports.blah = "boo";
exports.sayHello = function(string toWho)  return "hello " + toWho; 

// routes/main.js
var demoModuleReference = require('./myModule.js');
console.log(demoModuleReference.blah);           // logs: "boo"
console.log(demoModuleReference.sayHello("World"));   // logs: "hello World"

在该示例中,demoModuleReference 是一个如下所示的对象:


  blah: "foo",
  sayHello: [Function]

为什么是模块而不是全局变量(又名命名空间和“全局是新的私有”)?

现在看起来很复杂?全局变量肯定更容易吗? requires 确保以下内容:

确保有序加载依赖项 它通过exports 对象防止global 内的变量名冲突

This application at mankz.com (chrome or firefox only) 很迷人。根据您使用 js 代码的方式,您很可能在全局范围内发生变量名称冲突。名称冲突无处不在。例如,在浏览器中,它们可以来自扩展。 node.js 略有不同,但随着时间的推移,兼容插件越来越多地扩展它(例如,您现在可以加载 jquery)。随着版本的继续,框架将被添加,全局名称冲突将变得更有可能。我上次在 chrome 中运行该应用程序时显示了 1200 多个全局命名空间变量。

命名空间 - 为什么?

Douglas Crockford 很早就通过 Eric Miraglia 在文章“A JavaScript Module Pattern”中公开了这种全局命名空间污染。总结:

js文件之间需要用到的所有对象都是全局的 因此,创建一个唯一的命名空间对象 将返回值分配给匿名函数 在该函数中添加私有方法和变量 用模式做一些有用的事情

例子:

ANDYBROWNSONICSUITE.BoomBox.SoundModule = function () 
  var privateField = "can't touch this";
  return 
    play: function() 
      console.log(privateField);
    
  

为什么这么好?

现在您只将世界上的global 命名空间成员增加了一个,但该成员包含任意数量的项目。 您的应用程序与其他命名空间发生冲突的可能性要小得多 这是一种模式,other frameworks expect you to use it 可以正确地与它们交互。在那个参考中,jQuery 是一个浏览器插件,但你可以use it with node and therefore your app,所以库交互策略声明就是一个完美的例子。 这是一种模式,如果我们都遵循它我们我们的程序都更有可能相处

当您阅读Crockford reference 以及我在开头提到的Croll reference(直接分配部分)时,您会明白为什么它看起来如此复杂,而不仅仅是做:sound.play = function() ... - 易于维护,重构命名空间等等只是原因之一。

总结

总结:

我可以创建全局变量吗?是的,很简单,在声明前省略var关键字。 我应该创建全局变量吗?您应该使用 node 和 express 隐式支持的模块模式 为什么要创建全局变量?如果是用于配置,请使用配置命名空间(例如How to store Node.js deployment settings/configuration files?)

【讨论】:

很好的答案-尽管仅供参考,您对命名空间/匿名函数与其余答案之间的关系的意图并不完全清楚。我的意思是你没有明确定义什么时候应该使用模块模式(使用匿名函数):而不是全局变量?或者在使用require的时候?或者在使用 require 制作全局变量时?【参考方案2】:

你可以:

global.name = function();

但您确实应该避免使用全局变量,即使可以使用它们。

【讨论】:

我觉得这让人们感到困惑。你不需要'global'来创建全局变量,你只需要省略 var 关键字。我投了反对票。如果您更改此设置,将重新投票。我同意使用像“全球”这样的约定可能是更好的做法,但这需要提及。 如果省略“var”,您的代码将在 scrit 模式下失败“'use strict';”

以上是关于express.js 中的全局函数?的主要内容,如果未能解决你的问题,请参考以下文章

nodejs 怎么全局安装express

设置全局安装后未找到Express命令

如何判断函数中的变量是全局变量还是局部变量

更改函数JS中的全局变量[重复]

全局变量与参数

从导入模块中的函数访问全局变量