代码之家  ›  专栏  ›  技术社区  ›  meandmycode

与javascript范围链交互

  •  3
  • meandmycode  · 技术社区  · 16 年前

    给定作用域中的以下javascript片段:

    var x = 10;
    
    function sayx() {
      alert(x);
    }
    
    sayx();
    

    当然,您会期望消息框打印“10”,您可以进行多功能嵌套以与确定“x”的方式交互,因为在解析“x是什么”时,环境会沿着范围链向上移动。

    甚至可以使用eval执行“重新编译”级别,以便在运行时插入新的范围。例如:

    var x = 10;
    
    function sayx() {
      alert(x);
    }
    
    function wrap(f) {
      return eval('(function() { var x = 20;(' + f + ')(); })');
    }
    
    wrap(sayx)();
    

    这是因为函数将调用其ToString函数,该函数将返回“原始”源。因此,我们实质上创建了一个函数的封装版本,该函数有一个覆盖X的新作用域。结果将是一个打印“20”而不是“10”的警告框。

    然而,从表面上看,这似乎可行,但作用域链已断开,链中的下一个项不再相同,因为函数“f”现在定义在不同的位置。更糟糕的是,它继承的作用域链可能包含许多调用函数不应该访问的引用。

    那么,是否有一种更受支持、更可行的方法来注入一个范围项?类似:

    function withScope(f, scope) { ??? }
    
    ---
    
    var x = 10, y = 10;
    
    function dothemath() {
      alert(x + y);
    }
    
    var haxthemath = withScope(dothemath, { x: 9000 });
    haxthemath(); // 9010 not 20
    

    我猜答案是“不”,有些人可能会说这样的范围注入存在“安全”问题,但是考虑到你无论如何都能做到这一点(尽管严重损坏),我不认为是……

    这样做的好处是,您基本上可以伪造自己的伪变量。

    事先谢谢。


    编辑,只是澄清一点,想象一下我想要“withscope”一个具有以下范围链的函数:

    Window - window properties
    Object - { var x = 10 }
    Object - { var y = 5 + x }
    

    我希望能够返回一个有效地具有相同链+我提供的作用域的函数。IE:

    withScope(somefunc, { foo: 'bar' })
    

    会给我

    Window - window properties
    Object - { var x = 10 }
    Object - { var y = 5 + x }
    Ext scope - { foo = 'bar' }
    

    所有先前的站立变量都会被发现,因为我的扩展范围没有提到它们。

    4 回复  |  直到 16 年前
        1
  •  4
  •   Jani Hartikainen    16 年前

    如果按范围引用函数和/或闭包中的局部变量,我认为答案是否定的。

    您可以更改 this 关键字通过使用functionname.call(scope,arg1,…)或functionname.apply(scope,[arg1,…]);这可以与原型一起使用,创建类似的链,如您所描述的那样-如果在对象自己的属性中找不到某些内容,则在其原型中查找。如果属性不存在,则使用链中的下一个原型,依此类推。

        2
  •  0
  •   Breton    16 年前

    我想你要找的答案是内置的“with”语句。

    但是,我不建议使用它,因为它已被弃用,并且很可能不存在于ecmascript 6中。

    我认为您能做这类事情的唯一其他方法是从宿主应用程序本身内部,从外部操纵JavaScript环境。或者,如果你使用犀牛,你可以从JavaScript中做到这一点,因为JAVA API和JavaScript之间的链接就是犀牛的无缝连接。当史蒂夫耶格第一次指出这件事时,我的脑子就被打乱了。从Javascript外部操作Javascript,但从Javascript内部操作!真是天才!

    如果你困在一个浏览器环境中,也许你可以使用一个用JavaScript编写的JavaScript解释器,比如Narcissus。

        3
  •  0
  •   Caleb    16 年前

    可能使用javascript内置的 toString 函数的方法?

    function withScope(f, scope) {
        var toExec = "";
        for (var prop in scope) {
            toExec += "var " + prop + " = scope['" + prop + "'];"
        }
        toExec += "f = (" + f.toString() + ")";
        eval(toExec);
        return f;
    }
    var x = 10;
    var f = function() {
        console.log(x);
    };
    withScope(f, {x: 20})();
    

    不过,这似乎是个坏主意…

        4
  •  0
  •   pr1001    16 年前

    如果你想玩范围,你可能会喜欢 let javascript 1.7中提供的语句。 Recent versions of Firefox support let .

    推荐文章