9

I have an EventListener that listens to the entire document and records keystrokes, but I want to remove this Listener when certain conditions are met.

The following is a snippet of my code:

document.addEventListener('keyup', function(e) {
    var letter_entered = String.fromCharCode(e.keyCode).toLowerCase();
    player.makeGuess(letter_entered);

    if(player.win_status === true || player.lose_status === true) {
        document.removeEventListener('keyup', arguments.callee, false);
    }
});

This works, however according to the Mozilla Developer Docs this method has been deprecated.

I'm aware that I can simply name the function, but is there an alternative that would allow me to continue using the unnamed function?

leppie
  • 115,091
  • 17
  • 196
  • 297
MitulP91
  • 1,279
  • 2
  • 12
  • 24

2 Answers2

14

Use the following process:

  • Create a variable
  • Assign an anonymous function to the variable
  • Invoke it with the variable reference
  • The anonymous function references itself using the variable name

Use it as such:

   var foo = function(e)
    {
    "use strict";
    console.log(e);
    document.removeEventListener('keyup', foo, false);
    }

document.addEventListener('keyup', foo);

You can solve this problem easily using the y combinator:

function y(f) {
    return function () {
        return f.bind(null, y(f)).apply(this, arguments);
    };
}

Now you can rewrite your code as follows:

document.addEventListener("keyup", y(function (callee, e) {
    player.makeGuess(String.fromCharCode(e.keyCode).toLowerCase());
    if (player.win_status || player.lose_status) document
        .removeEventListener("keyup", callee);
}));

That's all folks.

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • Is this different from `function y(f) { return function yf() { return f.bind(null, yf).apply(this, arguments)`? –  Oct 22 '14 at 18:34
  • Yes, but the entire point of the OP's question is not to use named functions. – Aadit M Shah Oct 22 '14 at 19:23
  • 2
    Cool stuff but it doesn't answer the question which is in the title. In fairness, the title is wrong. :) But I was actually looking for the answer to a generic alternative for `arguments.callee` and this isn't it. – Stijn de Witt Apr 17 '17 at 20:18
  • Javascript is such a weird language, thanks for this solution! I didn't know it was possible to do that. – rez Mar 11 '20 at 15:21
3

Use another anonymous function as a wrapper to store a named function (callee shim) to your original function:

document.addEventListener('keyup', (function(e)
  {
  var aFunction = function()
    {
    var letter_entered = String.fromCharCode(e.keyCode).toLowerCase();
    player.makeGuess(letter_entered);
    };

  if(player.win_status === true || player.lose_status === true) 
    {
    document.removeEventListener('keyup', window, false);
    }
  else
    {
    aFunction();
    }
  }
), false);

References

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265