[Изучить] Как сделать JS – API более удобным в использовании

JavaScript API

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

1. Введение

Когда предыдущая компания разрабатывала систему фонового управления, ей часто приходилось сталкиваться с различными проблемами отображения данных, и было хорошо внедрить ее в самом начале. Позже, когда я написал больше, мне было неудобно смотреть это самому. Просто думаю о том, как оптимизировать код и использовать его повторно. Ниже приведен простой пример того, как сделать API более практичным и удобным для повторного использования.

1. Практичность кода может быть только настолько, насколько это возможно. Не существует такого понятия, как идеальный API или API, который можно написать один раз и никогда не изменять.

2. Что касается удобства использования, также важны именование и расширяемость API. Но я уже писал статью ранее, поэтому повторяться здесь не буду.[Внешняя разработка] -- Поделитесь методом именования личных привычек,Рефакторинг — разработка механизма расширения для API

2. Приведите пример

Например, если есть требование, есть такие данные

{
    cashAmount: 236700,//回款金额(分)
    cashDate: "2018-05-26 10:25:28",//回款时间
    cashId: "SM2018022800020692",//回款ID
    cashStatus: 0,//回款状态
    createTime: "2018-05-23 10:26:25",//创建时间
    custoName: "广州测试有限公司",//回款公司名称
    id: "SM2018022800020692",//回款ID
    merchandisers: "守候",//回款公司联系人
    ordId: "SO2018022800020692",//订单ID
    payChannel: null,//支付方式
    remark: "",//备注
    userMobile: "18819222363",//回款公司联系人电话
}

Данные необходимо обработать следующим образом, а затем отобразить на странице

1. конвертировать cashAmount в юани и сохранить два десятичных знака

2. Анализ cashStatus (0-платеж не получен 1-платеж получен)

3. PayChannel для анализа («zfb» — Alipay, «wx» — оплата WeChat, «cash» — оплата наличными, «bankTransfer» — банковский перевод)

4. Все поля, значение которых «», NULL, undefined все установлены: '-'

Столкнувшись с такой необходимостью, это очень просто, достаточно прийти

let obj = {
    cashAmount: 236700,//回款金额(分)
    cashDate: "2018-05-26 10:25:28",//回款时间
    cashId: "SM2018022800020692",//回款ID
    cashStatus: 0,//回款状态
    createTime: "2018-05-23 10:26:25",//创建时间
    custoName: "广州测试有限公司",//回款公司名称
    id: "SM2018022800020692",//回款ID
    merchandisers: "守候",//回款公司联系人
    ordId: "SO2018022800020692",//订单ID
    payChannel: null,//支付方式
    remark: "",//备注
    userMobile: "13226452474",//回款公司联系人电话
}
function setValue(obj) {
    let _obj=JSON.parse(JSON.stringify(obj));
    //设置金额
    _obj.cashAmount = (_obj.cashAmount / 100).toFixed(2);
    //解析回款状态
    _obj.cashStatus = _obj.cashStatus === 0 ? '未回款' : '已回款';
    //解析支付方式
    let payChannelLabel = {
        'zfb': '支付宝',
        'wx': '微信支付',
        'cash': '现金支付',
        'bankTransfer': '银行转账'
    }
    _obj.payChannel=payChannelLabel[_obj.payChannel];
    //设置默认值
    for (let key in _obj){
        if(_obj[key]===''||_obj[key]===null||_obj[key]===undefined){
            _obj[key]='--'
        }
    }
    return _obj;
}
obj=setValue(obj);
console.log(obj)

Результат также правильный, как показано ниже

Но если в будущем требования изменятся, например, что если userMobile нужно изменить на xxx xxx xxxx?

Это также очень просто, изменить

function setValue(obj) {
    let _obj=JSON.parse(JSON.stringify(obj));
    //设置金额
    //解析回款状态
    //解析支付方式
    /*和上面代码一样,不重复粘贴*/
    //设置电话号码格式
    let _formatType="xxx xxx xxxx",i = 0;
    _obj.userMobile= _formatType.replace(/x/g, function(){
        return _obj.userMobile[i++]
    });
    //设置默认值
    /*和上面代码一样,不重复粘贴*/
}

Код написан, и все должны чувствовать себя некомфортно. Потому что каждый раз, когда требование изменяется, setValue должен быть изменен. Чем больше вы меняетесь, тем больше вероятность проблем. Кроме того, он не подлежит повторному использованию. Только представьте, если на другой странице есть требование, те же данные. Но поле cashDate должно быть точным только до часов, минут и секунд. Такие потребности очень похожи. Но приведенный выше код не применяется, вам нужно скопировать метод setValue (назовем его setValue2), а затем добавить логику, согласно которой cashDate отображает только часы, минуты и секунды. код хорошо написан

