【问题标题】:Javascript: typeof says "function" but it can't be called as a functionJavascript:typeof 表示“函数”,但不能作为函数调用
【发布时间】:2018-10-29 11:20:28
【问题描述】:

这次我真的对Javascript感到困惑:

var x = Array.prototype.concat.call;
typeof x; // function
x(); // Uncaught TypeError: x is not a function

这到底是怎么回事?


如果有帮助,我还注意到:

  • x([1,2],[3,4]) 也不起作用

  • toString 也认为是函数:

    Object.prototype.toString.call(x); // "[object Function]"
    
  • Array.prototype.concat.apply 也会发生这种情况。

  • 当它被强制作为表达式时它也不起作用:

    (0, Array.prototype.concat.call)([1,2],[3,4]); // Same TypeError
    

在 Chrome 和 Node 中测试。

【问题讨论】:

  • 这只是错误信息中的一个错误(不是函数的东西是x()this,而不是x)。 Firefox 是正确的,例如:“TypeError: Function.prototype.call called on incompatible undefined”
  • spec 表示应该抛出 TypeError,但不是特定消息应该是什么。
  • @Ry- 你能澄清一下吗?请注意,x([1,2],[3,4]) 也不起作用。
  • @Hamsterrific:Array.prototype.concat.call === Function.prototype.call。重要的是你如何调用call——它的this 值决定了被调用的函数。 x()this 值为 undefinedvar x = Function.prototype.call.bind(Array.prototype.concat); 可能是有意为之(但错误消息仍然是错误的,与var x = Array.prototype.concat.bind([]) 相比仍然会更好)。
  • toString = Function.prototype.toString; toString() -> Uncaught TypeError: Function.prototype.toString requires that 'this' be a Function 看起来错误不一致。

标签: javascript function typeerror


【解决方案1】:

该错误具有误导性。 x 一个函数,但是它丢失了引用的函数(concat),这会抛出一个错误

在 firefox 上运行会给出更具描述性的错误

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Called_on_incompatible_type

它的意思是call 函数没有任何绑定。 就像你拿一个像这样的对象:

const a = {
  b: 2,
  test() {
    console.log('hi', this.b);
  }
};
const c = a.test;
c();

你会得到hi undefined,因为你失去了函数与b的关系。

您可以通过 c.bind(a)()c.call(a) 来解决此问题

call 函数的行为类似。 每个函数都是一样的,伪代码看起来像这样:

class Function {
  constructor(functionDefinition) {
    this.functionDefinition = functionDefinition;
  }

  call(newThis, ...args) {
    // take this.functionDefinition, and call it with `this` and `args`
  }
}

由于您要提取调用函数,它会丢失与之关联的函数对象。

您可以通过将 concat 绑定到函数或使用 call on call 来解决此问题 :-)

const a = []
const boundFn = a.concat.call.bind(a.concat)
console.log(boundFn([3], [1,2]));

// Or, you can use `call` to pass in the concat function
const callFn = a.concat.call;
console.log(callFn.call(a.concat, [4], [1,2]))

【讨论】:

  • 谢谢!我现在明白了,感谢您的回答,尤其是上面 Ry- 的评论。建议:你可以强调每个函数的调用函数都是一样的,重要的是调用的this(我知道你已经简单说了,但这对我来说是症结所在,我认为可以更明确地说) :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多