By accident, I discovered a new way of doing front-end enumeration. “What is this?” I thought.

After recovering, he exclaimed, “Exquisite! Cattle beep! High efficiency thief!”

I tried to use it in the company’s project, and I really felt that the execution efficiency of the program became faster (of course, there must be a psychological implication).

When Code Review came, my colleagues were shocked:

Let’s see how it works!

Enumeration definition

/** * SKILLS: **/
const SKILLS = {
  CSS: 1 ,
  JS: 1 << 1.HTML: 1 << 2.WEB_GL: 1 << 3
}
Copy the code

The definition of enumerations seems mundane, but a little strange, right?

Explain:

The << symbol is the bit operator in JS. 1 << N means: move the bits of the number 1 N to the left.

1 << 1 / / 2
// Binary: 1 => 10
1 << 2 / / 4
// Binary: 10 => 100.1 << N // 2 to the N
Copy the code

Second, enumeration use

We defined enumerations as we did in step 1, so how should we use them?

Consider a scenario: When we interview a front end student, we are constantly marking his skills. The marking process is as follows:

let skills = 0
// Add a skill he knows
function addSkill(skill) {
  skills = skills | skill / / add
}

addSkill(SKILLS.CSS) / / 1
addSkill(SKILLS.HTML) / / 5
addSkill(SKILLS.WEB_GL) / / 13
Copy the code

Once the skills have been added, we need to spend what skills the person has elsewhere. The spending process is as follows:

// Determine if he knows CSS
SKILLS.CSS & skills // 1 (0 means no, non-0 means yes)

// Determine if he can JS
SKILLS.JS & skills // 0 (0 means no, non-0 means yes)


// Determine if he knows HTML and WebGl
SKILLS.HTML & skills && SKILLS.WEB_GL & skills // 8 (0 means no, non-0 means yes)

// Determine whether he knows JAVASCRIPT or HTML
SKILLS.JS & skills || SKILLS.HTML & skills
Copy the code

OK! The basic skills are there.

Some students are going to ask: “What are its advantages? Such poor readability!”

Of course there are advantages, the advantage lies in: it is efficient thief high!

Three, efficiency comparison

To see how “efficient” it is, I wrote two common “control group” notations.

Common writing method 1: array type play

let skills = []
function addSkill(skill) {
  if(! skills.includes(skill)) {// Check whether the skill exists in the spell
    skills.push(skill)
  }
}

addSkill(SKILLS.CSS) / / 1
addSkill(SKILLS.HTML) / / 5
addSkill(SKILLS.WEB_GL) / / 13

skills.includes(SKILLS.CSS)
skills.includes(SKILLS.JS)
skills.includes(SKILLS.HTML) && skills.includes(SKILLS.WEB_GL)
skills.includes(SKILLS.JS) || skills.includes(SKILLS.HTML)
Copy the code

In this way, an array is used to store the enumeration of skills, and the arr.includes() method is used to determine whether the enumeration has been stored.

Common writing method 2:MapType of play

let skills = {}
function addSkill(skill) {
  if(! (skills[skill])) {// Check whether the skill exists in the spell
    skills[skill] = true
  }
}
addSkill(SKILLS.CSS) / / 1
addSkill(SKILLS.HTML) / / 5
addSkill(SKILLS.WEB_GL) / / 13

skills[SKILLS.CSS]
skills[SKILLS.JS]
skills[SKILLS.HTML] && skills[SKILLS.WEB_GL]
skills[SKILLS.JS] || skills[SKILLS.HTML]
Copy the code

The enumeration is stored in {[value]: true} mode and then evaluated in map[value] mode to determine whether the enumeration has been stored.

Comparing the results

Guess what the efficiency ranking would look like? The results are as follows: Fastest group: bitwise group (recommended in this article)

1.1 billion times per second

# 2: Array play

31.24 million executions per second

Slowest group: Map style play

9.52 million times per second

Use case address: jsbench. Me / 4okyr97QI9 /…

Interested friends can visit the link above to verify themselves.

According to the results, there is even a 2-3 data level difference between the fastest and slowest.

Four, principle analysis (why so fast!)

Why is the bitwise formula recommended in this article so efficient? How does it do this through bit operations?

4.1 Definition Principle

This is fromJavascriptThe signed integer uses 31 bits to represent the value of the integer, using the first digit32The symbol for an integer,0For positive numbers,1Negative numbers. The value range is[- 2 ^ 31, 2 ^ 31-1), namely [-2147483648, 2147483647].When we define enumerations, each occupies a binary value on a different bit.

Therefore, this approach is only suitableFewer than or equal to 31 enumerationsThe scene.

4.2 Principle of value storage

Why skills = skills | skill can be said on this code adds an enumeration item? | is an operator of Javascript: or. When two Numbers for | operation, can compare to each one, any one, if both number is zero, the result is 0. In other cases, the result is 1; Such as:

1 << 1 | 1 << 2 / / 010 | 100
// The result is 110, i.e. the number: 6

1 | 1 << 3 / / 0001 | 1000
// The result is 1001, i.e. the number: 9
Copy the code

Therefore, as long as performed skills = skills | skill, as a result, the skill matching that there must be a 1 a.

4.3 Principle of Value Selection

Why does “SKILLS.CSS & SKILLS” return a non-zero value to indicate that “SKILLS” contains “SKILLS.CSS”? Otherwise, it doesn’t include? & is the Javascript operator: and. When an & is performed on two values, each digit is compared. If both digits are 1, the result is 1. In other cases, the result is 0; Such as:

1 & 9 // 0001 &1001 = 0001 (1)

2 & 8 // 0010&1000 = 0000 (0)
Copy the code

Therefore, if skills. CSS & SKILLS returns a non-zero value, you can determine that skills. CSS must exist in SKILLS.

Five, who is using it? (Rain Creek: I am.)

Where did I see the above usage? Yes, it is from the vue3 source code. Source code address: github1s.com/vuejs/core/…

In the source code, VUe3 defines enumeration in this way, overhead enumeration, it is worth learning. ShapeFlags enumeration is defined as follows:

export const enum ShapeFlags {
  ELEMENT = 1,
  FUNCTIONAL_COMPONENT = 1 << 1,
  STATEFUL_COMPONENT = 1 << 2,
  TEXT_CHILDREN = 1 << 3,
  ARRAY_CHILDREN = 1 << 4,
  SLOTS_CHILDREN = 1 << 5,
  TELEPORT = 1 << 6,
  SUSPENSE = 1 << 7,
  COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,
  COMPONENT_KEPT_ALIVE = 1 << 9,
  COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT
}
Copy the code

The end of the

I’m Spring brother. I love vue.js, ElementUI, and Element Plus. My goal is to share the most practical and useful knowledge points with you. I hope you can leave work early, finish your work quickly, and feel calm 🐟.

You can pay attention to me in nuggets: spring elder brother’s dream is to touch fish, can also find me in the public number: the front end to touch fish. I hope you will be stronger in 2022.