Javascript commonly used code optimization and refactoring methods

Introduction to the

It mainly introduces the following points:

  1. Refining function
  2. Merge repeated conditional fragments
  3. Extract conditional branch statements into functions
  4. Rational use cycle
  5. Instead of nesting conditional branches, let functions exit early
  6. Pass object arguments instead of a long argument list
  7. Use less triadic operators
  8. Use chained calls wisely
  9. Decomposing large classes
  10. Use bitwise operators
  11. Pure functions

This post will be updated, and if there are any problems, please feel free to add them in the comments section.

1. Refine functions

Benefits:

  • Avoid large functions.
  • Independent functions facilitate code reuse.
  • Independent functions are easier to override.
  • A stand-alone function, if well named, acts as a comment in its own right.
  • Semantically, multiple separate sections of logic are implemented in different functions to make the code logical and clear to see what each step is doing.

Example code:

The implementation gets the data, then manipulates the DOM to display the data, and finally adds events

  • Before the function is refined
// The logic is written together. You need to read all the logic before you know what the code is for
function main() {
    $.ajax.get('/getData').then((res) = > {
        const ul = document.getElementById('ul');
        ul.innerHTML = res.list.map(text= > `<li class="li">${text}</li>`).join('\n');
        const list = document.getElementsByClassName('li');
        for (let i = 0; i < list.length; i ++) {
            list[i].addEventListener('focus'.() = > {
                // do something}); }}); }Copy the code
  • After the function is refined
function getData() {
    return $.ajax.get('/getData').then((res) = > res.data.list);
}
function showList(list) {
    const ul = document.getElementById('ul');
    ul.innerHTML = list.map(text= > `<li class="li">${text}</li>`).join('\n');
}
function addEvent() {
    const list = document.getElementsByClassName('li');
    for (let i = 0; i < list.length; i ++) {
        list[i].addEventListener('focus'.() = > {
            // do something}); }}// The logic is clear. At a glance, you can understand what each step is doing. Some of the extracted functions can be reused
async function main() {
    const list = await getData(); // Get the data
    showList(list); // Display the page
    addEvent(); // Add events
}
Copy the code

2. Merge repeated conditional segments

If a function has conditional branch statements, and the conditional branch statements spread duplicate code, it may be necessary to do a merge and deduplication.

/ / before the merger
function main( currPage ){
    if ( currPage <= 0 ){
        currPage = 0;
        jump( currPage ); / / jump
    }else if ( currPage >= totalPage ){
        currPage = totalPage;
        jump( currPage ); / / jump
    }else{
        jump( currPage ); / / jump}};/ / after the merger
function main( currPage ){
    if ( currPage <= 0 ){
        currPage = 0;
    }else if ( currPage >= totalPage ){
        currPage = totalPage;
    }
    jump( currPage ); // Make the jump function independent
};
Copy the code

3. Refine conditional branch statements into functions

Complex conditional branch statements are one of the major reasons programs are difficult to read and understand, and can easily lead to a large function. Sometimes conditional branch statements can be refined into semantic functions to make the code more intuitive and logical.

// Depending on the season
function getPrice( price ){
    var date = new Date(a);if ( date.getMonth() >= 6 && date.getMonth() <= 9) {/ / in the summer
        return price * 0.8;
    }
    return price;
};


// Is it summer
function isSummer(){
    var date = new Date(a);return date.getMonth() >= 6 && date.getMonth() <= 9;
};
// After extracting the conditions
function getPrice( price ){
    if ( isSummer() ){
        return price * 0.8;
    }
    return price;
};
Copy the code

Use the cycle wisely

If multiple pieces of code are actually doing some repetitive work, you can use loops instead to make the amount of code smaller.

// What is the browser
function getBrowser(){
    const str = navigator.userAgent;
    if (str.includes('QQBrowser')) {
	return 'qq';
    } else if (str.includes('Chrome')) {
	return 'chrome';
    } else if (str.includes('Safari')) {
        return 'safri';
    } else if (str.includes('Firefox')) {
        return 'firefox';
    } else if(explorer.indexOf('Opera') > =0) {return 'opera';
    } else if (str.includes('msie')) {
        return 'ie';
    } else {
        return 'other'; }};// Loop judgment, abstracting the correspondence into a configuration, more explicit
function getBrowser(){
    const str = navigator.userAgent;
    const list = [
        {key: 'QQBrowser'.browser: 'qq'},
        {key: 'Chrome'.browser: 'chrome'},
        {key: 'Safari'.browser: 'safari'},
        {key: 'Firefox'.browser: 'firefox'},
        {key: 'Opera'.browser: 'opera'},
        {key: 'msie'.browser: 'ie'},];for (let i = 0; i < list.length; i++) {
        const item = list[i];
        if (str.includes(item.key)) {return item.browser};
    }
    return 'other';
}

Copy the code

5. Let functions exit early instead of nesting conditional branches

Make the function return multiple exits ahead of time, instead of nesting conditional branches.

function del( obj ){
    var ret;
    if ( !obj.isReadOnly ){ // Only non-read-only objects can be deleted
        if ( obj.isFolder ){ // If it is a folder
            ret = deleteFolder( obj );
        }else if ( obj.isFile ){ // If it is a fileret = deleteFile( obj ); }}return ret;
};

function del( obj ){
    if ( obj.isReadOnly ){ // Reverse the if expression
        return;
    }
    if ( obj.isFolder ){
        return deleteFolder( obj );
    }
    if ( obj.isFile ){
        returndeleteFile( obj ); }};Copy the code

6. Pass object parameters instead of a long parameter list

Function arguments that are too long increase the risk of error, making sure they are passed in the right order is a hassle, and code readability becomes worse. Try to make sure that function arguments are not too long. If you must pass more than one parameter, use an object instead.

In general, it is best not to have more than three function arguments

function setUserInfo( id, name, address, sex, mobile, qq ){
    console.log( 'id= ' + id );
    console.log( 'name= ' +name );
    console.log( 'address= ' + address );
    console.log( 'sex= ' + sex );
    console.log( 'mobile= ' + mobile );
    console.log( 'qq= ' + qq );
};
setUserInfo( 1314.'sven'.'shenzhen'.'male'.'137 * * * * * * * *'.377876679 );

function setUserInfo( obj ){
    console.log( 'id= ' + obj.id );
    console.log( 'name= ' + obj.name );
    console.log( 'address= ' + obj.address );
    console.log( 'sex= ' + obj.sex );
    console.log( 'mobile= ' + obj.mobile );
    console.log( 'qq= ' + obj.qq );
};
setUserInfo({
    id: 1314.name: 'sven'.address: 'shenzhen'.sex: 'male'.mobile: '137 * * * * * * * *'.qq: 377876679
});
Copy the code

7. Use fewer ternary operators

Ternary operators have high performance and little code.

However, we should not abuse the ternary operator. We should use it in simple branches and avoid it in complex branches.

// Simple logic can use the ternary operator
var global = typeof window! = ="undefined" ? window : this;

// Complex logic is not suitable for use
var ok = isString ? (isTooLang ? 2 : (isTooShort ? 1 : 0)) : -1;
Copy the code

8. Use chained calls wisely

Advantages: Chaining calls are simple to use and require less code.

Cons: The downside of chained calls is that they are not easy to debug. If we know there is an error in a chain, we have to break the chain to add some debug logs or breakpoints so that we can locate the error.

If the structure of the chain is relatively stable and is not easy to be modified later, the chain can be used.

var User = {
    id: null.name: null.setId: function( id ){
        this.id = id;
        return this;
    },
    setName: function( name ){
        this.name = name;
        return this; }}; User .setId(1314 )
  .setName( 'sven' );

var user = new User();
user.setId( 1314 );
user.setName( 'sven' );
Copy the code

9. Decompose large classes

The decomposition of large classes is much like the refinement of functions; too large classes can cause problems of unclear logic, difficult to understand, and difficult to maintain.

Reasonable decomposition of classes can make the logic of classes clear, and submodules can be easily reused.

10. Use bitwise operators

None of the programming languages is very good at calculating multiplication and division, but in some cases bitwise operators can improve the performance of such operations.

11. Pure functions

A pure function is one that does not depend on and does not change the state of a variable outside its scope.

The return value of a pure function is determined only by the arguments it was called with, and its execution is independent of the state of the system (execution context).

For the same input parameters, you must get the same output, which means there are no internal random variables that affect the output.

Features that are not pure functions:

  • Changing a File System
  • Insert records into the database
  • Send an HTTP request
  • Variable data
  • Print/log
  • Get user input
  • DOM query
  • Accessing system Status

What pure functions do:

  • Reliability: Function returns are always as expected
  • Cacheability: Since the output must be the same as long as the input is the same, you can use the input as the key, the output as the value, and use the object to cache the computed results
  • Portability: Because there are no external dependencies, porting to any environment will work correctly
  • Testability: Facilitates unit testing of functions
  • Parallelism: For some complex computations, the computation can be carried out in parallel (for example, using nodeJS multiple sub-processes to compute multiple tasks simultaneously to improve the computation speed).

Application scenario:

  • Utility functions are best used as pure functions
  • Multi-platform code (NodeJS, browser, wechat applet, Native client, etc.)
  • Relatively independent function
var a = 1;
// Impure function
function sum(b) {
    return a + b;
}
// Impure function
function sum(b) {
    a = 2;
    return b;
}
// Impure function
function sum(b) {
    return b + Math.random();
}


/ / pure functions
function sum (b, c) {
    return b + c;
}
Copy the code

12. Use mappings instead of repeating logical branches

// Duplicate logic branches
function example(type) {
    if (type === 'a') {
        return Type '1';
    } else if (type === 'b')  {
        return 'type 2';
    } else if (type === 'c')  {
        return '3';
    } else if (type === 'd')  {
        return '4'; }}// Use mappings instead of repeating logical branches
function example(type) {
    const map = {
        a: Type '1'.b: 'type 2'.c: '3'.d: '4'
    };
    return map[type];
}
Copy the code

reference

  • JavaScript design patterns and development practices