当前位置:首页 > Web开发 > 正文

你不知道的JS系列 ( 7 ) - 欺骗词法感化域

2024-03-31 Web开发

如果词法感化域完全由写代码期间函数所声明的位置来界说,怎样才华在运行时来“改削”词法感化域呢?有些人喜欢特殊的步伐来解决遇到的问题。我们规定词法感化域是代码写在哪里决定的,一旦决定了无法变动,因为一些问题,我们不得不变动感化域,尽管这是不被保举的,那是什么步伐,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