# Frontend Performance Tuning: Optimizing JavaScript Arrays and Objects for Better Code Efficiency

In the process of writing and maintaining front-end code, we often encounter scenarios that require performance optimization. Particularly when handling arrays and objects, the appropriate use of JavaScript methods can not only improve the execution efficiency of the code but also make it more concise and easier to understand. In this article, I will take you through a specific permission validation logic and discuss how to achieve optimization by leveraging JavaScript's array and collection methods.

## Business Scenario

Let's first look at a common scenario where we need to verify whether users have been assigned the appropriate permissions for each selected permission scope. This requirement sounds very straightforward, but in practical implementation, it may involve a series of array operations, and that is the source code we want to optimize today:

```javascript
// Initial permission validation logic
const selectedObjItem = [];
this.selectedPermissions.forEach((item) => {
  !selectedObjItem.includes(item.action_id) && selectedObjItem.push(item.action_id);
});

const result = this.selectedScopes.every(scope => {
  if (scope.has_instance) {
    return selectedObjItem.includes(scope.action_id);
  }
  return true;
});

if (!result) {
  showMsg(this.$t('AUTH:Please select the object scope'), 'warning');
  return false;
}
```

The purpose of this code is to validate whether each selected scenario (`selectedScopes`) has selected a permission scope, and these permission scopes need to be matched in `selectedPermissions` (each permission object has a unique identifier `action_id`).

Although the code superficially achieves the expected effect, detailed analysis reveals that there are still opportunities for optimization. Indeed, we can improve execution efficiency and make the code clearer with a few simple changes. For this, we can consider the following questions:

1. To achieve array recording and deduplication, is there a more efficient way?
    
2. Is `every` the best method for traversing and validating choices?
    
3. For the final result judgment, is it necessary to wait until all traversals have ended?
    

## Optimization

### 1\. Deduplication and Recording

The first step of recording actually includes deduplication, mainly in the pre-`push` proof determination: `!selectedObjItem.includes(item.action_id)`. As long as deduplication is involved, we can think of using ES6's naturally efficient data type `Set`, as `Set` inherently has deduplication properties, so the code can be optimized as:

```javascript
const selectedObjItem = new Set();
this.selectedPermissions.forEach((item) => {
  selectedObjItem.add(item.action_id);
});
```

Using `Set` for deduplication and combining it with the `has` method to check for element existence is generally more efficient than using arrays for deduplication (using `push` in conjunction with `includes`). The reasons are as follows:

1. **Time Complexity**:
    
    * The `add` and `has` methods of a `Set` usually have a constant time complexity O(1), as `Set` is implemented internally by a hash table, which allows for fast data lookup and insertion.
        
    * The `includes` method of an array has a time complexity of O(n) because, in the worst-case scenario, it needs to traverse the entire array to determine whether an element exists.
        
2. **Deduplication**:
    
    * `Set` is designed as a collection of unique elements; it automatically manages the uniqueness of its elements. When trying to add an element already in the `Set`, the `Set` will not perform any operation, so there is no need to manually write deduplication logic.
        
    * To deduplicate an array, additional logic (usually using `includes` then `push`) is required to ensure the elements are unique, increasing code complexity and operational steps.
        
3. **Code Conciseness**:
    
    * Using `Set` makes the code more concise and understandable. As the `Set` interface clearly represents a collection data structure, it makes the intent of the code clearer and semantically better.
        
    * Using arrays for deduplication involves the `includes` and `push` methods. Although these methods are array methods and easy to understand, they need to be combined to achieve deduplication, which makes the code less intuitive.
        

