在函数中覆盖函数

Overwrite a function in a function

我正在想办法扩展:

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 相同。就是做不到。

内部函数包含在您无权访问的闭包中。不幸的是(与 "nothing is impossible" 意识形态相反)这不能在运行时完成。

这就是您所说的 'private' 函数。该函数就像任何其他变量一样存储。在 JavaScript 中,这通常意味着它必须是 'local scope'(而不是成员变量),因此它不能被覆盖。 (如果他们使用了 this.functionName... 那么您可以更轻松地覆盖)

好消息是,有一个 hack 似乎是跨浏览器兼容的。 (在 IE 11 中测试,仿真选项回到 IE 5!)在 JavaScript 中,您可以替换函数本身的实际 'source code'。 (与适当的覆盖有点不同)

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"

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