12 советов по Javascript для улучшения качества кода

JavaScript
12 советов по Javascript для улучшения качества кода

Общие методы оптимизации и рефакторинга кода Javascript

Введение

В основном ввести следующие пункты:

  1. Функция уточнения
  2. Объединить повторяющиеся условные фрагменты
  3. Преобразование операторов условного перехода в функции
  4. Используйте цикл с умом
  5. Ранний выход из функции let вместо вложенных условных ветвей
  6. Передавайте аргументы объекта вместо длинных списков аргументов
  7. Используйте тернарные операторы экономно
  8. Разумное использование связанных вызовов
  9. Разложение больших классов
  10. Использование побитовых операторов
  11. чистая функция

Эта статья будет постоянно обновляться, а недостатки можно добавлять в область комментариев.

1. Функция уточнения

выгода:

  • Избегайте слишком больших функций.
  • Независимые функции помогают повторно использовать код.
  • Отдельные функции легче переопределить.
  • Если у отдельной функции хорошее имя, она сама выступает в роли комментария.
  • Семантика реализует несколько сегментов разделенной логики в разных функциях, что может сделать логику кода ясной и ясно видеть, что делает каждый шаг.

Пример кода:

Реализуйте сбор данных, затем манипулируйте домом для отображения данных и, наконец, добавляйте события.

  • До уточнения функции
// 逻辑都写在一起,需要将所有逻辑看完才知道这段代码是干嘛的,局部逻辑无法复用
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
            });
        }
    });
}
  • После уточнения функции
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
        });
    }
}
// 逻辑清晰,一眼读懂每一步在做什么,某些提炼出来的函数还可以被复用
async function main() {
    const list = await getData(); // 获取数据
    showList(list); // 显示页面
    addEvent(); // 添加事件
}

2. Объединить повторяющиеся условные фрагменты

Если в теле функции есть какие-то условные операторы ветвления, и внутри этих условных операторов ветвления разбросан какой-то повторяющийся код, то необходимо объединить и удалить дубликаты.

// 合并前
function main( currPage ){
    if ( currPage <= 0 ){
        currPage = 0;
        jump( currPage ); // 跳转
    }else if ( currPage >= totalPage ){
        currPage = totalPage;
        jump( currPage ); // 跳转
    }else{
        jump( currPage ); // 跳转
    }
};

// 合并后
function main( currPage ){
    if ( currPage <= 0 ){
        currPage = 0;
    }else if ( currPage >= totalPage ){
        currPage = totalPage;
    }
    jump( currPage ); // 把jump 函数独立出来
};

3. Преобразование операторов условного перехода в функции

Сложные условные операторы ветвления являются важной причиной того, что программы трудно читать и понимать, и они могут легко привести к огромной функции. Иногда операторы условного перехода можно преобразовать в семантические функции, чтобы сделать код более интуитивно понятным и логически ясным.

// 根据不同季节决定打折力度
function getPrice( price ){
    var date = new Date();
    if ( date.getMonth() >= 6 && date.getMonth() <= 9 ){ // 夏天
        return price * 0.8;
    }
    return price;
};


// 是否是夏天
function isSummer(){
    var date = new Date();
    return date.getMonth() >= 6 && date.getMonth() <= 9;
};
// 提炼条件后
function getPrice( price ){
    if ( isSummer() ){
        return price * 0.8;
    }
    return price;
};

4. Используйте циклы с умом

Если несколько частей кода на самом деле отвечают за какую-то повторяющуюся работу, вместо этого можно использовать циклы, чтобы сделать код меньше.

// 判断是什么浏览器
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';
    }
};


// 循环判断,将对应关系抽象为配置,更加清晰明确
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';
}

5. Ранний выход из функции вместо вложенных условных переходов

Пусть функция станет多出口вернуться раньше, заменить嵌套条件分支.

function del( obj ){
    var ret;
    if ( !obj.isReadOnly ){ // 不为只读的才能被删除
        if ( obj.isFolder ){ // 如果是文件夹
            ret = deleteFolder( obj );
        }else if ( obj.isFile ){ // 如果是文件
            ret = deleteFile( obj );
        }
    }
    return ret;
};

function del( obj ){
    if ( obj.isReadOnly ){ // 反转if 表达式
        return;
    }
    if ( obj.isFolder ){
        return deleteFolder( obj );
    }
    if ( obj.isFile ){
        return deleteFile( obj );
    }
};

