我正在开发一个需要在客户端和服务器端工作的JS应用程序(在浏览器和Node.js中的Javascript中),我希望能够重用部分的用于双方的代码。
我发现window
是一个只能在浏览器上访问的变量,而global
在节点中是可访问的,因此我可以检测代码在哪个环境中执行(假设没有脚本声明window
1}}变量)
他们是两个问题。
我应该如何检测代码在哪个浏览器中运行。例如,这段代码是否正常。 (此代码是内联的,意味着它被一些全局代码包围,可以在两种环境中重用)
if window?
totalPath= "../examples/#{path}"
else
totalPath= "../../examples/#{path}"
如何在两种环境中使用全局变量?现在,我正在做以下事情,但这确实感觉不对。
if window?
window.DocUtils = {}
window.docX = []
window.docXData= []
else
global.DocUtils= {}
global.docX = []
global.docXData = []
答案 0 :(得分:69)
注意:这个问题有两个部分,但因为标题是"环境检测:node.js或浏览器" - 我将首先介绍这一部分,因为我猜很多人都会来这里寻找答案。一个单独的问题可能是有序的。
在JavaScript中,变量可以由内部作用域重新定义,因此假设环境没有创建名为process的变量,global或window可能很容易失败,例如,如果使用node.js jsdom模块,{{3} }
var window = doc.defaultView;
之后根据window
变量的存在来检测环境会在该范围内运行的任何模块系统地失败。使用相同的逻辑,任何基于浏览器的代码都可以轻松覆盖global
或process
,因为它们不是该环境中的保留变量。
幸运的是,有一种方法需要全局范围并测试它是什么 - 如果使用new Function()
构造函数创建新函数,this
的执行范围将绑定到全局范围并且您可以将全局范围直接与预期值进行比较。 *)
所以创建一个函数检查全局范围是否为" 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将确保如果未定义变量,则返回false
。
isNode()
还可以比较this.process.title==="node"
或node.js中找到的其他全局范围变量(如果愿意的话),但在实践中与全局范围进行比较应该足够了。
注意 :建议不要检测运行环境。但是,它在特定环境中很有用,例如开发和测试环境,它具有全局范围的某些已知特征。
现在 - 答案的第二部分。在环境检测完成后,您可以选择要使用哪个基于环境的策略(如果有)来绑定您的变量&# 34;全球"到您的申请。
在我看来,推荐的策略是使用单例模式绑定类中的设置。 SO中已有一个很好的替代品清单
所以,如果你不需要"全球"变量,您根本不需要环境检测,只需使用单例模式定义一个模块,该模块将为您存储值。好吧,有人可以说模块本身是一个全局变量,它实际上是在JavaScript中,但至少在理论上它看起来更简洁一些。
*)Simplest/Cleanest way to implement singleton in JavaScript?
注意:使用Function构造函数创建的函数不会创建 封闭他们的创作背景;他们总是在 全球范围。运行它们时,它们只能访问 他们自己的局部变量和全局变量,而不是范围内的变量 其中调用了Function构造函数。
答案 1 :(得分:12)
由于显然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;
}
}
}
多级条件是在搜索未定义变量时避免错误,因为某些浏览器限制。
参考:https://nodejs.org/api/process.html#process_process_versions
答案 2 :(得分:7)
您可以根据情况附加到变量窗口或全局。虽然它不是推荐的制作多平台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';
}
所以我的想法是你的主应用程序逻辑将完全相同并将使用相同的对象,只有全局对象必须根据环境进行更改。这使得您的应用程序在平台方面更加便携和灵活。
答案 3 :(得分:2)
只有一个npm包,它可以在客户端和服务器端使用。
你可以这样使用
if (isBrowser) {
// do browser only stuff
}
if (isNode) {
// do node.js only stuff
}
免责声明:我是此套餐的作者:)
答案 4 :(得分:1)
我知道这是一个(已有1.5年的)老问题的较晚答案,但是为什么不复制jQuery的源代码?
if (typeof module === "object" && typeof module.exports === "object") {
// node
}
if (typeof window !== "undefined" && typeof window.document !== "undefined") {
// browser
}
祝你好运。
答案 5 :(得分:1)
<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>
答案 6 :(得分:0)
我并不完全熟悉Node环境及其所有情况,例如使用Babel或WebPack时。但是,如果您的代码在浏览器和Node控制台中运行,则这是一种方法:
if (this.window) {
// inside browser
} else {
// inside Node
}
答案 7 :(得分:0)
来自pdf.js的简单条件
第二个条件变体过程。 constructor.name ==='过程'
src / shared / is_node.js :
file.eof()
答案 8 :(得分:0)
无论范围如何,这似乎都能很好地工作,除非您已命名其他内容 window
const isBrowser = () => typeof window !== `undefined`
if (isBrowser())
console.log(`is browser`)
else
console.log(`is node.js`)