由jQuery项目中的BUG引发的对eval和let的思考

217 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情

阅读须知

阅读本文需了解eval以及let、const、var。

该文章主要记述我项目中的一个BUG及其解决方案和原理。不用知道jquery的知识应该也能看懂。

bug原理涉及:let与var的块渗透情况、jquery的$('选择器').html()的原理【已经过时的技术,在这里原理点到为止,不做过多阐述】。

知识点详见:

使用jQuery将html文件引入到另一个html文件

正常使用jQuery的项目,当我们要将一个html文件【或php】作为模板引入到另一个html文件中,我们需要使用ajax请求

【没学过的同学在该篇文章中可以片面的将ajax这个功能认为为一个异步操作,是给定一个url他会传回指定url的文件的具体内容,之后调用then就可以以将一个函数作为参数传入,作为异步操作完成之后执行的代码。当然实际功能要复杂的多。】

,并将请求后得到的html文件的字符串作为jQuery的html()函数的参数传入,便可将指定的html代码加载到指定位置,且html模板中对应的脚本也可以被执行成功。

比如:demo.html文件需要将demo1.html文件的内容挂载在demo.html的id为load的div下。

demo.html

<!--省略其他无关内容-->
<div id="load">
    <script>
        $.ajax('demo1.html').then((res) => {
        //$.ajax可以看作返回期约的ajax封装,属于jquery自带的。
            $("#load").html(res);
        });
    </script>
</div>

项目中的异常情况

以下demo为具体项目业务逻辑的简单抽象。

我想在demo.html文件中id为loadMainView的div中加载demo1.html文件的内容。

demo1.html文件的内容如下。

<script>
    let x = 2,a;
</script>
<div id="loadHTML">
  <script>
    console.log("此处的x" + x);//访问不了
  </script>
</div>

在引入文件之后我发现浏览器报错了。显示说x变量不存在。

然而普通html文件中,let定义的变量是可以跨script的。所以说html写的应该没有问题,是其他问题。

问题出现原因

经过长时间排查以及查找资料,最终发现是$().html这个API的原理所导致的。

该API的原理大致就是,遇到script先看是内嵌脚本还是外部引用脚本,要是外部引用脚本就正常处理,要是内嵌脚本就使用eval函数运行内嵌脚本中的代码。

然而要知道eval中运行的代码的作用域是在全局,且被包裹在一个块中的。而let是局部作用域,无块渗透功能,所以说let变量被限制在这个全局的块中。当他运行下一个内嵌脚本的时候,上一个内嵌脚本的let变量已经被销毁。无法在当前运行的脚本中观测。所以会出现访问变量,变量报未定义的错。

解决方案

使用var,由于var的作用域是函数或全局作用域,本身自带块渗透功能。详见一篇读懂var、let、const、暂时性死区

而将demo1.html中的let x = 2,a;改为var x = 2,a;

这样就能保证变量从eval创建的块中渗透出去,直接到全局作用域中。挂载到了全局上下文的变量对象上,这样就可以在全局任意地方访问。

自然报错解决。

句末语

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情