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 ofnoscript
get parsed as markup.
好的吧,标准就是这么定的!事实上,在不同的浏览器上可能还是会有略微的表现形式差异,但是我们仍然应该基于标准开发。
参考资料
水了一篇,美滋滋。
植入部分
如果您觉得文章不错,可以通过赞助支持我。
如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。
跨域动态创建script请求头不就是用createElement 后再addappendChild上去的么。。。
对