环境检测:node.js或浏览器

edi*_*999 48 javascript browser-detection node.js coffeescript

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

我发现这window是一个只能在浏览器和global节点上访问的变量,所以我可以检测代码在哪个环境中执行(假设没有脚本声明window变量)

他们是两个问题.

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

    if window?
        totalPath= "../examples/#{path}"
    else
        totalPath= "../../examples/#{path}"
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如何在两种环境中使用全局变量?现在,我正在做以下事情,但这确实感觉不对.

    if window?
        window.DocUtils = {}
        window.docX = []
        window.docXData= []
    else
        global.DocUtils= {}
        global.docX = []
        global.docXData = []
    
    Run Code Online (Sandbox Code Playgroud)

Ter*_*nen 76

注意:这个问题有两个部分,但由于标题是"环境检测:node.js或浏览器" - 我将首先介绍这一部分,因为我想很多人都来这里寻找答案.一个单独的问题可能是有序的.

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

var window = doc.defaultView;
Run Code Online (Sandbox Code Playgroud)

之后,根据window变量的存在检测环境会在该范围内运行的任何模块系统地失败.使用相同的逻辑,任何基于浏览器的代码都可以轻松覆盖,global或者process因为它们不是该环境中的保留变量.

幸运的是,有一种方法需要全局范围并测试它是什么 - 如果使用new Function()构造函数创建新函数,则执行范围this绑定到全局范围,您可以将全局范围直接与期望值进行比较.*)

因此,要创建一个函数,请检查全局范围是否为"窗口"

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");
Run Code Online (Sandbox Code Playgroud)

并且测试全球sope是否被绑定到"全球"的功能

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");
Run Code Online (Sandbox Code Playgroud)

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

isNode()还可以比较this.process.title==="node",或者如果你会发现里面其他一些全球范围内变量的Node.js,但相较于全球应该在实践中是不够的.

http://jsfiddle.net/p6yedbqk/

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

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

在我看来,这里建议的策略是使用单例模式来绑定类中的设置.SO中已有很多替代品

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

因此,如果您不需要"全局"变量,并且根本不需要环境检测,则可能会使用单例模式来定义模块,该模块将为您存储值.好吧,有人可以说模块本身是一个全局变量,它实际上是在JavaScript中,但至少在理论上它看起来更简洁一些.

*)https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function

注意:使用Function构造函数创建的函数不会为其创建上下文创建闭包; 它们总是在全球范围内创建.运行它们时,它们只能访问自己的局部变量和全局变量,而不能访问调用Function构造函数的范围.

  • 嗨,感谢您提供此解决方案,我尝试了许多事情,但是这一工作非常完美,所以我使用此解决方案发布了一个npm软件包,希望您不要介意...查看https://www.npmjs。 com / package / detect-is-node (2认同)
  • 没有例外:`(function(){return(typeof window!=='undefined')&&(this === window);}).call(undefined);` (2认同)

Dan*_* B. 15

由于显然Node.js可以同时具有两个(w/NW.js?),我的个人方法是检测node条目是否存在于process.versions对象中.

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

多级条件是由于某些浏览器限制而在搜索未定义变量时避免错误.

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

  • 在现代语法中: `const isNode = typeof process !== "undefined" && process?.versions?.node;` (4认同)
  • 单行代码:`function isNodejs(){返回typeof“ process”!==“ undefined” && process && process.versions && process.versions.node; }` (2认同)

Din*_*yan 10

有一个专门用于此的 npm 包,它可以在客户端和服务器端使用。

浏览器或节点

你可以这样使用

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

if (isNode) {
  // do node.js only stuff
}
Run Code Online (Sandbox Code Playgroud)

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


Log*_*nch 9

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

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

if (typeof window !== "undefined" && typeof window.document !== "undefined") {
  // browser
}
Run Code Online (Sandbox Code Playgroud)

祝你好运。


mok*_*oka 7

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

var app = window ? window : global;
Run Code Online (Sandbox Code Playgroud)

拥有全局变量会更好,它将用于应用程序逻辑,但将由基于不同平台的部分组成.就像是:

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

if (window) {
    app.env = 'browser';
    app.agent = navigator.userAgent;
} else if (process) {
    app.env = 'node';
}
Run Code Online (Sandbox Code Playgroud)

所以我的想法是你的主应用程序逻辑将完全相同并将使用相同的对象,只有全局对象必须根据环境进行更改.这使得您的应用程序在平台方面更加便携和灵活.

  • 在节点 `var app = window ? window : global;` 产生 `Thrown: ReferenceError: window is not Defined`。你测试过它在节点中工作吗?(使用的版本为“v11.15.0”) (4认同)

小智 5

无论范围如何,这似乎都能很好地工作,除非您指定了其他名称window

const isBrowser = () => typeof window !== `undefined`

if (isBrowser())
  console.log(`is browser`)
else
  console.log(`is node.js`)
Run Code Online (Sandbox Code Playgroud)