是否可以访问函数的关闭?

IT技术 javascript scope closures
2021-01-23 00:53:16

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

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

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

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

//access y here with x somehow
4个回答

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

但是,您可以通过 getter/setter 授予访问权限。

您可能想看看Stuart Langridge关于闭包的演讲非常值得推荐的还有 Douglas Crockfords Explanations。你可以用闭包做很多花哨的东西;)

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

不,除非你暴露它:

var x = function(){
        var y = 5;

        return {             
           getY: function(){
              return y;
          },
          setY: function(newY){
             y = newY;
          }    
       }
   }


    x.setY(4);

您可以编辑警报功能:

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 希望能够检查闭包中的所有变量。
2021-03-14 00:53:16
我只想说明一点,闭包并非完全是黑匣子。
2021-04-09 00:53:16

如果你在前端环境中,并且如果你可以在之前的脚本标签中执行你自己的 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而不是内联代码,它会有点困难。<script>MutationObserver 看到标签时,调整它或用一个新的脚本标签替换它,它textContent是原始脚本内容加上您的修改为了获得原始内容,<script>在进行所需的替换之前,要么检查内置内容并对其替换进行硬编码,要么获取脚本标记的文本(可能将请求从另一台服务器上反弹以避免 CORS 问题)插入打过补丁的代码。(或者,如果您有服务器,您可以让服务器执行文本替换 - 然后,您需要做的就是src将插入的脚本标记的更改为指向您的服务器而不是默认位置。)

哦有趣,所以“+ 脚本”只是跳过第一个,对,没有意识到..mutationobserver 是否遍历所有正在加载的脚本?在生产中应该使用 document.querySelectorAll,还是没有必要?
2021-03-13 00:53:16
有趣,你能详细说明一下“脚本+脚本”部分吗?我注意到没有它就无法工作,我只是不知道它的作用
2021-03-15 00:53:16
哦,你的意思是选择器,这就是注入的上层脚本如何识别下层脚本是否存在。script + script是一个 CSS 选择器,它将匹配<script>紧跟另一个<script>标签的标签。是否mutationobserver 迭代所有正在加载的脚本?一次只能创建一个脚本。观察者将在脚本加载后,在脚本被放入 DOM 之后,在脚本执行之前立即运行它的回调。
2021-03-27 00:53:16
您可以使用任何想要标识所需元素的方法。我喜欢querySelectorAll,但任何能完成你正在寻找的逻辑的东西都会起作用
2021-04-05 00:53:16
这只是将内置页面脚本标记与您的扩展程序/用户脚本/等注入页面的脚本区分开来的示例。实际上,上面的脚本标签可能不存在,因为来自浏览器的其他东西将“运行”该代码。
2021-04-06 00:53:16