覆盖函数中的函数

Overwrite a function in a function

本文关键字:函数 覆盖      更新时间:2023-09-26

我正试图找出如何扩展:

var outdatedBrowser = function(options) {
  function startStylesAndEvents() {
   console.log("bleh");
  }
}

我试图在不接触库的源代码的情况下覆盖函数startStylesAndEvents:https://github.com/burocratik/outdated-browser/blob/develop/outdatedbrowser/outdatedbrowser.js

所以当我打电话给时

outdatedBrowser({
    bgColor: '#f25648',
    color: '#ffffff',
    lowerThan: 'transform',
    languagePath: 'your_path/outdatedbrowser/lang/en.html'
})

它使用startStylesAndEvents函数,它使用我的而不是他们的。。。

谢谢!

不修改原始源代码?你不能。

所有JavaScript作用域都基于函数(暂时忽略letconstclass)。如果一个值是在函数内部声明的,则除非从函数返回或修改某些外部值,否则无法在该函数外部访问该值。

例如,想象这样一个函数:

function doStuff() {
  var times = 10;
  for (var i = 0; i < times; i++) {
    doThing(i);
  }
}

您的问题在语义上与询问如何更改times完全相同。这是不可能的。

内部函数包含在一个闭包中,您无法访问它。不幸的是(与"没有什么是不可能的"思想相反),这无法在运行时完成。

这就是所谓的"私有"函数。该函数的存储方式与其他任何变量一样。在JavaScript中,这通常意味着它必须是"本地范围"(而不是成员变量),因此不能重写。(如果他们使用了this.functionName…那么你可以更容易地覆盖)

好消息是,有一个黑客似乎是跨浏览器兼容的。(在IE 11中测试,模拟选项返回IE 5!)在JavaScript中,您可以替换函数本身的实际"源代码"。(与正确的超控有点不同)

var newInnerFunction = function () { // intentionally anonymous for use in eval
}
var overriddenFunction = eval(
    outdatedBrowser.toString() // expecting outdatedBrowser to be anonymous for use in eval
    .replace('{', '{var startStylesAndEvents=' + newInnerFunction.toString() + ';')
)

注意,outdatedBrowser是一个匿名函数(简称function())。如果它被命名,那么eval的使用将产生副作用,将新函数添加到其原始名称下的命名空间中。如果这是一个问题,一个额外的replace可以解决这个问题。

很可能,你做不到。但这并非完全不可能。

例如,如果在其作用域对象已泄漏到外部的with语句中调用startStylesAndEvents

var scope = Object.create(null);
var outdatedBrowser = function(options) {
  function startStylesAndEvents() {
     console.log("bleh");
  }
  with(scope) {
    startStylesAndEvents(); // You expect this to be the private function above
  }
}
outdatedBrowser(); // "bleh"

然后,您可以劫持对startStylesAndEvents:的呼叫

scope.startStylesAndEvents = function() {
  console.log("blah");
};
outdatedBrowser(); // "blah"

当然,不要这样做。这是邪恶的,缓慢的,在严格的模式下是不允许的。