由eval(...) !== (1,eval)(...)引发的思考

先看一个例子
var x = 'outer';
(function() {
var x = 'inner';
eval('console.log("direct call: " + x)');
(1,eval)('console.log("indirect call: " + x)');
})();

答案是:
direct call: inner
indirect call: outer



eval('1+1')是直接eval调用,而(1,eval)('1+1')不是。由于后者不是直接调用,因此它是间接eval调用。
( 1 , eval ) ( '1+1' )
|____| |_____| |_____|
常量 操作符 标识符

|_________________________|
表达式

|______________________________|
主要表达式

|______________________________| |________|
成员表达式 参数

|________________________________________________|
调用表达式
在上面的例子里,很显然参数(调用括号)之前的哪部分不只是由“eval”标识符组成。这是一个完整的其他类型的表达式,由逗号操作符,数字常量,然后才是"eval"标识符组成。1,eval - 基于逗号操作符运行的方式-仍然执行一个标准的内置的eval函数,不过整个表达式不再是直接调用了。因此它是 间接eval调用。

(1, eval)('...')
(eval, eval)('...')
(1 ? eval : 0)('...')
(__ = eval)('...')
var e = eval; e('...')
(function(e) { e('...') })(eval)
(function(e) { return e })(eval)('...')
(function() { arguments[0]('...') })(eval)
this.eval('...')
this['eval']('...')
[eval][0]('...')
eval.call(this, '...')
eval('eval')('...')
依据ES5,所有这些都是间接调用,且 应当在全局范围内执行执行代码。你是否注意到ES5定义说明调用表达式的eval应当执行标准的、内置的函数?这意味着根据上下文内容eval('1+1')必定不是直接调用。仅仅当eval真正地(不是重写或者隐含地)引用了标准的、内置的函数的时候,调用才被认为是直接调用。
eval = (function(eval) {
return function(expr) {
return eval(expr);
};
})(eval);

eval('1+1'); // 它看前来像直接调用,不过实际上是间接调用。
// 这是因为`eval`解析为定制的函数,而不是标准的、内置的函数。


eval('...')
(eval)('...')
(((eval)))('...')
(function() { return eval('...') })()
eval('eval("...")')
(function(eval) { return eval('...'); })(eval)
with({ eval: eval }) eval('...')
with(window) eval('...')
看前来相当的直白,难道不是吗?
不过等一下,为什么认为(eval)('...')和(((eval)))('...')是直接调用呢?当然,它们并不遵守我们前面所建立的特性 - 调用表达式内部的成员表达式内的有"eval"标识符。这儿到底发生什么呢?难道是eval两边的括号让它成为间接调用的吗?

这个有点微妙的问题的答案就在ES5直接调用定义的第一段里 - 是这样一个事实:调用表达式里的 "eval"应当是引用,而不是值。在程序执行期间,eval('1+1')表达式里的eval只不过是一个引用,而且需要计算出一个值。一旦计算完成,这个值(最可能)是标准的、内置的函数对象。在前面已经分析的(1,eval)('1+1')间接调用里所发生的是(1,eval)表达式计算出一个值,而不是一个引用。由于它计算出的
不是引用,所以不能认为它是直接eval调用。
但是(eval)('1+1')又如何呢?

认为(eval)是直接调用的原因是因为(eval)表达式仍然计算出的是一个引用,不是一个值。((eval)),(((eval)))等也是同样的。这种情况的出现是因为成组操作符-"("和")"-不能计算自身的表达式。如果传递引用给成组操作符-"("和")"-它仍然计算出一个引用,而不是一个值。

eval(); // <-- 调用括号左边的表达式 — "eval" — 计算出一个引用
(eval)(); // <-- 调用括号左边的表达式 — "(eval)" — 计算出一个引用
(((eval)))(); // <-- 调用括号左边的表达式 — "(((eval)))" — 计算出一个引用
(1,eval)(); // <-- 调用括号左边的表达式 — "(1, eval)" — 计算出一个值
(eval = eval)(); // <-- 调用括号左边的表达式 — "(eval = eval)" — 计算出一个值
如ECMAScript所说,这是因为两个操作符 - (例子(1,eval)里的)逗号操作符和(例子(eval=eval)里的)等号操作符-对它的操作数执行了GetValue。因此,(1,eval)和(eval = eval)计算出一个值,而eval 和 (eval)计算出的是一个引用。

