嘛,除夕之日,发了个无聊的项目:http://zsxsoft.github.io/useragent.js。这期间比较麻烦的是怎么让它既能在Node.JS中使用,又能在浏览器各类框架中调用。
话不多说,直接上代码:
(function(root) {
var someThing = {};
// Node
if (typeof module !== 'undefined' && module.exports) {
module.exports = someThing;
}
// AMD
else if (typeof define !== 'undefined' && define.amd) {
define([], function() {
return someThing;
});
}
// CMD
else if (typeof define !== 'undefined' && define.cmd) {
define([], function(require, exports, module) {
module.exports = someThing;
});
} else {
root.someThing = function() {};
someThing.prototype.xxx = someThing.xxx;
}
})(this);
这样子,在未引用任何模块化框架的情况下,便可把回退到window之下,把它当一个全局变量调用。值得注意的是,这里如果只留
(function(root) {
root.someThing = function() {};
})(this);
的话,只能在浏览器中使用,而不能在NodeJS里调用。如图:
另外,在ASP JScript里,这个做法是无效的(WScript下有效,我也不知道为毛)。必须这样(@evio指出):
with (this) {
(function () {
var xxxx;
someThing = xxxx;
});
}
Why?
首先知道,在浏览器里执行的时候,最外层this即为window。
再看ASP JScript,由Visual Studio可得,此处的this(对象无法被展开,不知道原因)即为最外层。但是这个最外层没有任何对象可以访问,所以
我们用如下代码可推得,JScript下的最外层必须先用
var xx;
定义变量,然后才可以进行读写等访问。至于with在这里是怎么实现的,call也改变了上下文为什么会出错,我只能说怪我咯?
<script language="javascript" runat="server">
try {
(function () {
var a = "c";
}).call(this);
if (a == "c") Response.Write("PASS 1<br/>");
} catch (e) {
Response.Write("ERROR 1: " + e.message + "<br/>");
}
// ERROR 1: 'a' 未定义
try {
(function (root) {
root.a = "c";
})(this);
if (a == "c") Response.Write("PASS 2<br/>");
} catch (e) {
Response.Write("ERROR 2: " + e.message + "<br/>");
}
// ERROR 2: 对象不支持此属性或方法
try {
this.a = "c";
if (a == "c") Response.Write("PASS 3<br/>");
} catch (e) {
Response.Write("ERROR 3: " + e.message + "<br/>");
}
// ERROR 3: 对象不支持此属性或方法
try {
var c = "b";
this.c = "c";
if (c == "c") Response.Write("PASS 4<br/>");
} catch (e) {
Response.Write("ERROR 4: " + e.message + "<br/>");
}
// PASS 4
try {
var f = "a";
(function (root) {
root.f = "c";
})(this);
if (f == "c") Response.Write("PASS 5<br/>");
} catch (e) {
Response.Write("ERROR 5: " + e.message + "<br/>");
}
// PASS 5
</script>
再返回去看Node。Node下最外层root不是window(因为压根没有),是global。
由前面的图得知,丫最外层的this根本就是个空Object而不是global。那这里的this是什么?
翻Node.JS代码,lib/module.js里,
Module.prototype._compile = function(content, filename) {
//...
return compiledWrapper.apply(self.exports, args);
}
根据实验,也可得知,这里的this指向的是exports这玩意,即外部接口。
嗯,所以,Node里用相同代码,只会在模块内部暴露一个给外界的接口……
也就是说,以下语句基本等价(引用啥的就略过吧)……
module.exports.someThing = someThing;
this.someThing = someThing;
module.exports = someThing;
this = someThing;
糊你熊脸……
最后结论:
浏览器中,最外层this == window,全局变量在window下。
ASP JScript中,最外层this就是全局,没有可访问的方式,在未用var定义变量前不可以直接用this.xx修改值。
Node中,能接触到的最外层this == exports,全局变量在global下。
WScript中,最外层this不知道怎么访问,可以直接修改值。
你TMD在逗我。