JavaScript Note.我想插入一个动态的脚本

发现各位观众老爷们要求太高吓得我都不敢更新了……喵喵喵,我明明只是一个笔记本顺便分享一下……的说。

还是安静的当个笔记本吧……

最近两次跌到在同一个坑里,问题其实非常简单,也非常基础,就是——我需要动态加载并执行脚本。

一般来说,我喜欢用 innerHTML 这种简单明快的方式添加内容,但是却发现,innerHTML 竟然无法执行我添加的 <script> 脚本,很明显,这不符合我的预期——

先来说说解决方案吧:

简单粗暴:eval

eval 是一种非常简单粗暴的方式,但是确实会带来很明显的安全问题,「eval is evil」。

引用自 MDN:

eval() 是一个危险的函数, 他执行的代码拥有着执行者的权利。如果你用 eval() 运行的字符串代码被恶意方(不怀好意的人)操控修改,您最终可能会在您的网页/扩展程序的权限下,在用户计算机上运行恶意代码。更重要的是,第三方代码可以看到某一个 eval() 被调用时的作用域,这也有可能导致一些不同方式的攻击。相似的 Function 就不容易被攻击。
eval() 通常比替代方法慢,因为它必须调用 JS 解释器,而许多其他结构则由现代 JS 引擎进行优化。

很明显,最简单粗暴的方法也最不可取。

更新:eval 同时改变了作用域,所以大多数情况下我们并不能选择它,除非是非常简单的脚本。

常见策略:appendChild

三行代码也可以插入并执行一段代码——

const s = document.createElement('script');
s.textContent = text;
document.body.appendChild(s);

这种方法肯定比前一种靠谱多了。如果你只想要运行,可以在完成添加后移除掉这个标签。

更新:但是这种方法也有缺点,就是无法用 try catch 捕获异常,如果你直接执行内容,那么只能在 window.onerror 中捕获到异常,这样其实是非常不便的。

骚操作:document.write

document.write 当然是可以的,不过问题是——顺手把页面也给刷新了,一般情况下肯定是不能够的,不过这点正好被用在了需要复写的 restc-chrome-extension

https://github.com/csvwolf/restc-chrome-extension/blob/master/src/index.js#L35

为什么 innerHTML 无效

刚开始很郁闷,同样是插入标签,为什么只有 innerHTML 不行,直到我在标准中看到这样一句:

script elements get marked unexecutable and the contents of noscript get parsed as markup.

好的吧,标准就是这么定的!事实上,在不同的浏览器上可能还是会有略微的表现形式差异,但是我们仍然应该基于标准开发。

参考资料

水了一篇,美滋滋。

植入部分

如果您觉得文章不错,可以通过赞助支持我。

如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。

标签: 知识, 语法

已有 2 条评论

  1. 跨域动态创建script请求头不就是用createElement 后再addappendChild上去的么。。。

添加新评论