简体   繁体   English

如何防止闭包保留javascript函数的参数?

[英]How do I prevent an argument to a javascript function being retained by a closure?

EDIT: The context for this question is, the argument is the source string for a module being loaded which could be huge, and there are many many modules being loaded this way, and each one has a closure with the original source code of the module held within it, using memory, when its not needed or wanted. 编辑:此问题的上下文是,参数是正在加载的模块的源字符串,该字符串可能很大,并且以这种方式加载了许多模块,每个模块都有一个与模块原始源代码一起的闭包当不需要或不需要内存时,使用内存将其保留在内存中。

Specifically, I am trying to fix this https://github.com/dojo/dojo/blob/master/dojo.js#L367 code which leaks the module source into the closure. 具体来说,我正在尝试修复此https://github.com/dojo/dojo/blob/master/dojo.js#L367代码,该代码会将模块源泄漏到闭包中。

<script>
function closureTest(n) {
    function eval_(__text) {
        return eval(__text);
    }
    for (var i = 0; i < n; i++) {
        var m = eval_("(function(){ var x = 10; return function(n) { return x+n; }; })(window);");
        m(5);
    }
}
</script>
<button onclick="closureTest(1000)">Run</button>

In the above code, if a breakpoint is placed inside the anonymous function, and the closures that exist are examined, we can see that one of the closures contains __text and arguments[0] that contains the original source code of the module as it was passed to eval_ 在上面的代码中,如果在匿名函数内部放置了一个断点,并且检查了存在的闭包,我们可以看到其中一个闭包包含__text和arguments [0],该文本原样包含模块的原始源代码传递给eval_

Here is a variation of the above: 这是上述内容的一种变体:

<script>
function closureTest(n) {
    function eval_() {
        return eval(arguments[0]);
    }
    for (var i = 0; i < n; i++) {
        var m = eval_("(function(){ var x = 10; return function(n) { return x+n; }; })(window);");
        m(5);
    }
}
</script>
<button onclick="closureTest(1000)">Run</button>

In this case, the closure no longer contains __text but does still contain arguments[0] with the string passed to eval_. 在这种情况下,闭包不再包含__text,但仍包含带有传递给eval_的字符串的arguments [0]。

About the best I could come up with is the following, which deletes the argument to eval_ after processing it, a side effect is that the module being defined now also appears in the closure as a variable called module. 我能想到的最好的方法是,在处理完后删除eval_的参数,其副作用是现在正在定义的模块在闭包中也显示为称为模块的变量。

<script>
function closureTest(n) {
    function eval_() {
        var module = eval(arguments[0]);
        delete arguments[0];
        return module;
    }
    for (var i = 0; i < n; i++) {
        var m = eval_("(function(){ var x = 10; return function(n) { return x+n; }; })(window);");
        m(5);
    }
}
</script>
<button onclick="closureTest(1000)">Run</button>

Is there a better way to prevent the closure retaining a copy of the argument passed to eval_? 有没有更好的方法来防止闭包保留传递给eval_的参数的副本?

[EDIT] Completely missed the point of the question. [编辑]完全错过了问题要点。

Short answer: You cannot. 简短答案:您不能。 As you are aware, a closure maintains the environment state from which it was created; 如您所知,闭包会维护从中创建闭包的环境状态。 there's no way to "break out" of a closure scope hierarchy. 没有办法“突破”闭包作用域层次结构。

When you call m() you are not calling it within a global context, but rather part of a chain of environments of, not only the eval_ closure but also closureTest as well -- You can see your returned eval'ed function also has access to the i and n vars defined in closureTest . 当您调用m()您不是在全局上下文中调用它,而是一系列环境的一部分,不仅是eval_闭包,而且还有闭包closureTest -您都可以看到返回的eval'ed函数也具有访问权限到closureTest定义的in var。

So, you cannot restrict or break out of a closure. 因此,您不能限制或打破封闭。 However, if you define a new variable in your new scope with the same name as a variable from a previous closure you lose direct access to that. 但是,如果您在新作用域中定义了与先前闭包中的变量同名的新变量 ,则将无法直接访问该变量。 Therfore, your middle example is as close as you can get: 因此,您的中间示例尽可能接近:

function closureTest(n) {
    function eval_() {
        return eval(arguments[0]);
    }
    for (var i = 0; i < n; i++) {
        var m = eval_("(function(){ var x = 10; return function(n) { return x+n; }; })(window);");
        m(5);
    }
 }

Here, your returned eval'ed function cannot access eval_ 's arguments since it's own arguments have overridden it (it does, however, still have access to i and n from the for loop). 在这里,您返回的eval'ed函数无法访问eval_的参数,因为它自己的arguments已覆盖它(但是,确实可以从for循环访问in )。 This means, functionally, that eval'ed string cannot access the arguments passed to eval_ . 从功能上讲,这意味着评估字符串无法访问传递给eval_的参数。

Notes: 笔记:

  • Yes, when you set a breakpoint in DevTools you can inspect the parent closures however that does not impact the fact that the executing function cannot directly access eval_ 's `arguments[0] . 是的,当您在DevTools中设置断点时,您可以检查父闭包,但这不会影响执行函数不能直接访问eval_的`arguments [0]的事实
  • Also, the function could get the string of the upper functions using arguments.callee.caller.toString(); 同样,该函数可以使用arguments.callee.caller.toString();获取上层函数的字符串arguments.callee.caller.toString(); etc. This still doesn't allow the function direct access to redefined vars, but thought it was worth mentioning. 等等。这仍然不允许函数直接访问重新定义的var,但是认为值得一提。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用Closure Compiler优化Javascript并保留函数名称? - How do I optimize Javascript with Closure Compiler and keep function names? 如何防止此 javascript 被评估? - How do I prevent this javascript from being evaluated? 如果我传递参数,则不会调用javascript函数 - javascript function is not being called if i pass a argument 如何阅读 Javascript 闭包语法? - How do I read Javascript Closure Syntax? 如何重用此JavaScript超时关闭? - How do I reuse this JavaScript timeout closure? Javascript - 使用参数引用全局函数的匿名函数中的闭包 - 我如何使用preventDefault? - Javascript - closure in anonymous function referencing a global function using arguments - how do i use preventDefault? 如何在JavaScript中的函数(本身就是一个参数)中传递参数 - How argument is being passed in the function(which itself is an argument) in JavaScript javascript:如何将参数传递给对象内的私有函数? - javascript: how do I handover an argument to a private function within an object? 如何预防,停止或终止Javascript功能? - How do I prevent, stop, or kill Javascript function? 在JavaScript中,如何使用字符串参数访问对象上的函数? - In JavaScript, how do I access a function on an object using a string argument?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM