7 votes

Function.prototype.call comportement inattendu lorsqu'il est assigné à une variable

Le code suivant appelle console.log imprime "hello" :

console.log.call(console, "hello")

Cependant, le code ci-dessous provoque une erreur de type (TypeError) :

x = console.log.call
x(console, "hello")

jets :

Uncaught TypeError: x is not a function
    at <anonymous>:1:1

Quelqu'un peut-il expliquer ce scénario étrange ?

(Bien sûr, c'est la même chose pour les deux call y apply )

7voto

SLaks Points 391154

.call obtient la fonction à appeler à partir de son this paramètre.

Vous l'appelez via x sans this il n'a donc pas de fonction à appeler (ou plutôt, il essaie d'appeler le paramètre window ) et génère une erreur.

Vous devez lier votre x à la variable log fonction :

x = console.log.call.bind(console.log);

Bonus : .call provient de Function.prototype Il est identique quelle que soit la manière dont vous y accédez. C'est pourquoi, Function.call.bind(console.log) fonctionne également (parce que Function est une fonction et a donc .call ). De même que les Date.call .

3voto

nem Points 2882

Note : J'utiliserai apply au lieu de call dans ma réponse juste parce que la formulation/lecture est un peu moins confuse, mais la même réponse s'applique à call .

Vous pouvez imaginer apply ressemble à quelque chose comme ça :

Function.prototype.apply = function apply(context, rest) {
  // `this` in here is the function object on which we call `apply` as a method
  // we then invoke whatever is bound to `this` (it should be the function that was "applied")
  // and change its context and pass the rest of the arguments
  // Note: I'm using `call` since we don't have access to native function  code that can call a function with an overwritten context
  this.call(context, ...rest)
}

Lorsque vous appelez le apply (ou toute autre fonction d'ailleurs) en tant que méthode sur un objet fonction ( les fonctions sont des objets de première classe ), this à l'intérieur de celui-ci est lié à la fonction (objet) sur laquelle vous avez appelé apply (il s'agit d'une des règles sur la façon dont le contexte est lié en JS lorsqu'une fonction est appelée en tant que méthode d'un objet)

Function.prototype.apply = function apply(context, rest) {
  this.call(context, ...rest)
  // `this` is the function that `call` invokes
  // in the example bellow, `this` is `console.log`
  // so this function will do `console.log.call(console, 'example')`
}

console.log.apply(console, ['example'])
// ^^^^^^^^ console.log is the context because we are calling `apply` on it, with the dot (.) notation

Cependant, lorsque vous stockez le apply dans une variable et l'invoquer ensuite, alors la règle pour la fonction this contraignant est d'être undefined (en mode strict ou en mode global window sinon) et il n'y a donc pas de fonction à appeler sous le capot.

Function.prototype.apply = function apply(context, rest) {
  this.call(context, ...rest)
  // using the example bellow
  // `this` is `undefined` now because `apply` was called like a regular function, not a method
  // which means the code bellow does `undefined.call(console, 'example')`
}

// calling a function as a normal function (not a method via the dot notation), makes `this` be `undefined`
// therefore `apply` doesn't have a function which to call with an overwritten context
let apply = console.log.apply;
apply(console, ['example']) // error, `this.call is not a function`

0voto

Thomas Brd Points 375

En fait, le scénario est normal. Vous devez déclarer x en tant que fonction qui encapsule votre logique comme suit :

ps : ...args est l'opérateur d'étalement en javascript ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax )

x = (...args) => console.log.call(...args)
x(console, "hello")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X