function setValue2(obj) {
    let _obj=JSON.parse(JSON.stringify(obj));
    //设置金额
    //解析回款状态
    //解析支付方式
    //设置电话号码格式
    /*和上面代码一样,不重复粘贴*/
    //设置 cashDate 只显示时分秒
    _obj.cashDate= _obj.cashDate.split(' ')[0];
    //设置默认值
    /*和上面代码一样,不重复粘贴*/
}

3. Принцип единой ответственности

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

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

/**
 * @description 设置默认值
 * @param obj 待处理对象
 * @return obj 已处理对象
 */
function setDefault(obj) {
    let _obj=JSON.parse(JSON.stringify(obj));
    for (let key in _obj){
        if(_obj[key]===''||_obj[key]===null||_obj[key]===undefined){
            _obj[key]='--'
        }
    }
    return _obj;
}
/**
 * @description 格式化电话号码
 * @param obj 待处理对象
 * @return obj 已处理对象
 */
function setFormatMobile(obj) {
    let _obj=JSON.parse(JSON.stringify(obj));
    let _formatType="xxx xxx xxxx",i = 0;
    _obj.userMobile= _formatType.replace(/x/g, function(){
        return _obj.userMobile[i++]
    });
    return _obj;
}
/**
 * @description 解析支付方式
 * @param obj 待处理对象
 * @return obj 已处理对象
 */
function setPayChannelLabel(obj) {
    let _obj=JSON.parse(JSON.stringify(obj));
    let payChannelLabel = {
        'zfb': '支付宝',
        'wx': '微信支付',
        'cash': '现金支付',
        'bankTransfer': '银行转账'
    }
    _obj.payChannel = payChannelLabel[_obj.payChannel];
    return _obj;
}
/**
 * @description 设置回款金额
 * @param obj 待处理对象
 * @return obj 已处理对象
 */
function setCashAmount(obj) {
    let _obj=JSON.parse(JSON.stringify(obj));
    _obj.cashAmount = (_obj.cashAmount / 100).toFixed(2);
    return _obj;
}
/**
 * @description 解析回款状态
 * @param obj 待处理对象
 * @return obj 已处理对象
 */
function setCashStatus(obj) {
    let _obj=JSON.parse(JSON.stringify(obj));
    _obj.cashStatus = _obj.cashStatus === 0 ? '未回款' : '已回款';
    return _obj;
}

obj=setFormatMobile(obj);
obj=setCashStatus(obj);
obj=setCashAmount(obj);
obj=setPayChannelLabel(obj);
obj=setDefault(obj);

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

/**
 * @description 设置汇款时间
 * @param obj 待处理对象
 * @return obj 已处理对象
 */
function setCashDate(obj) {
    let _obj=JSON.parse(JSON.stringify(obj));
    _obj.cashDate = _obj.cashDate.split(' ')[0];
    return _obj;
}

obj=setFormatMobile(obj);
obj=setCashStatus(obj);
obj=setCashAmount(obj);
obj=setCashDate(obj);
obj=setPayChannelLabel(obj);
obj=setDefault(obj);
console.log(obj)

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

4. Принцип наименьшего знания

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

Во-первых, глобальную функцию легко решить, обернув ее объектом, глобальных функций меньше, а также ими легко управлять.

Повторяющийся код и комментарии здесь игнорируются, вставка не повторяется.

let handle={
   setDefault(obj) {
        //省略的代码
    },
    setFormatMobile(obj) {
        //省略的代码
    },
    setPayChannelLabel(obj) {
        //省略的代码
    },
    setCashAmount(obj) {
        //省略的代码
    },
    setCashStatus(obj) {
        //省略的代码
    }
}


obj=handle.setFormatMobile(obj);
obj=handle.setCashStatus(obj);
obj=handle.setCashAmount(obj);
obj=handle.setPayChannelLabel(obj);
obj=handle.setDefault(obj);
console.log(obj)

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

let handle={
   /*省略代码*/
   setCash(obj){
        let _obj=JSON.parse(JSON.stringify(obj));
        _obj=this.setFormatMobile(_obj);
        _obj=this.setCashStatus(_obj);
        _obj=this.setCashAmount(_obj);
        _obj=this.setPayChannelLabel(_obj);
        _obj=this.setDefault(_obj);
        return _obj;
    }
}
obj=handle.setCash(obj);
console.log(obj)

