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