你不知道的JS系列 ( 7 ) - 欺骗词法感化域
如果词法感化域完全由写代码期间函数所声明的位置来界说,怎样才华在运行时来“改削”词法感化域呢?有些人喜欢特殊的步伐来解决遇到的问题。我们规定词法感化域是代码写在哪里决定的,一旦决定了无法变动,因为一些问题,我们不得不变动感化域,尽管这是不被保举的,那是什么步伐,JavaScript 中有两种机制来实现这个目的
eval
function foo(str, a) { eval(str); console.log(a, b) } var b = 2; foo("var b = 3", 1); // 1, 3
eval() 函数可以接受一个字符串为参数,然后可以在写的代码顶用措施生成代码并运行,就仿佛代码是写在阿谁位置一样
eval() 挪用中的 "var b - 3;",这段代码声明了一个新的变量 b,因此它对已经存在的 foo 的词法感化域进行了改削。事实上,和前面提到的道理一样,这段代码实际上在 foo 感化域内部创建了一个变量 b,并遮蔽了外部感化域的同名变量。
当 console.log() 被执行时,在 foo 感化域内部同时找到 a 和 b,因为感化域查找会在找到第一个匹配当标识符时遏制,所以永远也无法找到外部的 b。
默认情况下,如果 eval() 中所执行的代码包罗有一个或多个声明的变量还是函数,就会对 eval() 所处的词法感化域进行改削。严格模式下不会,严格模式下, eval 有本身的词法感化域,意味着此中的声明无法改削地址的感化域。
在措施中动态生成代码的使用场景非常罕见,因为它所带来的好处无法抵消性能上的损掉
with
JavaScript 中的另一个难以掌握的用来欺骗词法感化域的成果可能是 with 关键字,此刻也不保举使用。为什么都不保举使用,我们还要去搞懂它呢?说不定我们遇到要维护老项目,哪个二货就用了,遇到了坑,,我们不知道其道理,无法定位问题,岂不是慌的一批
with 凡是被看成反复引用同一个东西中的多个属性的快捷方法,可以不需要反复引用东西自己,好比:
var obj = { a: 1, b: 2, c: 3 } // 单调乏味的反复 "obj" obj.a = 2; obj.b = 3; obj.c = 4; // 简单的快捷方法 with(obj){ a = 3; b = 4; c = 5; } 但实际上这不只仅是为了便利地访谒东西属性。考虑如下代码: function foo(obj){ with(obj){ a = 2; } } var o1 = { a: 3 } var o2 = { b: 3 } foo(o1); console.log(o1.a); // 2 foo(o2); console.log(o2.a); // undefined console.log(a); // 2 欠好,a 被泄漏到全局感化域了
o2 的感化域,foo 的感化域和全局感化域都没有找到标识符 a,因此当 a = 2 执行时,自动创建了一个全局变量(非严格模式下)。
此外一个不保举使用 eval() 和 with 的原因是会被严格模式所影响。with 完全禁止,而在保存核心成果的前提下,间接或非安适地使用 eval() 也被禁止了
如果它们能实现更庞大的成果,并且代码更具有扩展行,难道不长短常好的成果吗?答案是否定的。
JavaScript 引擎在编译阶段进行数项的性能优化。此中有些优化依赖于能够按照代码的词法进行静态分析,并预先确定所有变量和函数的界说位置,才华在执行过程中快速找到标识符。但如果引擎在代码中发明 eval() 或 with,它只能简单地假设关于标识符位置的判断都是无效的。
如果代码中大量使用 eval() 或 with,那么运行起来必然会非常慢。无论引擎多聪明,试图将这些灰表情况的副感化限制在最小范畴内,也无法制止如果没有这些优化,代码会运行的更慢这个事实
你不知道的JS系列 ( 7 ) - 欺骗词法感化域
温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/web/30047.html
- 上一篇:网站优化扶植的10个最佳实践
- 下一篇:是一种json格式的报文