5. Разделение данных конфигурации и бизнес-логики

Вышеприведенный код выглядит более удобным, но все же есть проблема, то есть функция setCash слишком мертва. Исправлены пять методов: setFormatMobile,setCashStatus,setCashAmount,setPayChannelLabel,setDefault. Если вам не нужно в дальнейшем обрабатывать телефонные номера, вам нужно снова изменить setCash, поставить_obj=this.setFormatMobile(_obj);Удалите эту строку кода. Хотя изменения небольшие, проблема возникла. Если одно из мест нужно выполнитьsetFormatMobile, его нельзя удалить. Если другое место, не нужно выполнятьsetFormatMobile, он будет удален. Вот так и теряешь из виду.

Решение должно быть известно всем, то есть какую функцию нужно выполнить, просто динамически передать в функцию.

let handle={
   /*省略代码*/
   setCash(obj,fns='setFormatMobile,setCashStatus,setCashAmount,setPayChannelLabel,setDefault'){
        let _obj=JSON.parse(JSON.stringify(obj));
        let _fns=fns.split(',');
        _fns.forEach(item => {
            _obj=this[item](_obj);
        });
        return _obj;
    }
}
obj=handle.setCash(obj);
console.log(obj)

//比如另一个地方不需要执行 setFormatMobile
obj = {
    cashAmount: 236700,//回款金额(分)
    cashDate: "2018-05-26 10:25:28",//回款时间
    cashId: "SM2018022800020692",//回款ID
    cashStatus: 0,//回款状态
    createTime: "2018-05-23 10:26:25",//创建时间
    custoName: "广州测试有限公司",//回款公司名称
    id: "SM2018022800020692",//回款ID
    merchandisers: "守候",//回款公司联系人
    ordId: "SO2018022800020692",//订单ID
    payChannel: null,//支付方式
    remark: "",//备注
    userMobile: "13226452474",//回款公司联系人电话
}
obj=handle.setCash(obj,'setCashStatus,setCashAmount,setPayChannelLabel,setDefault');
console.log('比如另一个地方不需要执行 setFormatMobile',obj)

6. Пакетная обработка

Увидев здесь, кажется почти. Но если его записать, то все будут знать, что в списке пользователей общей системы управления фоном вообще нет одних только данных. Обычно объект массива. следующим образом

let arr=[
    {
        cashAmount: 236700,//回款金额(分)
        cashDate: "2018-05-26 10:25:28",//回款时间
        cashId: "SM2018022800020692",//回款ID
        cashStatus: 0,//回款状态
        createTime: "2018-05-23 10:26:25",//创建时间
        custoName: "广州测试有限公司",//回款公司名称
        id: "SM2018022800020692",//回款ID
        merchandisers: "守候",//回款公司联系人
        ordId: "SO2018022800020692",//订单ID
        payChannel: null,//支付方式
        remark: "",//备注
        userMobile: "13226452474",//回款公司联系人电话
    },
    {/*省略的代码*/},
    {/*省略的代码*/},
    {/*省略的代码*/},
    //省略的代码
]

При написании пишите так

arr.forEach((item,index)=>{
    arr[index]=handle.setCash(item);
})
console.log(arr)

Хотя кода не так много, но есть лучшее решение, используйте лучшее решение. Например, с помощью пакетной обработки. Просто напишите еще одну функцию.

let handle={
   /*省略代码*/
   batch(arr,fns,...orther){
        let _arr=JSON.parse(JSON.stringify(arr));
        let _fns=fns.split(',');
        _arr.forEach((item,index)=>{
            _fns.forEach(fn => {
                _arr[index]=this[fn](_arr[index],...orther);
            });
        })
        return _arr
    }
}

Вызов немного проще, чем раньше, и результат правильный

arr=handle.batch(arr,'setCash')
console.log(arr)

Вы также можете передать другие параметры

arr=handle.batch(arr,'setCash','setCashStatus,setCashAmount,setPayChannelLabel,setDefault')
console.log(arr)

Если вы хотите передать несколько операционных функций

arr=handle.batch(arr,'setCashStatus,setCashAmount')
console.log(arr)

7. Резюме

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

------------------------- Великолепная разделительная линия --------------------

Если вы хотите узнать больше, общаться со мной и продвигать вакансии, добавьте меня в WeChat. Или обратите внимание на мой паблик WeChat: В ожидании книжного магазина