js的with

作者: Gary嘉骏 | 来源:发表于2020-12-22 15:26 被阅读0次

    js里的with,除了刚接触前端的时候知道不推荐用以外,就没有再有任何的了解和使用。但最近在看阿里巴巴的飞冰项目中的微前端的实现时,在其中沙箱用了with去阻断沙箱内对 window 全局变量的访问和修改。在好奇沙箱原理前,必须温习下with

    首先with只能在非严格模式中使用,通常被当做重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。

    var obj = {
      a: 1,
      b: 2,
      c: void 0
    }
    
    with (obj) {
       a = a + b;
       c = a;
    }
    
    console.log(obj.c) // 3
    

    上面看起来写法确实简洁,但有一个问题,可能会导致数据泄露,比如:如果上面的obj初始化时没有加c这个变量,还会打印出3吗?结果是undefined,但c的赋值去哪了?其实都离不开js的基础知识,这时涉及的就是作用域链了,with里找c属性,实际是找obj.c,下一步发现没有这个属性,就往上一个作用域去找,这时就是window了,而非严格模式下,即使没有声明c这个变量,但也会隐式去声明并赋值。

    或者可以这样想with里面的运行状况

     with (obj) {
       a = a + b;
       c = a;
    }
    
    等于:
    
    function (obj) {
    var a = obj.a;
    var b = obj.b;
    a = a + b;
    c = a;
    obj.a = a;
    obj.b = b;
    }()
    
    

    另外with还有性能问题,原因是 浏览器JavaScript 引擎会在编译阶段进行数项的性能优化。其中有些优化依赖于能够根据代码的词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标识符。但with的话,无法确认with里的作用域值。

    可以这样对比下,性能差距还是挺大的:

    function normal() {
        console.time("normal");
        var obj = {
            a: [1, 2, 3]
        };
        for(var i = 0; i < 100000; i++)
        {
            var v = obj.a[0];
        }
        console.timeEnd("normal");
    }
    normal();
    
    function funcWith() {
        console.time("funcWith");
        var obj = {
            a: [1, 2, 3]
        };
        with(obj) {
            for(var i = 0; i < 100000; i++) {
                var v = a[0];
            }
        }
        console.timeEnd("funcWith");
    }
    
    funcWith();
    

    相关文章

      网友评论

          本文标题:js的with

          本文链接:https://www.haomeiwen.com/subject/jnrsnktx.html