`
项志鹏同學
  • 浏览: 12670 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类
最新评论

由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('...')不是直接调用的原因。
分享到:
评论

相关推荐

    java解析公式 eval.jar

    1. **动态公式解析**:`eval.jar`能够将字符串形式的公式转换为可执行的表达式。这意味着在程序运行过程中,可以根据需要动态改变计算公式,增加程序的灵活性。 2. **运算符支持**:库支持基本的算术运算符(+,-,...

    Z.Expressions.Eval.rar

    公式操作、表达式动态语句,可以考虑使用 Eval Expression。 本文件给你无限使用的特权,基于netstand2.1制作,可以方便的用于netcore 3.1和net5中 需要下列包 &lt;PackageReference Include="Microsoft.Extensions....

    Z.Expressions.Eval.2.4.2

    Z.Expressions.Eval 2.4.2 是一个专注于表达式解析的开源库,它由Java语言构建,设计为超轻量级且高度可扩展。这个工具包的主要目标是提供一个强大的框架,允许开发者在应用程序中方便地处理和执行自定义的公式化...

    Z.Expressions.Eval 4.0.68.zip

    《Z.Expressions.Eval 4.0.68:强大的表达式评估库》 在.NET开发领域,Z.Expressions.Eval是一款非常实用的库,主要用于解析和执行动态表达式。该库的最新版本4.0.68引入了对.NET 3.1和.NET 6框架的全面支持,为...

    Faster R-CNN中voc_eval.py文件

    借助Faster R-CNN中voc_eval.py文件,测试YOLO测试数据集mAP等结果,博客见

    前端项目-expr-eval.zip

    1. 引入库:在项目中引入expr-eval库,可以是通过npm(Node Package Manager)安装,或者直接引入CDN链接。 2. 创建表达式:将需要计算的数学表达式以字符串形式存储。 3. 评估表达式:调用expr-eval提供的函数,...

    trec_eval_latest.tar

    1. **计算评价指标**:trec_eval可以计算多种评价指标,如查准率(Precision)、查全率(Recall)、F-measure(包括F1-score)、平均精确率(Average Precision)、NDCG(Normalized Discounted Cumulative Gain)等...

    GD32E230C_EVAL.rar

    标题中的"GD32E230C_EVAL.rar"是一个压缩包文件,主要涉及的是GD32系列微控制器,特别是GD32E230C评估板上的固件移植示例。GD32是由国内知名半导体公司GigaDevice(兆易创新)推出的32位通用MCU产品线,其E230系列...

    trec_eval.exe

    trec_eval.exe是一款广泛应用于信息检索领域的效果评价工具,它是由TREC(Text REtrieval Conference)组织开发的,旨在为研究人员提供一种标准化的方式来评估和比较不同的信息检索系统。TREC是国际上颇具影响力的...

    java四则运算eval.jar

    例: Expression e = new [removed]"1+2*((3+5)/10*5*4 +(1-2)/4)"); System.out.println(e.eval&#40;&#41;);//32.5 要求jdk1.6

    powerdesigner125-eval.exe

    powerdesigner125_eval.exe,powerdesigner125_eval.exe,powerdesigner125_eval.exe,powerdesigner125_eval.exe,powerdesigner125_eval.exe,powerdesigner125_eval.exe,powerdesigner125_eval.exe,powerdesigner125_...

    iDRAC9-Ent-Eval.xml

    下载iDRAC试用版许可证以便启用PowerEdge企业功能。 iDRAC9 试用

    SQL2019-SSEI-Eval.exe

    MSSQL2019,用于安装微软的数据库2019年版,可以适用于计算机后台开发数据库存储,WIN10试用版,可以在WIN10系统上安装使用,不适用WIN7系统。

    iDRAC9-Ent-Eval.rar

    这个“iDRAC9-Ent-Eval.rar”文件包含的是iDRAC9企业版的试用许可证,有效期为30天。试用版的目的是让潜在用户在购买正式许可证之前,能够全面体验iDRAC9的功能。 iDRAC9的主要特点和功能包括: 1. **远程访问**:...

    绘制yolov3 P-R曲线的脚本voc_eval.py

    能够进行绘制yolov3算法模型P-R曲线的脚本voc_eval.py,在python2环境下运行。

    Codejock.ToolkitPro.MFC.Eval.17.3.0.part

    Codejock.ToolkitPro.MFC.Eval.17.3.0.part2

    I2C.zip_STM3210E_STM32F10X.h_stm32_eval.h_stm32_eval_i2c__stm32f

    #include "stm32_eval_i2c_tsensor.h" #include "stm32_eval.h" #ifdef USE_STM32100E_EVAL #include "stm32100e_eval_lcd.h" #elif defined USE_STM3210E_EVAL #include "stm3210e_eval_lcd.h" #elif defined ...

    nTierGen.eval.1.3

    《nTierGen.eval.1.3:探索N层架构代码生成器的魅力》 在软件开发领域,尤其是在企业级应用的构建中,N层架构(也称为多层架构)是一种广泛采用的设计模式。它将应用程序分为多个逻辑层,包括用户界面层、业务逻辑...

    python 常用 示例 数据 train.csv eval.csv titanic.csv

    X_eval, y_eval = df_eval.drop('Survived', axis=1), df_eval['Survived'] X_train, X_test, y_train, y_test = train_test_split(X_train, y_train, test_size=0.2) model = LogisticRegression() model.fit(X_...

    GD32307C_EVAL.rar

    GD32307C_EVAL.rar 是一个针对GD32307C微控制器的开发资源压缩包,其中包含了多个知名实时操作系统(RTOS)的移植版本。这些RTOS包括FreeRTOS、rt-thread、uCos_II、uCosIII以及RTX和LiteOS。这个资源对于那些在GD32...

Global site tag (gtag.js) - Google Analytics