Foreword
Recently, I was in charge of the Quill project. There was a requirement for the product to initiate a request when the editor presses the enter key to change the line, and at the same time record the line where the current cursor is located.
But once Quill presses the enter key to change the line, the cursor changes, and the line before the line break cannot be found. So we have to ask us to send the request before the new line, and then record the line, which can be processed later.
A problem occurred
Quill can add keyboard processing functions, through the quill.addBinding
function or in quill’s keyboard
configuration, such as listening to the enter key
new Quill('#editor', {<!-- --> modules: {<!-- --> keyboard: {<!-- --> bindings: {<!-- --> 'enter':{<!-- --> key: 'enter', handler () {<!-- --> //todo } } } } } })
The official documentation explains
This added custom keyboard event will be inserted after the current default keyboard event.
If you want to insert before the current default keyboard event, what should you do?
After reading the official documentation, I couldn’t find any instructions.
So, let’s take a look at the source code to see how it is added.
class Keyboard extends Module {<!-- --> constructor(quill, options) {<!-- --> super(quill, options); this.bindings = {<!-- -->}; Object.keys(this.options.bindings).forEach((name) => {<!-- --> // Important if (name === 'list autofill' & amp; & amp; quill.scroll.whitelist != null & & !quill.scroll.whitelist['list']) {<!-- --> return; } if (this. options. bindings[name]) {<!-- --> this.addBinding(this.options.bindings[name]); } }) // ...omitting part of the code } addBinding(key, context = {<!-- -->}, handler = {<!-- -->}) {<!-- --> let binding = normalize(key); // ...omitting part of the code binding = extend(binding, context, handler); this.bindings[binding.key] = this.bindings[binding.key] || []; this.bindings[binding.key].push(binding); } }
Here Quill uses the Object.keys
method to get all the keys, and then calls the addBinding
method to push the key value
to bindings
.
so i was thinking
Are the keys of the array returned by Object.keys
in order?
Is it returned in the order defined?
Is it possible to change the order to achieve my needs?
Object.keys
The description above on mdn:
Object.keys()
will only traverse the properties that can be enumerated by itself, and return an array. The order of the array properties is the same as the order returned when looping through the object normally.
This order is consistent to make people more confused? In what order are they returned?
Continue to check the information, we open the ecma262 standard document and find the Object.keys part
Object.keys (?`O`?) 1. Let obj be ? ToObject(O). 2. Let keyList be ? EnumerableOwnProperties(obj, key). 3. Return CreateArrayFromList(keyList).
First try to convert the parameter into an object, then call the EnumerableOwnProperties
method to pass in the object, and return the keyList, which should be the list returned by the key.
Continue to see the definition of the EnumerableOwnProperties
method
EnumerableOwnProperties ( O, kind ) 1. Let ownKeys be ? O.[[OwnPropertyKeys]](). 2. Omit part of the code
The EnumerableOwnProperties
method continues to call the object’s O.[[OwnPropertyKeys]]
method internally, returning ownKeys
.
Then continue to look at the definition of [[OwnPropertyKeys]]
, and the OrdinaryOwnPropertyKeys
method is called internally.
It’s really layer upon layer, layer upon layer.
[[OwnPropertyKeys]] ( ) 1. Return OrdinaryOwnPropertyKeys(O).
Finally, we saw the definition of OrdinaryOwnPropertyKeys
and found the internal logic.
OrdinaryOwnPropertyKeys ( O ) 1. Let keys be a new empty List. 2. For each own property key P of O such that P is an array index, in ascending numeric index order, do a. Append P to keys. 3. For each own property key P of O such that P is a String and P is not an array index, in ascending chronological order of property creation, do a. Append P to keys. 4. For each own property key P of O such that P is a Symbol, in ascending chronological order of property creation, do a. Append P to keys. 5. Return keys.
I simply translate:
The process is roughly like this:
- First define an empty array called
keys
. - Then traverse the object, if the key is an array index, push these indexes into the array in ascending order (not the defined order)
- If the key is a string and not an index of an array, it will be pushed into the array according to the order defined when it was created
- If the key is a
Symbol
, it will be pushed into the array in the order defined when it was created - Return
keys
.
You can see that if the document key is an index of an array, that is, a positive integer, it will be sorted first, followed by strings and Symbols.
Because Object.keys
does not return the Symbol
type, we will not discuss it here.
We can see by example
Object.keys({<!-- -->name: 'answer cp3', age:18, gender: 'boy'}) // ['name', 'age\ ', 'gender'] Object.keys({<!-- -->name: 'answer cp3', 13:18, gender: 'boy'}) // ['13', 'name', \ 'gender'] Object.keys({<!-- -->name: 'answer cp3', 13:18, '6': 'boy'}) // ['6', '13 ', 'name']
If your keys are all strings and not numbers, return them in the defined order. If there are numbers, including string numbers, return the numbers first, and then return the defined order.
But here is one thing to pay attention to: The key is required to be an index of the array, so it must be a positive integer. If you are a floating point number, it will be treated as a string, which will follow the definition returned in order.
Object.keys({<!-- -->name: 'answer cp3', 13:18, 6.1: 'boy'}) // ['13', 'name\ ', '6.1']
13 is still at the front, but name and 6.1 are returned in the order defined, so pay attention here.
Problem Solved
So we want to execute the enter
key function defined by ourselves before the default keyboard event, just change the key to positive integer.
new Quill('#editor', {<!-- --> modules: {<!-- --> keyboard: {<!-- --> bindings: {<!-- --> 13:{<!-- --> key: 'enter', handler () {<!-- --> //todo } } } } } })
Summary
I always thought that the return of Object.keys
was out of order. This time, I learned the order of return of Object.keys
by looking at the Quill source code, and then solved the demand problem. The process It’s okay, keep going.
Finally, summarize the order rules returned by Object.keys
:
- If there is a number and it is a positive integer, it will be returned first
- Other string types (including floats) are returned in the order defined
- The last is the
Symbol
type, which is also returned in the order defined. ButObject.keys
does not return theSymbol
type, which can be ignored here.
Thanks for reading.