【问题标题】:Is it possible to gain access to the closure of a function?是否可以访问函数的闭包?
【发布时间】:2012-06-26 22:01:10
【问题描述】:

javascript 中的函数通过保持一个(隐藏的)链接到它的封闭范围来形成一个闭包。

当我们拥有函数(作为变量值)时,是否可以通过编程方式访问它?

真正的目标是理论上的,但演示可能是列出闭包的属性。

var x = (function(){
   var y = 5;
   return function() {
       alert(y);
   };
})();

//access y here with x somehow

【问题讨论】:

  • 代码示例可以更好地解释您的确切问题
  • @Blaster:试试看。它行不通。 y 不是 x 的属性。
  • @Blaster 那是因为这就是“x”函数的作用。您的示例也会在控制台上记录 5。
  • @Blaster:那是alert(y) 向您展示5console.log() 显示 TypeError: Cannot read property 'y' of undefined
  • 好的,谢谢大家现在明白了 :)

标签: javascript scope closures


【解决方案1】:

这是关闭的(其中一个)目的 - 保持信息的私密性。由于该函数已经被执行,它的作用域变量不再可以从外部获得(而且从来没有)——只有在它的作用域中执行的函数(仍然)可以访问。

但是您可以通过 getter/setter 提供访问权限。

您可能想查看Stuart Langridge's talk 关于闭包的信息。 Douglas Crockfords Explanations 也非常值得推荐。你可以用闭包做很多花哨的事情;)

编辑: 你有几个选项来检查闭包:在 webdeveloper 控制台中观察对象,或者(就像我经常做的那样)返回一个调试函数,它将所有私有变量转储到控制台。

【讨论】:

    【解决方案2】:

    不,除非你暴露它:

    var x = function(){
            var y = 5;
    
            return {             
               getY: function(){
                  return y;
              },
              setY: function(newY){
                 y = newY;
              }    
           }
       }
    
    
        x.setY(4);
    

    【讨论】:

      【解决方案3】:

      您可以编辑警报功能:

      var x = (function(){
         var y = 5;
         return function() {
             alert(y);
         };
      })();
      
      var oldAlert = alert;
      
      alert = function (x) {
          oldAlert(x);
          window.y = x;
      }
      
      x();
      
      console.log(y); // 5
      

      或者,如果您拥有代码,则可以使用标准的 getter 和 setter。

      【讨论】:

      • 嘿,+ 1 用于跳出框框思考。我认为 OP 希望能够检查闭包中的所有变量。
      • 我只想说明一点,闭包并不完全是黑盒子。
      【解决方案4】:

      如果您在前端环境中,并且可以在 prior 脚本标记中执行自己的 Javascript,则可以选择附加 MutationObserver,等待所需的脚本标记监视插入到文档中,并在插入时立即更改其代码,以便公开您要检查或更改的功能。这是一个例子:

      <script>
      new MutationObserver((mutations, observer) => {
        // Find whether the script tag you want to tamper with exists
        // If you can't predictably identify its location,
        // you may have to iterate through the mutations' addedNodes
        const tamperTarget = document.querySelector('script + script');
        if (!tamperTarget) {
          return;
        }
        observer.disconnect();
        console.log('Target script getting tampered with');
        tamperTarget.textContent = tamperTarget.textContent.replace(
          'return function',
          'window.y = y; return function'
        );
        setTimeout(() => {
          console.log("Hacked into tamper target's script and found a y of", y);
          console.log('Could also have replaced the local y with another value');
        });
      })
        .observe(document.body, { childList: true });
      
      </script>
      
      <script>
      console.log('Tamper target script running');
      var x = (function(){
         var y = 5;
         return function() {
             alert(y);
         };
      })();
      </script>

      这可能不是您的想法,但这种方法是破解闭包的极少数方法之一,当页面运行您无法更改的代码时,这是一种有用的技术。

      如果另一个脚本有一个src 而不是内联代码,那就有点难了。当 MutationObserver 看到 &lt;script&gt; 标签时,调整它或将其替换为新的脚本标签,其 textContent 是原始脚本内容加上您的修改。为了获得原始内容,要么检查内置的&lt;script&gt; 并对其替换进行硬编码,要么获取脚本标签的文本(可能将请求从另一台服务器反弹以避免 CORS 问题),然后才能进行需要替换并插入修补的代码。 (或者,如果您有一个服务器,您可以让 server 进行文本替换 - 然后,您需要做的就是更改插入脚本标记的 src 以指向您的服务器,而不是比默认位置。)

      【讨论】:

      • 有趣,你能详细说明一下“脚本+脚本”部分吗?我注意到没有它就行不通,我只是不知道它有什么作用
      • 这只是将内置页面脚本标记与您的扩展程序/用户脚本/等注入页面的脚本区分开来的示例。实际上,上面的 script 标签可能不存在,因为来自浏览器的其他东西会“运行”该代码。
      • 哦,很有趣,所以“+ 脚本”只是跳过了第一个,对,没有意识到.. 变异观察者是否遍历所有正在加载的脚本?在生产中应该使用 document.querySelectorAll,还是没有必要?
      • 哦,你说的是选择器,注入的上层脚本就是这样识别下层脚本是否存在的。 script + script 是一个 CSS 选择器,它将匹配一个 &lt;script&gt; 标记,该标记紧跟另一个 &lt;script&gt; 标记。 mutationobserver 是否遍历所有正在加载的脚本? 一次只能创建一个脚本。观察者将在脚本加载后、放入 DOM 之后、脚本执行之前立即运行其回调。
      • 你可以使用任何你想要的方法来识别你想要的元素。我喜欢querySelectorAll,但任何能够实现您正在寻找的逻辑的东西都会起作用
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多