环境检测:node.js 或浏览器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17575790/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Environment detection: node.js or browser
提问by edi9999
I'm developping a JS-app that needs to work both on the client side and the server side (in Javascript on a browser and in Node.js), and I would like to be able to reuse the parts of the code that are used for both sides.
我正在开发一个 JS 应用程序,它需要在客户端和服务器端工作(在浏览器上的 Javascript 和 Node.js 中),我希望能够重用代码的一部分用于双方。
I have found out that windowwas a variable only accessible on Browsers, and globalin node, so I can detect in which environment the code is executing (assuming that no script declares the windowvariable)
我发现这window是一个只能在浏览器和global节点中访问的变量,所以我可以检测代码在哪个环境中执行(假设没有脚本声明window变量)
They are two problems.
他们是两个问题。
How should I detect in which browser the code is running. For example, is this code OK. (This code is inline, meaning that it is surrounded by some global code, reused for both environments)
if window? totalPath= "../examples/#{path}" else totalPath= "../../examples/#{path}"How can I use global variables for both environments ? Now, I'm doing the following, but this really doesn't feel right.
if window? window.DocUtils = {} window.docX = [] window.docXData= [] else global.DocUtils= {} global.docX = [] global.docXData = []
我应该如何检测代码在哪个浏览器中运行。例如,此代码是否正常。(这段代码是内联的,意味着它被一些全局代码包围,在两种环境中重用)
if window? totalPath= "../examples/#{path}" else totalPath= "../../examples/#{path}"如何在两种环境中使用全局变量?现在,我正在执行以下操作,但这确实感觉不对。
if window? window.DocUtils = {} window.docX = [] window.docXData= [] else global.DocUtils= {} global.docX = [] global.docXData = []
回答by Tero Tolonen
NOTE: This question had two parts, but because the title was "Environment detection: node.js or browser" - I will get to this part first, because I guess many people are coming here to look for an answer to that. A separate question might be in order.
注意:这个问题有两个部分,但因为标题是“环境检测:node.js 或浏览器” - 我将首先进入这一部分,因为我想很多人都来这里寻找答案。一个单独的问题可能是有序的。
In JavaScript variables can be redefined by the inner scopes, thus assuming that environment has not created variables named as process, global or window could easily fail, for example if one is using node.js jsdom module, the API usage example has
在 JavaScript 中变量可以通过内部作用域重新定义,因此假设环境没有创建名为 process、global 或 window 的变量很容易失败,例如如果使用 node.js jsdom 模块,API 用法示例有
var window = doc.defaultView;
After which detecting the environment based on the existence of windowvariable would systematically fail by any module running under that scope. With the same logic any browser based code could easily overwrite globalor process, because they are not reserved variables in that environment.
之后,window在该范围内运行的任何模块都会系统地失败,基于变量的存在来检测环境。使用相同的逻辑,任何基于浏览器的代码都可以轻松覆盖global或process,因为它们不是该环境中的保留变量。
Fortunately there is a way of requiring the global scope and testing what it is - if you create a new function using a new Function()constructor, the execution scope of thisis binded to the global scope and you can compare the global scope directly to the expected value. *)
幸运的是,有一种方法可以要求全局范围并测试它是什么——如果您使用new Function()构造函数创建一个新函数,则 的执行范围将this绑定到全局范围,您可以直接将全局范围与预期值进行比较。*)
So to create a function check if the global scope is "window" would be
因此,要创建一个函数检查全局范围是否为“窗口”将是
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");
And function to test if global sope is binded to "global" would be
测试全局 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");
the try... catch -part will makes sure that if variable is not defined, falseis returned.
try... catch -part 将确保如果未定义变量,false则返回。
The isNode()could also compare this.process.title==="node"or some other global scope variable found inside node.js if you will, but comparing to the global should be enough in practice.
如果isNode()愿意,也可以比较this.process.title==="node"或在 node.js 中找到的其他一些全局范围变量,但在实践中与全局比较应该足够了。
NOTE: detecting the running environment is not recommended. However, it can be useful in a specifiic environment, like development and testing environment which has some known characteristics for the global scope.
注意:不建议检测运行环境。但是,它在特定环境中很有用,例如开发和测试环境,它具有一些全局范围的已知特征。
Now - the second part of the answer.after the environment detection has been done, you can select which environment based strategy you want to use (if any) to bind your variable which are "global" to your application.
现在 - 答案的第二部分。环境检测完成后,您可以选择要使用的基于环境的策略(如果有)将“全局”变量绑定到您的应用程序。
The recommended strategy here, in my opinion, would be to use a singleton pattern to bind your settings inside a class. There is a good list of alternatives already in SO
在我看来,这里推荐的策略是使用单例模式将您的设置绑定到一个类中。SO中已经有一个很好的替代方案列表
Simplest/Cleanest way to implement singleton in JavaScript?
在 JavaScript 中实现单例的最简单/最干净的方法?
So, it may turn out if you do not need a "global" variable, and you do not need the environment detection at all, just use the singleton pattern to defined a module, which will store the values for you. Ok, one can argue that the module itself is a global variable, which in JavaScript it actually is, but at least in theory it looks a bit cleaner way of doing it.
因此,如果您不需要“全局”变量,并且根本不需要环境检测,则可能会发现,只需使用单例模式定义一个模块,该模块将为您存储值。好吧,有人可能会争辩说模块本身是一个全局变量,在 JavaScript 中它实际上是一个全局变量,但至少在理论上它看起来更简洁一些。
*) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
*) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
Note: Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was called.
注意:使用 Function 构造函数创建的函数不会为其创建上下文创建闭包;它们总是在全局范围内创建。运行它们时,它们将只能访问自己的局部变量和全局变量,而不能访问调用 Function 构造函数的范围内的变量。
回答by Dan. B.
Since apparently Node.js could have both (w/ NW.js?), my personnal way to do it is by detecting if the nodeentry exists in process.versionsobject.
由于显然 Node.js 可以同时拥有两者(w/ NW.js?),我个人的做法是检测node条目是否存在于object.js中process.versions。
var isNode = false;
if (typeof process === 'object') {
if (typeof process.versions === 'object') {
if (typeof process.versions.node !== 'undefined') {
isNode = true;
}
}
}
The multilevel of conditions is to avoid errors while searching into an undefined variable due to some browsers limitations.
多级条件是为了避免由于某些浏览器的限制而在搜索未定义变量时出错。
Reference: https://nodejs.org/api/process.html#process_process_versions
参考:https: //nodejs.org/api/process.html#process_process_versions
回答by moka
You can attach to variable window or global - based on situation. Though it is not a recommended way of making multi-platform JS application:
您可以根据情况附加到可变窗口或全局。虽然它不是制作多平台 JS 应用程序的推荐方式:
var app = window ? window : global;
It is much better to have your global variable, that will be used over logic of application, but will be made of parts of based on different platforms. Something like:
拥有全局变量会更好,它将用于应用程序的逻辑,但将由基于不同平台的部分组成。就像是:
var app = {
env: '',
agent: ''
};
if (window) {
app.env = 'browser';
app.agent = navigator.userAgent;
} else if (process) {
app.env = 'node';
}
So the idea is that your main application logic will be absolutely the same and will use same object, only that global object have to be changed based on environment. That makes your application much more portable and flexible in terms of platforms.
所以这个想法是你的主要应用程序逻辑将完全相同并且将使用相同的对象,只有全局对象必须根据环境进行更改。这使您的应用程序在平台方面更加便携和灵活。
回答by Dinesh Pandiyan
There is an npm package just for this and it can be used both on client-side and server-side.
有一个专门用于此的 npm 包,它可以在客户端和服务器端使用。
You can use it this way
你可以这样使用
if (isBrowser) {
// do browser only stuff
}
if (isNode) {
// do node.js only stuff
}
Disclaimer: I am the author of this package :)
免责声明:我是这个包的作者:)
回答by LogicalBranch
I know this is a late answer to a (1.5 year) old question but why not copy jQuery's source code?
我知道这是一个(1.5 年)老问题的迟到答案,但为什么不复制jQuery的源代码?
if (typeof module === "object" && typeof module.exports === "object") {
// node
}
if (typeof window !== "undefined" && typeof window.document !== "undefined") {
// browser
}
Good luck.
祝你好运。
回答by jimmont
<script type=module>
/*
detect global/window/self in browser, deno, nodejs
including where 'this' is undefined
*/
const self = new Function('return this')();
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>
回答by nonopolarity
I am not totally familiar with the Node environment and all its situations such as when Babel or WebPack is being used. But this is one way if you have code that runs in the browser vs in the Node console:
我并不完全熟悉 Node 环境及其所有情况,例如使用 Babel 或 WebPack 时。但如果您的代码在浏览器和 Node 控制台中运行,这是一种方法:
if (this.window) {
// inside browser
} else {
// inside Node
}

