问与答 javascript-环境检测:node.js或浏览

dillon · 2020-03-07 13:26:31 · 热度: 81

我正在开发一个需要同时在客户端和服务器端工作的JS应用程序(在浏览器中的Javascript和Node.js中),并且我希望能够重用部分代码。 用于双方。

我发现if window? window.DocUtils = {} window.docX = [] window.docXData= [] else global.DocUtils= {} global.docX = [] global.docXData = [] 是只能在浏览器上访问的变量,而节点上的global是变量,因此我可以检测到代码在哪个环境中执行(假设没有脚本声明window变量)

他们是两个问题。

  1. 我应该如何检测代码在哪个浏览器中运行。 例如,此代码是否可以。 (此代码是内联代码,这意味着它被一些全局代码包围,可在两种环境中重复使用)

    if window?
        window.DocUtils = {}
        window.docX = []
        window.docXData= []
    else
        global.DocUtils= {}
        global.docX = []
        global.docXData = []
    
  2. 如何在两种环境中使用全局变量? 现在,我正在执行以下操作,但这确实感觉不对。

    if window?
        window.DocUtils = {}
        window.docX = []
        window.docXData= []
    else
        global.DocUtils= {}
        global.docX = []
        global.docXData = []
    

猜你喜欢:
共收到 5 条回复
orville #1 · 2020-03-07 13:26:31

注意:这个问题有两个部分,但是因为标题是“环境检测:node.js或浏览器”-我将首先进入这一部分,因为我想很多人都会来这里寻求答案。 可能有一个单独的问题。

在JavaScript中,变量可以由内部作用域重新定义,因此,假设环境尚未创建名为process,global或window的变量,则很容易失败,例如,如果使用的是node.js jsdom模块,则API使用示例将

var window = doc.defaultView;

之后,基于isNode()变量的存在来检测环境将被在该范围内运行的任何模块系统地失败。 使用相同的逻辑,任何基于浏览器的代码都可以轻松覆盖this.process.title==="node"process,因为它们不是该环境中的保留变量。

幸运的是,有一种方法需要全局范围并测试它的含义-如果使用2755725326574683683136构造函数创建新函数,则this.process.title==="node"的执行范围将绑定到全局范围,并且可以将全局范围直接与期望值进行比较 。 *)

因此,要创建一个函数,请检查全局范围是否为“ window”

var isBrowser=new Function("try {return this===window;}catch(e){ return false;}");

// tests if global scope is binded 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 binded to "global"
if(isNode()) console.log("running under node.js");

try ... catch -part将确保如果未定义变量,则返回isNode()

如果愿意,isNode()也可以比较this.process.title==="node"或在node.js中找到的某些其他全局范围变量,但在实际中与全局比较就足够了。

[HTTP://JS fiddle.net/怕6也多半情况/]

注意:不建议检测运行环境。 但是,它在特定的环境(例如具有全球范围内某些已知特征的开发和测试环境)中很有用。

现在-答案的第二部分。 在完成环境检测之后,您可以选择要使用的基于环境的策略(如果有)将“全局”变量绑定到应用程序。

我认为,这里推荐的策略是使用单例模式将您的设置绑定到类中。 SO中已经有很多替代方案

在JavaScript中实现单例的最简单/最简洁的方法?

因此,事实证明,如果您不需要“全局”变量,并且根本不需要环境检测,只需使用单例模式定义一个模块即可为您存储值。 好的,可以说模块本身是一个全局变量,实际上在JavaScript中是全局变量,但至少在理论上,它看起来更干净一些。

*) [HTTPS://developer.Mozilla.org/恩-US/docs/Web/JavaScript/reference/global_objects/function]

注意:使用Function构造函数创建的函数不会创建   封闭其创作环境; 他们总是在   全球范围。 运行它们时,他们将只能访问   他们自己的局部变量和全局变量,而不是范围中的变量   在其中调用了Function构造函数。

beau #2 · 2020-03-07 13:26:33

由于显然Node.js可以同时拥有这两个(w / NW.js?),所以我的个人方式是通过检测node对象中是否存在node条目。

var isNode = false;    
if (typeof process === 'object') {
  if (typeof process.versions === 'object') {
    if (typeof process.versions.node !== 'undefined') {
      isNode = true;
    }
  }
}

多级条件是为了避免由于某些浏览器的限制而在搜索未定义的变量时出错。

参考:[https://nodejs.org/api/process.html#process_process_versions]

salvador #3 · 2020-03-07 13:26:34

您可以根据情况附加到变量窗口或全局窗口。 尽管不是推荐的制作多平台JS应用程序的方法:

var app = window ? window : global;

最好使用全局变量,该变量将在应用程序逻辑上使用,但由基于不同平台的部分组成。 就像是:

var app = {
    env: '',
    agent: ''
};

if (window) {
    app.env = 'browser';
    app.agent = navigator.userAgent;
} else if (process) {
    app.env = 'node';
}

因此,想法是您的主要应用程序逻辑将完全相同,并且将使用相同的对象,只是必须根据环境更改全局对象。 就平台而言,这使您的应用程序更具可移植性和灵活性。

barret #4 · 2020-03-07 13:26:36

为此有一个npm软件包,它可以在客户端和服务器端使用。

浏览器或节点

你可以这样使用

if (isBrowser) {
  // do browser only stuff
}

if (isNode) {
  // do node.js only stuff
}

免责声明:我是这个软件包的作者:)

ingemar #5 · 2020-03-07 13:26:38

我知道这是一个(1.5年)老问题的较晚答案,但是为什么不复制jQuery的源代码呢?

if (typeof module === "object" && typeof module.exports === "object") {
  // node
}

if (typeof window !== "undefined" && typeof window.document !== "undefined") {
  // browser
}

祝好运。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册