关于最外层this的一部分笔记

zsx in 记录整理 / 3 / 3819

嘛,除夕之日,发了个无聊的项目: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里调用。如图:

QQ截图20150218153620.png

另外,在ASP JScript里,这个做法是无效的(WScript下有效,我也不知道为毛)。必须这样(@evio指出):

with (this) {

    (function () {

        var xxxx;

        someThing = xxxx;

    });

}


Why?

首先知道,在浏览器里执行的时候,最外层this即为window。

再看ASP JScript,由Visual Studio可得,此处的this(对象无法被展开,不知道原因)即为最外层。但是这个最外层没有任何对象可以访问,所以

QQ截图20150218154728.png

我们用如下代码可推得,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在逗我。

如果本文对你有帮助,你可以用支付宝支持一下:

Alipay QrCode
反应bug:如图,之前的评论丢失(?)了(之前还有文字(大概):评论发生错误,请联系客服)所以这是一个第三方接口,吗?之前的问题:__WINDOWS_和_WIN32的区别是???Q:576487480E:576487480@qq.com
zsx at 2017/2/11[回复]
你的评论是写在另一篇文章下的……
at 2015/2/26[回复]
支持一下