6. Передача параметров объекта вместо длинных списков параметров

Если параметры функции будут слишком длинными, это повысит риск ошибок.Проверить порядок передачи хлопотно, да и читабельность кода ухудшится.Постарайтесь, чтобы параметры функции не были слишком долго. Если вам необходимо передать несколько параметров, рекомендуется использовать对象заменять.

В общем, параметры функции лучше всего不要超过3个

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
});

7. Используйте тернарные операторы экономно

Тернарный оператор отличается высокой производительностью и небольшим объемом кода.

Но тернарным оператором не следует злоупотреблять, мы должны использовать его в простых логических ветвях и избегать его использования в сложных логических ветвях.

// 简单逻辑可以使用三目运算符
var global = typeof window !== "undefined" ? window : this;

// 复杂逻辑不适合使用
var ok = isString ? (isTooLang ? 2 : (isTooShort ? 1 : 0)) : -1;

8. Разумное использование связанных вызовов

преимущество:Сцепленные вызовы просты в использовании и требуют меньше кода.

недостаток:Недостатком цепных вызовов является то, что调试不方便, если мы знаем, что в цепочке есть ошибка, мы должны сначала разобрать цепочку, прежде чем добавлять некоторые журналы отладки или добавлять точки останова, чтобы найти место, где возникает ошибка.

Если структура цепочки относительно стабильна и ее нелегко модифицировать позже, можно использовать цепной тип.

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' );

9. Декомпозиция больших классов

Декомпозиция больших классов очень похожа на извлечение функций: если класс слишком большой, логика будет неясной, его будет сложно понять и поддерживать.

Разумная декомпозиция класса может сделать логику класса понятной, а подмодули можно легко использовать повторно.

10. Используйте побитовые операторы

Производительность умножения и деления в языках программирования не высока, но в некоторых случаях использование побитовых операторов позволяет повысить производительность таких операций, как умножение и деление.

11. Чистые функции

чистая функция означает依赖于а также不改变Функция состояния переменной вне ее области видимости.

Возвращаемое значение чистой функции определяется только параметрами при ее вызове, а ее выполнение не зависит от состояния системы (контекста выполнения).

Одни и те же входные параметры обязательно получат один и тот же результат, т. е. не будет внутреннихСлучайные переменные, влияющие на результат.

Возможности, не являющиеся чистыми функциями:

  • изменить файловую систему
  • вставить запись в базу
  • отправить http запрос
  • переменные данные
  • печать/журнал
  • Получить пользовательский ввод
  • DOM-запрос
  • статус системы доступа

Что делает чистая функция:

  • надежность: Возврат функции всегда такой, как ожидалось.
  • кешируемость: потому что, пока ввод тот же, вывод должен быть таким же, поэтому ввод можно использовать в качестве ключа, вывод можно использовать в качестве значения, а вычисленный результат можно кэшировать с помощью объекта.
  • портативность: Портирован в любую среду для правильной работы, поскольку нет внешних зависимостей.
  • Тестируемость: Удобно для модульного тестирования функций
  • параллелизм: для некоторых сложных вычислений его можно вычислять параллельно (например, используя несколько подпроцессов nodejs для одновременного вычисления нескольких задач для повышения скорости вычислений).

Сценарии применения:

  • Вспомогательные функции лучше всего использовать чистые функции
  • Код для многоплатформенного использования (nodejs, браузер, апплет WeChat, собственный клиент и т. д.)
  • относительно независимая функция
var a = 1;
// 非纯函数
function sum(b) {
    return a + b;
}
// 非纯函数
function sum(b) {
    a = 2;
    return b;
}
// 非纯函数
function sum(b) {
    return b + Math.random();
}


// 纯函数
function sum (b, c) {
    return b + c;
}

12. Используйте карты вместо повторяющихся логических ветвей

// 重复的逻辑分支
function example(type) {
    if (type === 'a') {
        return '类型1';
    } else if (type === 'b')  {
        return 'type 2';
    } else if (type === 'c')  {
        return '3';
    } else if (type === 'd')  {
        return '4';
    }
}

// 使用映射代替重复的逻辑分支
function example(type) {
    const map = {
        a: '类型1',
        b: 'type 2',
        c: '3',
        d: '4'
    };
    return map[type];
}

Ссылаться на