Search code examples
javascriptecmascript-6javascript-objectsdom-eventskeydown

How to iterate through the keys of a event object?


I am debugging. I want to print all the fields of a keydown event:

 print(tag, stuff={}, newline=true){
    this.key_transcript_plane.innerHTML += "(" + tag;
    for (let [key, value] of Object.entries(stuff)) {
      let key_string = key ? "<em>"+key.toString()+"</em>" : "<em>undefined</em>";
      let value_string = value ? value.toString() : "<em>undefined</em>";
      this.key_transcript_plane.innerHTML += "&nbsp &nbsp <em>" + key_string + ":</em>" + value_string;
    }
    this.key_transcript_plane.innerHTML += ")";
    if(newline) this.key_transcript_plane.innerHTML += "<br>";
  }

and,

   key_input_plane.addEventListener("keydown", (e) => {
      this.print('keydown', e);
    });

But this is all that it prints:

(keydown    isTrusted:true)

However, if I set a breakpoint in the very same print function, and ask Chrome what the value of the 'stuff' object is, I get this:

> stuff
KeyboardEvent {isTrusted: true, key: "a", code: "KeyA", location: 0, ctrlKey: false, …}
altKey: false
bubbles: true
cancelBubble: false
cancelable: true
charCode: 0
code: "KeyA"
... and a hundred more things

Which you might agree is just a little bit different ..

The console shows 'isTrusted' as does my 'print()' function, but then goes on with 'key', 'code' etc. What does the console know that I don't? Or more to the point, how can I print all of the keys and values for this event 'e'?

Of course I want to know the 'key' and 'code' but also all the other stuff Chrome puts in there on the first level, even things I can't specifically ask for because I don't know what Chrome has done. (Being the whole point of the matter.)

Note, Currently I'm not intending to ask about recursive descent into the value here. I'm just looking to print the top level keys and their values.


Solution

  • The problem with what you are trying to do is that you want to iterate over properties that are not enumerable or they are not owned by the object.

    "Enumerable properties are those properties whose internal enumerable flag is set to true, which is the default for properties created via simple assignment or via a property initializer"

    "Ownership of properties is determined by whether the property belongs to the object directly and not to its prototype chain."

    You can use something like that to get all the properties.

    var typeA = new KeyboardEvent('keydown', {key:'a'});
    
    var SimplePropertyRetriever = {
      getOwnAndPrototypeEnumerablesAndNonenumerables: function(obj) {
          return this._getPropertyNames(obj, true, true, this._enumerableAndNotEnumerable);
      },
      _enumerableAndNotEnumerable: function(obj, prop) {
          return true;
      },
      // Inspired by http://stackoverflow.com/a/8024294/271577
      _getPropertyNames: function getAllPropertyNames(obj, iterateSelfBool, iteratePrototypeBool, includePropCb) {
          var props = [];
    
          do {
              if (iterateSelfBool) {
                  Object.getOwnPropertyNames(obj).forEach(function(prop) {
                      if (props.indexOf(prop) === -1 && includePropCb(obj, prop)) {
                          props.push(prop);
                      }
                  });
              }
              if (!iteratePrototypeBool) {
                  break;
              }
              iterateSelfBool = true;
          } while (obj = Object.getPrototypeOf(obj));
    
          return props;
      }
    };
    
    SimplePropertyRetriever.getOwnAndPrototypeEnumerablesAndNonenumerables(typeA)
    

    You must read this article for more details.

    Enumerability and ownership of properties