【发布时间】:2013-05-23 05:35:24
【问题描述】:
如何在 express.js 中定义一个全局函数,没有require 我可以调用它
【问题讨论】:
-
为什么不想用这个函数创建模块?
如何在 express.js 中定义一个全局函数,没有require 我可以调用它
【问题讨论】:
“如何”很简单:
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。在下面的详细部分中,您将看到使用全局变量会很快陷入困境,它们应该真正被视为推动您走向依赖注入和/或命名空间和模块的东西。
这里有一个很好的规则:如果您将其上传到网络服务器,或与其他人共享,请不要使用全局变量。
global 在微小的“星期六下午”应用程序in node.js with express.js 中是允许的,但如果它们被采用到生产环境中,往往会在以后引起问题。因此:
exports 是最佳实践。 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”中公开了这种全局命名空间污染。总结:
例子:
ANDYBROWNSONICSUITE.BoomBox.SoundModule = function () {
var privateField = "can't touch this";
return {
play: function() {
console.log(privateField);
}
}
}
global 命名空间成员增加了一个,但该成员包含任意数量的项目。 当您阅读Crockford reference 以及我在开头提到的Croll reference(直接分配部分)时,您会明白为什么它看起来如此复杂,而不仅仅是做:sound.play = function() { ... } - 易于维护,重构命名空间等等只是原因之一。
总结:
var关键字。【讨论】:
你可以:
global.name = function(){};
但您确实应该避免使用全局变量,即使可以使用它们。
【讨论】: