JavaScript 核心原理解析
周爱民
《JavaScript 语言精髓与编程实践》作者,南潮科技(Ruff)首席架构师
32699 人已学习
新⼈⾸单¥59
登录后,你可以任选3讲全文学习
课程目录
已完结/共 28 讲
开篇词 (1讲)
JavaScript 核心原理解析
15
15
1.0x
00:00/00:00
登录|注册

21 | (0, eval)("x = 100") :一行让严格模式形同虚设的破坏性设计(下)

豁免案例
值和引用的返回
语句执行的结果
直接调用的执行环境
直接调用的严格模式问题
直接调用的特性
间接调用的执行环境
间接调用的严格模式问题
间接调用的特性
思考题
eval的返回结果
直接调用eval
间接调用eval
JavaScript中的eval调用

该思维导图由 AI 生成,仅供参考

你好,我是周爱民。欢迎回到我的专栏。书接上回,这一讲我们仍然讲动态执行。
之前我说到过,setTimeout 和 setInterval 的第一个参数可以使用字符串,那么如果这个参数使用字符串的话,代码将会在哪里执行呢?毕竟当定时器被触发的时候,程序的执行流程“很可能”已经离开了当前的上下文环境,而切换到未知的地方去了。
所以,的确如你所猜测的那样,如果采用这种方式来执行代码,那么代码片断将在全局环境中执行。并且,这也是后来这一功能被部分限制了的原因,例如你在某些版本的 Firefox 中这样做,那么你可能会得到如下的错误提示:
> setTimeout('alert("HI")', 1000)
Content Security Policy: The page’s settings blocked the loading of a resource at eval (“script-src”).
在全局环境中执行代码所带来的问题远远不止于此,接下来,我们就从这个问题开始谈起。

在全局环境中的 eval

早期的 JavaScript 是应用于浏览器环境中的,因此,当网页中使用<SCRIPT>标签加载.js 文件时候,代码就会在浏览器的全局环境中执行。但这个过程是同步的,将 BLOCK 掉整个网页的装载进度,因此有了defer这个属性来指示代码异步加载,将这个加载过程延迟到网页初始化结束之后。不过即使如此,JavaScript 代码仍然是执行在全局环境中的。
在那个时代,<SCRIPT>标签还支持forevent属性,用于指定将 JavaScript 代码绑定给指定的 HTML 元素或事件响应。当采用这种方式的时候,代码还是在全局环境中执行,只不过可能初始化为一个函数(的回调),并且this指向元素或事件。很不幸,有许多浏览器并不实现这些特性,尤其是for属性,它也许在 IE 中还存在,这一特性与 ActiveXObject 的集成有关。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

JavaScript严格模式并非一种特定的“严格模式环境”,而是对代码执行过程的限制。全局环境中执行代码可能带来问题,对eval()函数的使用也进行了详细讨论。严格模式的实质是对代码执行过程的限制,而非一种环境模式。文章解释了严格模式的实现方式,包括在可执行对象创建或初始化阶段处理大部分严格模式特性,以及在语法分析阶段识别和处理部分特性。在讨论eval()调用时,文章提到了直接调用和间接调用的区别,以及在间接调用中的严格模式处理方式。文章还解释了标题中的代码为何是一种间接调用。总的来说,文章涉及了JavaScript严格模式的技术特点,对于读者快速了解文章概览具有一定的参考价值。 在文章中,还对eval()的返回结果进行了讨论,指出eval(x)将返回语句执行的结果,而不返回引用。此外,文章还提到了间接调用对“严格模式”的绕过机制,以及间接调用的实用意义和对系统的潜在威胁。最后,留下了一个思考题,让读者尝试找出一例豁免案例,即直接调用eval()的写法。 总的来说,本文深入探讨了JavaScript严格模式和eval()函数的技术特点,对于读者快速了解这些内容具有一定的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《JavaScript 核心原理解析》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(7)

  • 最新
  • 精选
  • 海绵薇薇
    老师好: 一开始我并不能理解函数中的eval是一个环境引用(一开始以为必须要全局环境引用 ): function a () { var eval = global.eval } 这里的eval是一个环境引用,但是却和global.eval不是一个引用,因为 eval = global.eval 将右边的值赋值给左边的引用,所以eval是一个引用存储了global.eval这个 引用的值。 也就是说eval是一个引用但是并不是global.eval这个引用,是函数环境引用。 所以eval要求的是环境引用并不要求全局环境引用。 另,环境可以分为四种:全局环境,对象环境,模块环境和eval环境。 另,eval的名字一定要是eval 根据上面两个直接调用eval的条件,能想到的还有如下两个额外的豁免方法。 第一(在当前环境中): try { throw eval } catch (eval) { let e = 1; eval("console.log(e)") } 第二(在eval环境中): eval("let e = 1; eval(console.log(e)) ")

    作者回复: 对的。你现在的理解就是对的。而且catch()这个豁免方法是完全出乎我意料的,但也是对的。赞~ ~ 不过通常不要叫“环境引用”,就是“环境”而已,“环境(Environment)”是一个规范类型,它跟“引用(Reference)规范类型”一样,都是ECMAScript中的、同一级别的东东。

    2020-09-05
    7
  • 行问
    2020 年好! 立一个 flag,今年要把您的书和专栏学习 2 次,不是阅读,是学习。虽然有很多的不懂,持续学习,不断积累。 也公布下本年度的 flag,有兴趣的小伙伴可以来共勉:2020 年做到 80% 以上的每一天 5:28 起床、23:00 前睡觉(2019 年只做到大概 50%,惭愧)

    作者回复: ...... 给新年计划点赞! 我已经保持大概(或至少)20年的习惯,大概是每天3:00前后睡了。 不过这不是好习惯,不值得推广……

    2020-01-01
    2
    3
  • kittyE
    var arr = [] var x = 100 arr[0] = eval (arr[0])(x) 属性引用仍然是间接调用,我这样理解对吗

    作者回复: 是的。

    2020-01-01
    1
  • qqq
    (0, eval)('this.eval("b = 1")')

    作者回复: 这个可没有被豁免,"b = 1"仍然是被间接调用的eval执行的。

    2020-01-02
  • K4SHIFZ
    规范18.2.1.1章: Runtime Semantics: PerformEval ( x, evalRealm, strictCaller, direct ) ... 12.NOTE: If direct is true, ctx will be the execution context that performed the direct eval. If direct is false, ctx will be the execution context for the invocation of the eval function. 13.If direct is true, then Let lexEnv be NewDeclarativeEnvironment(ctx's LexicalEnvironment). Let varEnv be ctx's VariableEnvironment. 14.Else, Let lexEnv be NewDeclarativeEnvironment(evalRealm.[[GlobalEnv]]). Let varEnv be evalRealm.[[GlobalEnv]]. 15.If strictEval is true, set varEnv to lexEnv. ...
    2020-02-05
    2
  • qqq
    (eval.valueOf())('a = 1')
    2021-03-26
  • undefined
    转眼这个课程一年了,还没有学完。 最近开始重新翻出来学习,搭配书籍一块儿消化下。
    2021-03-15
收起评论
显示
设置
留言
7
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部