The use and application of `Set` are further introduced in \[the following section\](##Appendix: Description and Examples of Set)

### 2\. **Checking Optimization**

It's possible to use the `every` method in the source code, but it's also inefficient because `every` needs to traverse all items. Since the purpose of the check is to ensure all items are selected, if one is not selected, we can return an error result early without needing to check the rest.

With this thought, it's easy to think of the `some` method, and the optimized code is as follows:

```javascript
const result = this.selectedScopes.some(scope => {
  if (scope.has_instance) {
    return !selectedObjItem.has(scope.action_id);
  }
  return false;
});
```

The logic and structure of the code look no different from the original, but the actual efficiency will improve since `some` will not continue subsequent loops after returning `true`.

### 3\. Complete Code

The complete optimized code is as follows:

```javascript
// Deduplicate and record action_id
const selectedObjItem = new Set();
this.selectedPermissions.forEach((item) => {
  selectedObjItem.add(item.action_id);
});

// Check if all options have been selected
const result = this.selectedScopes.some(scope => {
  if (scope.has_instance) {
    return !selectedObjItem.has(scope.action_id);
  }
  return false;
});

if (result) {
  showMsg(this.$t('AUTH:Please select the object scope'), 'warning');
  return false;
}
```

## Summary

JavaScript is an ever-evolving language. The ES6 version introduced new syntax and features that greatly improved the efficiency and readability of code writing. Here's a brief summary of the methods and applications mentioned:

1. **Use the new data structure** `Set`\*\*: Implementing array deduplication and efficient recording of non-duplicate values is very convenient. Compared to traditional traversal checking methods, `Set`'s native mechanism ensures the collection's uniqueness, significantly impacting performance optimization, particularly in handling large datasets.
    
2. **Rational use of array methods:** ES6 offers array methods such as `forEach`, `every`, and `some`. Appropriate use of these methods can make code clearer and choose the most suitable iteration method for different business logic needs, such as using `some` to return early results, avoiding unnecessary traversal.
    
3. **Optimizing logical judgment:** Logical optimizations such as looping early can save resources and time by avoiding unnecessary computations. When validating arrays or collections, considering boundary conditions and short-circuit logic can lead to more efficient code execution.
    
4. **Utilizing ES6's concise syntax:** Features such as arrow functions and template strings can make the code more concise, avoid redundancy, and enhance code readability.
    

In practical programming, each optimization point may only bring a slight performance enhancement, but collectively, these improvements can significantly increase application performance and user experience. By incorporating the above optimization methods, we can write JavaScript code that is both efficient and readable.

## Appendix: Description and Examples of Set

> `Set` is a special type of collection — "a collection of values" (without keys), **and each value can only occur once**.

The previous section introduced one application scenario of `Set`. Here is a simple review of the features of this data type. Its main methods are as follows:

* `new Set(iterable)` — creates a `set`; if an iterable object (usually an array) is provided, values from the array will be copied into the `set`.
    
* `set.add(value)` — adds a value, returns the set itself.
    
* `set.delete(value)` — removes the value; returns `true` if `value` is present at the time of the call, otherwise returns `false`.
    
* `set.has(value)` — if `value` is in the set, returns `true`; otherwise returns `false`.
    
* `set.clear()` — clears the set.
    
* `set.size` — returns the number of elements.
    

Its main characteristic is that repeating the same value call `set.add(value)` does not bring about any change, which is why each value in `Set` appears only once.

### Counting (Statistics)

First, look at the following code to understand what it's doing and the associated principle without comments:

```javascript
const uid = () =>
  String(
    Date.now().toString(32) +
      Math.random().toString(16)
  ).replace(/\./g, '');

const size = 1000000
const set = new Set(new Array(size)
  .fill(0)
  .map(() => uid()))

console.log(
  size === set.size ? 'all ids are unique' : `not unique records ${size - set.size}`
)
```

Correct, it's actually testing the uid function to check whether the generated id is unique. Interestingly, here is how `Set` is used to make a uniqueness judgment: why can `set.size === size` determine whether the created uuids are unique?

It's precisely because each value in a `Set` collection can only occur once; therefore, when using map with `uid()` to generate values, any identical values will not be added to the collection. Using this feature, we can count whether there are duplicate values at the beginning of the example and how many duplicates there are:

* By accessing `set.size`, if all are unique, then the length of the collection after mapping is consistent with the initially defined `size`;
    
* Otherwise, the difference between `size` and `set.size` is the number of duplicates.
    

Reasonably using `Set` can not only make the code more efficient but also refines and simplifies the understanding of the code, so in scenarios such as deduplication, statistics, counting, etc., if you previously used arrays without hesitation or consideration, you might want to pay more attention to whether you could use `Set` to improve code efficiency.
