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

Javascript 环境检测:node.js或浏览器,javascript,node.js,coffeescript,browser-detection,Javascript,Node.js,Coffeescript,Browser Detection,我正在开发一个JS应用程序,它需要同时在客户端和服务器端工作(在浏览器和Node.JS中使用Javascript),我希望能够重用用于客户端和服务器端的部分代码 我发现window是一个只能在浏览器上访问的变量,而global在节点中,因此我可以检测代码在哪个环境中执行(假设没有脚本声明window变量) 这是两个问题 我应该如何检测代码在哪个浏览器中运行。例如,此代码是否正确。(此代码是内联的,这意味着它被一些全局代码包围,可在两种环境中重用) 如何为这两种环境使用全局变量?现在,我正在做下

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

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

这是两个问题

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

  • 如何为这两种环境使用全局变量?现在,我正在做下面的事情,但这感觉真的不对

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

  • 您可以根据情况附加到变量窗口或全局。虽然这不是制作多平台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';
    }
    
    因此,您的主要应用程序逻辑将是完全相同的,并且将使用相同的对象,只是全局对象必须根据环境进行更改。这使您的应用程序在平台方面更具可移植性和灵活性。

    注意:这个问题有两个部分,但因为标题是“环境检测:node.js或browser”-我将首先讨论这一部分,因为我想很多人会来这里寻找答案。另一个问题可能是合适的

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

    在此之后,基于
    窗口
    变量的存在来检测环境将被在该范围内运行的任何模块系统性地失败。使用相同的逻辑,任何基于浏览器的代码都可以轻松覆盖
    全局
    过程
    ,因为它们在该环境中不是保留变量

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

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

    测试全局sope是否绑定到“全局”的函数是

    试一试。。。catch-part将确保如果未定义变量,则返回
    false

    isNode()
    也可以比较
    this.process.title==“node”
    或node.js中的其他一些全局范围变量(如果愿意),但在实践中,与全局范围变量进行比较就足够了

    注意:不建议检测运行环境。然而,它在特定的环境中是有用的,比如开发和测试环境,它具有一些全局范围的已知特性

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

    在我看来,这里推荐的策略是使用单例模式在类中绑定设置。有一个很好的备选方案清单已经在SO中列出

    因此,如果您不需要“全局”变量,并且根本不需要环境检测,那么可以使用singleton模式定义一个模块,该模块将为您存储值。好的,我们可以说模块本身是一个全局变量,在JavaScript中它实际上是一个全局变量,但至少在理论上它看起来更干净一点

    *)

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


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

    var isNode = false;    
    if (typeof process === 'object') {
      if (typeof process.versions === 'object') {
        if (typeof process.versions.node !== 'undefined') {
          isNode = true;
        }
      }
    }
    
    多级条件是为了避免由于某些浏览器限制而搜索未定义的变量时出错


    参考资料:

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

    你可以这样使用它

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

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

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

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

    祝你好运。

    我并不完全熟悉节点环境及其所有情况,例如使用Babel或WebPack时。但是,如果您的代码在浏览器中运行,而不是在节点控制台中运行,则这是一种方法:

    if (this.window) {
      // inside browser
    
    } else {
      // inside Node
    
    }
    
    
    /*
    在浏览器、deno、nodejs中检测全局/窗口/自身
    包括未定义“this”的地方
    */
    const self=new函数('returnthis')();//小心,功能就像评估,小心使用
    控制台日志(
    (self.window&“window”| self.global&“global”),
    self.toString().slice('[object'.length,-1).toLowerCase()
    );
    /*
    浏览器:窗口
    nodejs:全球
    窗口对象
    */
    
    pdf.js中的简单条件

    第二个条件变量进程。constructor.name==='process'

    src/shared/是_node.js

    /* Copyright 2018 Mozilla Foundation
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *     http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    /* globals process */
    
    // NW.js / Electron is a browser context, but copies some Node.js objects; see
    // http://docs.nwjs.io/en/latest/For%20Users/Advanced/JavaScript%20Contexts%20in%20NW.js/#access-nodejs-and-nwjs-api-in-browser-context
    // https://www.electronjs.org/docs/api/process#processversionselectron-readonly
    // https://www.electronjs.org/docs/api/process#processtype-readonly
    const isNodeJS =
      typeof process === "object" &&
      process + "" === "[object process]" &&
      !process.versions.nw &&
      !(process.versions.electron && process.type && process.type !== "browser");
    
    export { isNodeJS }; 
    

    无论范围如何,这似乎都能很好地工作,除非
    if (isBrowser) {
      // do browser only stuff
    }
    
    if (isNode) {
      // do node.js only stuff
    }
    
    if (typeof module === "object" && typeof module.exports === "object") {
      // node
    }
    
    if (typeof window !== "undefined" && typeof window.document !== "undefined") {
      // browser
    }
    
    if (this.window) {
      // inside browser
    
    } else {
      // inside Node
    
    }
    
    <script type=module>
    /*
    detect global/window/self in browser, deno, nodejs
    including where 'this' is undefined
    */
    const self = new Function('return this')(); // be careful, Function is like eval, use with caution
    console.log( 
        (self.window && "window" || self.global && 'global'),
        self.toString().slice('[object '.length, -1).toLowerCase()
    );
    /*
    browser: window window
    nodejs: global global
    deno: window object
    */
    </script>
    
    /* Copyright 2018 Mozilla Foundation
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *     http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    /* globals process */
    
    // NW.js / Electron is a browser context, but copies some Node.js objects; see
    // http://docs.nwjs.io/en/latest/For%20Users/Advanced/JavaScript%20Contexts%20in%20NW.js/#access-nodejs-and-nwjs-api-in-browser-context
    // https://www.electronjs.org/docs/api/process#processversionselectron-readonly
    // https://www.electronjs.org/docs/api/process#processtype-readonly
    const isNodeJS =
      typeof process === "object" &&
      process + "" === "[object process]" &&
      !process.versions.nw &&
      !(process.versions.electron && process.type && process.type !== "browser");
    
    export { isNodeJS };