【问题标题】:Why I can't pass console.log as a callback argument in Chrome (and Safari)?为什么我不能在 Chrome(和 Safari)中将 console.log 作为回调参数传递?
【发布时间】:2015-11-01 19:07:57
【问题描述】:

以下 sn-p 在 Firefox 中运行时会在 Chrome(和 Safari)中产生错误。

我希望在 javascript 控制台中显示 2 个数字,但在 Chrome 中我只得到第一个,然后是 Uncaught TypeError: Illegal invocation

// a generic promise that return a random float
var makePromise = function() {
  return $.Deferred().resolve(Math.random());
}

// This works in all browsers
makePromise().then(function(d) {
  console.log(d);
});
// This works in firefox only
makePromise().then(console.log);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

为什么会这样?

旁注:我的问题与this question不同。

更新

感谢 cmets 并回答使用console.log 作为需要做的回调

makePromise().then(console.log.bind(console));

【问题讨论】:

  • 可能是一些 webkit 安全限制。
  • console.log.bind(console)。没有什么能保证它是一个“静态”函数。
  • 正如@zerkms 所说,console.log.bind(console)。令人惊奇的是console.log 应该在 FF 中工作。

标签: javascript function google-chrome firefox jquery-deferred


【解决方案1】:

尝试使用deferred.resolveWith()

// a generic promise that return a random float
var makePromise = function() {
  // set `this` to `window.console` , 
  // pass arguments within array
  return $.Deferred().resolveWith(window.console, [Math.random()]);
}

// This works in all browsers
makePromise().then(console.log)
//.then(function(d) {
//  console.log(d);
//});
// This works in firefox only
makePromise().then(console.log);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>

【讨论】:

  • makePromise 只是一个最小的可重现示例。我不想更改所有返回承诺的代码,只是为了调试它。
【解决方案2】:

在 chromebook 中,我可以将问题复制如下:

function do4(cb){ cb(1); cb(2); cb(3); cb(4); }

do4(console.log)
VM1491:2 Uncaught TypeError: Illegal invocation
    at do4 (<anonymous>:2:19)
    at <anonymous>:2:12
    at Object.InjectedScript._evaluateOn (<anonymous>:905:140)
    at Object.InjectedScript._evaluateAndWrap (<anonymous>:838:34)
    at Object.InjectedScript.evaluate (<anonymous>:694:21)do4 @ VM1491:2(anonymous function) @ VM1552:2InjectedScript._evaluateOn @ VM1288:905InjectedScript._evaluateAndWrap @ VM1288:838InjectedScript.evaluate @ VM1288:694

但这很好用,确实指出了问题所在:

do4(console.log.bind(console))
VM1491:2 1
VM1491:2 2
VM1491:2 3
VM1491:2 4

这是为什么呢?

在 chrome 中,console 本身返回原型 ConsoleObject, 看:

console
Console {} memory: MemoryInfo__proto__: Console

console 视为Object 可能看起来很奇怪,但确实如此。 console 有几个其他较少使用的方法,这些方法不像 console.log 那样经常使用,但在 MDN Console DocsChrome Console Docs 中有记录

在这里,我们遇到了一个可以迷惑人们的大型 Javascript 主义:

Javascript 方法是未绑定的方法。也就是说,这些方法不绑定到任何特定的对象。

所以console.log 是一个函数,但它只是函数,不保留thisconsole 的绑定。

变量绑定在函数代码中由一个神奇的this 变量引用,可以使用function.bindfunction.apply 设置。

console.log()被调用时,JS将函数代码的this绑定到console对象。但是当console.log只是作为函数传递时,它不做绑定,让其他代码可以更灵活的使用它。这种行为不方便使用 console.log 和许多其他方法,但在某些情况下增加了所需的灵活性。

【讨论】:

    猜你喜欢
    • 2018-06-14
    • 1970-01-01
    • 2012-03-27
    • 1970-01-01
    • 2016-08-16
    • 1970-01-01
    • 2021-10-10
    相关资源
    最近更新 更多