Почему эти реализации классов не имеют идентичного поведения?

1

Я пытался написать доказательство концепции для класса, расширяющего Function, чтобы продемонстрировать конструктор функций, который можно было бы инициализировать на основе другой функции, и отразить this и arguments следующим образом:

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)

Тем не менее, я думал, что это приведет к идентичному поведению, основанному на моем понимании call и apply:

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)

Может кто-то объяснить, что я недопонимаю, или почему это не так?

  • 0
    Посмотрите здесь гораздо более простой способ расширения Function
  • 0
    @Bergi Берджи, пока я проголосовал за твой ответ, так как он был интересным, он точно не использует наследование. Помимо принудительного использования в качестве конструктора, ваша ExtensibleFunction основном отбрасывает инстанцируемое свойство this , которое, кажется, обходит проблему, а не решает ее «удовлетворяющим» способом, заключая вас в кавычки.
Показать ещё 2 комментария
Теги:
call
function
metaprogramming

2 ответа

1
Лучший ответ
Uncaught TypeError: call is not a function

так что что-то не так с функцией call().

Обратите внимание, что это сообщение вводит в заблуждение, это не call который не является функцией, а то, что call вызов.

Мое понимание заключалось в том, что если call() не был частью выражения вызова, его первым аргументом стала бы вызываемая функция

Нет. Эта функция вызывается не всегда this контекст call вызова, и ничего, что меняет это, когда call не вызывается как метод. Вам нужно сделать call.call(functor, context,...args).

  • 0
    call.call(functor, context, ...args) ли call.call(functor, context, ...args) functor.call(context, ...args) ?
  • 0
    Это эквивалентно, да (но нет, он не осуществляет внутренний доступ и не вызывает метод .call functor )
1

Вы вызываете 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)
  • 0
    call.call(...) ? Это была проблема все время? facepalm Но Function.call и Function.prototype.call одинаково действительны, поскольку Function instanceof Function , поэтому он будет иметь call метода-члена, являющийся экземпляром самого себя.
  • 0
    @PatrickRoberts: Верно; Я просто думаю, что это вводит в заблуждение, как передача {}.toString.call или что-то еще. К счастью, в этом нет необходимости, поскольку вы можете просто использовать свой оригинальный метод.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню