zoukankan      html  css  js  c++  java
  • with欺骗作用域

    with关键字可以划分出一个属于某个对象的作用域,然后在该作用域内对该对象的属性进行更新。
    例子:

    var obj = {
        a:1,
        b:2,
        c:3
     }
     
     obj.a = 11;
     obj.b = 22;
     obj.c = 33;
     //等价于
     with(obj){
        a = 11;
        b = 22;
        c = 33;
    }
    

    但是如果在with划分出来的作用于里面对一些不属于与之绑定的对象的属性进行赋值时,会有特殊情况发生:

    function f(obj){
        with(obj){
            a=34;
        }
        console.log(obj);
    }
    var o1={a:1},o2={b:2};
    f(o1);
    f(o2);
    console.log(o2.a);
    console.log("window",a);
    //输出
    {a:34}
    {b:2}
    undefined
    window 34
    

    因为o1中有属性a,所以它的a被改变了,而o2中没有,这里并不会给它添加一个属性a,所以o2.a依然是undefined。而事实上,在传入参数为o2,执行a=34时,JavaScript引擎对a进行了LHS操作,引擎会沿着作用域链去查找a,如果直到全局作用域还没找到,就会创建一个a,所以最后可以看到全局作用域下有了一个a,并且被赋值为34.

    如果试着在函数f内创建一个变量a,在传入参数为o2时,改变的是f函数里的a,全局作用域下并不会创建a.

    function f(obj){
      var a = 9;
        with(obj){
            a=34;
        }
        console.log(obj);
      console.log("f",a)
    }
    var o1={a:1},o2={b:2};
    f(o1)
    f(o2)
    
    console.log("window",a)
    //输出
    {a:34}
    f 9
    {b:2}
    f 34
    Uncaught ReferenceError: a is not defined
    

    如果在with块内用var声明变量,该变量会被创建到with所在的作用域里:
    不加var

    function f(obj){
        with(obj){
           a=34;
        }
        console.log(obj);
        console.log("f",a)
    }
    var o1={a:1},o2={b:2};
    f(o1)
    f(o2)
    //f(o1)和f(o2)分别会输出
    {a:34}
    Uncaught ReferenceError: a is not defined
    {b:2}
    f 34
    

    f(o1)在打印a时会出错,因为f函数作用域和window作用域都没有创建过a。
    f(o2)输出的a其实是window.a,因为函数可以访问外部作用域的变量。
    看看加了var的:

    function f(obj){
        with(obj){
           var a=34;
        }
        console.log(obj);
      console.log("f",a)
    }
    var o1={a:1},o2={b:2};
    f(o1)
    f(o2)
    console.log("window",a);
    //输出
    {a:34}
    f undefined
    {b:2}
    f 34
    Uncaught ReferenceError: a is not defined
    

    这次调用f(o1)时没报错了,因为var a的声明被提升到了函数作用域上,而赋值操作依然是对obj.a进行的(如果有该属性的话)。
    在with内使用const和let,既不能提升到外层作用域,也不能完成赋值。

    参考:《你所不知道的JavaScript》(上卷)

  • 相关阅读:
    第二阶段冲刺--第五天
    git托管代码随笔--运用ssh传输,不用每次提交频繁输入github账号密码
    项目冲刺--第十天
    项目冲刺--第九天
    随堂练习--用例图练习
    项目冲刺--第四天
    第五次个人作业: 案例分析--微软必应词典客户端
    Code.R团队展示
    Android 自定义AlertDialog
    Ubuntu打开系统监视器查看进程&资源等信息
  • 原文地址:https://www.cnblogs.com/liulangbxc/p/15259049.html
Copyright © 2011-2022 走看看