为什么这些 class 实现没有相同的行为?

Why don't these class implementations have identical behavior?

我试图为扩展 Function 的 class 编写概念证明,以演示可以基于另一个函数初始化的函数构造函数,并反映 thisarguments 以下列方式:

class Handle extends Function {
  constructor(functor) {
    super("functor", "slice", `
      "use strict";
      return functor
        .call(this, ...slice.call(arguments, 2));
    `);

    return this.bind(this, functor, Array.prototype.slice)
  }
}

let handle = new Handle(function test() {
  console.log(this instanceof Handle, arguments.length)
})

console.log(handle instanceof Handle, handle.length)

handle(1, 2, 3)

但是,根据我对 callapply 的理解,我认为这会产生相同的行为:

class Handle extends Function {
  constructor(functor) {
    super("instance", "call", "slice", `
      "use strict";
      return call(this, instance, ...slice.call(arguments, 3));
    `);

    return Function.bind
      .call(this, functor, this, Function.call, Array.prototype.slice)
  }
}

let handle = new Handle(function test() {
  console.log(this instanceof Handle, arguments.length)
})

console.log(handle instanceof Handle, handle.length)

handle(1, 2, 3)

这抛出

Uncaught TypeError: call is not a function
  at Function.eval (eval at Handle (js:4), <anonymous>:5:14)

所以 call() 函数有问题。我的理解是,如果 call() 不是调用表达式的一部分,它的第一个参数将成为被调用的函数,其余参数将成为函数的上下文和参数,有点像 Function.call.call(this, instance, ...slice.call(arguments, 3)) 会做:

class Handle extends Function {
  constructor(functor) {
    super("instance", "call", "slice", `
      "use strict";
      return Function.call.call(this, instance, ...slice.call(arguments, 3));
    `);

    return Function.bind
      .call(this, functor, this, Function.call, Array.prototype.slice)
  }
}

let handle = new Handle(function test() {
  console.log(this instanceof Handle, arguments.length)
})

console.log(handle instanceof Handle, handle.length)

handle(1, 2, 3)

谁能解释一下我的误解,或者为什么情况似乎并非如此?

您正在调用 Function.call(我认为使用 Function.prototype.call 会更正确)而没有 this。不过,它需要一个,因为 this 值是它调用的函数。该问题的一个较短示例:

var call = Function.prototype.call;
call();

也许你打算 call.call(this, …)

class Handle extends Function {
  constructor(functor) {
    super("instance", "call", "slice", `
      "use strict";
      return call.call(this, instance, ...slice.call(arguments, 3));
    `);

    return Function.bind
      .call(this, functor, this, Function.call, Array.prototype.slice)
  }
}

let handle = new Handle(function test() {
  console.log(this instanceof Handle, arguments.length)
})

console.log(handle instanceof Handle, handle.length)

handle(1, 2, 3)

Uncaught TypeError: call is not a function

so it's something wrong with the call() function.

请注意 ,不是 call 不是函数,而是 call 试图调用的东西。

My understanding was that if call() wasn't part of a call expression, its first argument would become the function being called

没有。被调用的函数始终是 call 调用的 this 上下文,当 call 未作为方法调用时,没有任何改变。你需要做 call.call(functor, context, ...args).