现在希望已经弄清楚了(eval)('...')和(function(eval){ retuan eval('...')})(eval)是直接eval调用,而(1,eval)('...')和this.eval('...')不是直接调用的原因。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
eval32 v3.2.6 Beta R1 ShellEval数学表达式动态解释计算扩展函数库 ========================================= 欢迎使用:ShellEval数学表达式动态解释计算扩展函数库。 当前最终发行版本:V3.2.6。最初作为一个实用的文本字符串解释器,可以帮助程序开发人员快 速地整合到自己的应用程序之中。随着版本的不断升级,功能也越发完善,现V3.2.6版本已包含字符串解释、数学计算、线性代数、动态编连等相关操作总计大约两百个导出接口函数,主要用于实现高级语言之间的动态解释计算与调用。 例如对MATLAB的不能实现的相关功能做了较大的扩充。关于V3.2.6以前各个旧版本的相关介绍在网上请自行下载。 ShellEvalV3.2.6不是对旧版本如EvalExprV1.4.4等的简单扩充,相反地,它在旧版本EvalExprV1.4.4 的基础上去掉了大部分与数值动态编连解释计算无关的函数,只保留了原先版本的主要核心算法,同时对核心算法的相应函数另外增加了一个在原函数同名函数的基础上加M 结尾的版本, 例tsEvalExpr 对应的函数是:tsEvalExprM。这类以M 结尾的函数提供了基于MatCom核心的矩阵运 算功能。虽然本函数库是基于MatCom Version 4.5.1开发而成的,但是使用它时并不需要用户安装拥有MatCom,只需要使用本函数库提供的相应接口即可实现。 众所周知,MatLab、MatCom等数学软件提供了大约上千个矩阵数值运算函数,但是对于表达式的动态解释执行却是不能够实现的。例如: eval(TM(“[1,2;3,4]”)); MatCom可以实现,但是其功能也仅限于此。如下最基本的调用: eval(TM(“sin([1,2;3,4])”)); 等皆不能实现。而MatLab 虽然可以利用计算引擎技术与DDE 动态数据交换技 术间接实现字符串表达式的动态解释执行,但是效率低下,更重要的是,它要求用户机器上必须安装有匹配版本的体积庞大的MatLab,实际软件发布时是难以保证的。 本函数库主要用于对MATLAB、MatCom、MATFOR等矩阵运算软件表达式动态解释执行的扩展,利用它可以实现非常复杂的表达式计算,无论在表达式类 型种类还是矩阵运算方面都远非网络上的其他一些表达式计算控件可比。 例如计算上式,如下: #include “eval32.h” ... ... tsInitialize(NULL,NULL,NULL); tsMatrix * vValue = tsAllocM(1); INT nRetFlag = tsEvalExprM(_T(“sin([1,2;3,4])”),vValue); if(nRetFlag >= 0){ tsDispM(vValue); }else{ _tprintf(_T(“Eval Failed\n”)); } tsFreeM(vValue); vValue = NULL; tsTerminate(); 可以看出利用本函数库完全无需依赖于MatLab、MatCom或者其他第三方软件,当然你也可以结合它们使用,使得程序开发更加得心应手。 利用本工具你甚至可以只用四条语句即可编制一个迷你版的MatLab 软件。 如下: #include “eval32.h” int main(int argc, char* argv[]) { tsInitialize(NULL,NULL,NULL); atexit((void (*)())(tsTerminate)); tsShellEvalM(); tsTerminate(); return 0; } 怎样?够简单吧!但是生成的迷你版MatLab功能可不容小觑。为了运行之,需要将以下动态链接支持库复制到程序搜索目录下: eval32.dll 、ago4501.dll、v4501v.dll。 关于本函数库内核及具体使用方法以下将有介绍。 本函数库仿照Math Tools公司的MatCom与Math Works公司的MatLab制作开发,相信对于数值计算与混合编程的各位程序爱好者与开发人员有所帮助。 ==========eval32 ver3.2.6 beta============= 在 V3.2.3 基础上进行了代码的重新规范化编写。此 版本除在原先的基础上增加了少量功能之外,实现 算法并未加以重大修改。此版本并不与原先任何版 本兼容。 ==========ShellEval Ver3.2.6 ============= 筆者按。 2010、09、18

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值