js的with

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)