zoukankan      html  css  js  c++  java
  • new Function和with

    今天在看一篇将介绍前端的文章时,在讲到js 沙箱隔离的时候提到了 with() + new Function(code) + Proxy 的方式,with 和 new Function 我之前很少(没有)用到,没想到还有这作用,所以这篇来总结和记录下这两者的区别:

    with

    with语句用于 扩展一个语句的作用域链。语法如下:

    with (expression) {
        statement
    }
    

    JavaScript查找某个未使用命名空间的变量时,会通过作用域链来查找,作用域链是跟执行代码的context或者包含这个变量的函数有关。'with'语句将某个对象添加到作用域链的顶部,如果在statement中有某个未使用命名空间的变量,跟作用域链中的某个属性同名,则这个变量将指向这个属性值。如果沒有同名的属性,则将拋出ReferenceError异常。

    大白话就是:with语句会改变标识符的查找优先级,用来拦截对访问对象的查找,优先从with指定对象的属性中查找。

    with指定的对象为obj,with代码块的语句的作用域首先是obj,然后才是window,如果代码块中的属性在obj中存在,则可以正常访问,如果不存在obj中,则会继续向上寻找(window),如果window也没有,则会报 ReferenceError 异常

    var a = 1;
    var obj = {
        a: 2
    };
    
    with (obj) {
        console.log(a); // 2
        console.log(b); // Uncaught ReferenceError: b is not defined
    }
    
    var a = 1;
    var b = 3;
    var obj = {
        a: 2
    };
    
    with (obj) {
        console.log(a); // 2
        console.log(b); // 3
    }
    

    注意: 不推荐使用with,在 ECMAScript 5 严格模式中该标签已被禁止。推荐的替代方案是声明一个临时变量来承载你所需要的属性。

    new Function

    Function 构造函数创建一个新的 Function 对象。直接调用此构造函数可用动态创建函数,但会遇到和 eval 类似的的安全问题和(相对较小的)性能问题。然而,与 eval 不同的是,Function 创建的函数只能在全局作用域中运行。

    语法:

    new Function ([arg1[, arg2[, ...argN]],] functionBody)

    顺便提一下eval: 同样不推荐使用eval,可以使用Function来代替

    function test() {
      var x = 2, y = 4;
      console.log(eval('x + y'));  // 直接调用,使用本地作用域,结果是 6
      var geval = eval; // 等价于在全局作用域调用
      console.log(geval('x + y')); // 间接调用,使用全局作用域,throws ReferenceError 因为`x`未定义
      (0, eval)('x + y'); // 另一个间接调用的例子
    ​}
    

    new Function示例:

    var a = 1;
    function f() {
        var a = 2;
        var g = new Function('console.log(a);'); // 1
        g();
    }
    f();
    

    new Function + with

    with一般用于 一些模板引擎编译后的模板函数中会利用with访问模板数据(ejs 模板引擎就是用的with) 。

    我们看一个例子:

    var fn=new Function('obj', 'with(obj){return prop.value;}');
    var data={
        prop:{
            value:1
        }
    };
    fn(data);  //1
    

    例子中我们使用 prop.value 来访问data(with的指定对象),但是如果我们的data对象嵌套很深,我们就得写为 prop.value.xx.xxx.xxx.***...

    我们利用with可以简写为如下:

    function evalPropChain(data, propChainStr){
        return new Function('obj', 'with(obj){return ' + propChainStr + ';}')(data);
    }
    var data={
        prop:{
          prop1: {
            prop2: {
              value: 1
            }
          }
        }
    };
    evalPropChain(data, 'prop.prop1.prop2.value'); // 1
    

    参考

  • 相关阅读:
    【LeetCode-动态规划】编辑距离
    【LeetCode-栈】计算器
    【LeetCode-栈】字符串解码
    【LeetCode-数组】缺失的第一个正数
    【LeetCode-查找】寻找重复数
    【LeetCode-堆】丑数
    【LeetCode-堆】数据流中的第K大元素
    【LeetCode-排序】根据身高重建队列
    立项与启动
    JS中match方法探究
  • 原文地址:https://www.cnblogs.com/hanshuai/p/14984236.html
Copyright © 2011-2022 走看看