• 你不知道的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,那么运行起来一定会非常慢。无论引擎多聪明,试图将这些悲观情况的副作用限制在最小范围内,也无法避免如果没有这些优化,代码会运行的更慢这个事实
  • 相关阅读:
    guzzle 中间件原理
    K8S-K8S 环境搭建
    K8S-k8s 理念知识
    云计算的概念
    Linux-DHCP 交互的过程
    linux-怎么踢出系统当前已连接的用户
    linux-Centos 搭建http yum源
    linux-硬链接与软连接
    linux-centos网络配置bond
    linux-dd 一个测试文件
  • 原文地址:https://www.cnblogs.com/wzndkj/p/12320918.html
Copyright © 2020-2023  润新知