注意:这个问题有两部分,但因为标题是“环境检测:node.js 或浏览器” - 我会先进入这一部分,因为我想很多人都来这里寻找答案。一个单独的问题可能是有序的。
在 JavaScript 中变量可以通过内部作用域重新定义,因此假设环境没有创建名为 process、global 或 window 的变量很容易失败,例如如果使用 node.js jsdom module,API 用法示例有
var window = doc.defaultView;
之后,根据window
变量的存在检测环境将系统地失败,任何在该范围内运行的module都会失败。使用相同的逻辑,任何基于浏览器的代码都可以轻松覆盖global
或process
,因为它们不是该环境中的保留变量。
幸运的是,有一种方法可以要求全局范围并测试它是什么——如果您使用new Function()
构造函数创建一个新函数,则 的执行范围将this
绑定到全局范围,您可以直接将全局范围与预期值进行比较。*)
因此,要创建一个函数检查全局范围是否为“窗口”将是
var isBrowser=new Function("try {return this===window;}catch(e){ return false;}");
// tests if global scope is bound to window
if(isBrowser()) console.log("running under browser");
并且测试全局范围是否绑定到“全局”的函数将是
var isNode=new Function("try {return this===global;}catch(e){return false;}");
// tests if global scope is bound to "global"
if(isNode()) console.log("running under node.js");
try... catch -part 将确保如果未定义变量,false
则返回。
如果isNode()
愿意,也可以比较this.process.title==="node"
或在 node.js 中找到的其他一些全局范围变量,但在实践中与全局比较应该足够了。
http://jsfiddle.net/p6yedbqk/
注意:不建议检测运行环境。但是,它在特定环境中可能很有用,例如开发和测试环境具有一些全局范围的已知特征。
现在 - 答案的第二部分。环境检测完成后,您可以选择要使用的基于环境的策略(如果有)将“全局”变量绑定到您的应用程序。
在我看来,这里推荐的策略是使用单例模式将您的设置绑定到一个类中。SO中已经有一个很好的替代方案列表
在 JavaScript 中实现单例的最简单/最干净的方法
因此,如果您不需要“全局”变量,并且根本不需要环境检测,则可能会发现,只需使用单例模式定义一个module,该module将为您存储值。好吧,有人可能会争辩说module本身是一个全局变量,在 JavaScript 中它实际上是一个全局变量,但至少在理论上它看起来更简洁一些。
*) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
注意:使用 Function 构造函数创建的函数不会为其创建上下文创建闭包;它们总是在全局范围内创建。运行它们时,它们只能访问自己的局部变量和全局变量,而不能访问调用 Function 构造函数的范围内的变量。