Путь к простоте — эстетика дизайна API

внешний интерфейс API Ресурсы изображений jQuery

1. Введение

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

2. Именование

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

Вот несколько предложений по наименованию

2-1 Правильное написание

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

Китайское значение ожидать действительный
форма form from
Зарегистрироваться sign-up sign-in
принятие adopt adept
содержание content contend
контрольная работа test text
соединять contact contract
высокий height heigth
ширина width widht
переехать mobile moblie
Этикетка tab tap

Если эти слова написаны с ошибками, по крайней мере, редактор напомнит об этом. Но если неправильно, а слово правильно, то оно может быть большим или маленьким (форма, оформление, принятие, содержание, эти примеры, слово неправильное, значение изменилось, а слово правильное, редактор не напоминать).

Пробовал копать поглубже то есть: активность, есть регистрация, есть признак функции! Далее следует обработка

Получить информацию о зарегистрированном пользователе: getSignUpUserList,
Сбросить регистрационные данные: resetSignUpUser,
Отправьте операцию регистрации: signInDo

Получить информацию о вошедшем в систему пользователе: getSignInUserList,
Сбросить данные формы входа: resetSignInUser,
Отправьте операцию регистрации: signUpDo

При доработке бага я совсем запутался, и всем известна причина.

2-2. Обратите внимание на единственное и множественное число

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

Разные компании имеют разные привычки для отображения множественного числа, но они должны быть унифицированы, например, список продуктов.productList. Здесь список используется для представления множественного числа, а в других местах не рекомендуется использоватьproductsТаким образом, множественное число

2-3. Аккуратно используйте слова

Два главных аспекта

2-3-1 Неверное значение слов

Например, информация во всплывающем окне иногда отображается с помощью кнопкиnotice, но на самом деле,noticeКитайское значение должно быть «объявление, уведомление, заявление» или тому подобное.
Сообщение разговора, как всплывающее окно, рекомендуется использоватьmessageэто слово.noticeСледует использовать в таких ситуациях, как «объявление, уведомление, заявление».

2-3-2. Неправильное использование положительных и отрицательных слов

Например, чтобы закрыть всплывающее окно, методcloseDialog, а затем отображается всплывающее окно сshowDialog.showозначает «отображение», антоним должен бытьhide'Спрятать'. иcloseозначает близкий, антоним должен бытьopen.

С общими антонимами (некоторые с сокращениями)

in out
on off
prev next
show hide
close open
success fail
before after
begin end

2-4.Значение названия

Первоначально предполагалось, что эта часть будет освещена в 2-2, потому что название также является итоговым результатом, если оно имеет смысл. Но я привожу его здесь в конце, потому что в функциях такая ситуация встречается нечасто, а в обычных переменных должно быть больше (думаю, многие встречали такое название: var n1, n2, n3;). Что касается именования, рекомендуется выбирать осмысленные имена вместо бессмысленных имен.

Наиболее распространенная ситуация — именование иконок.

Например, следующие значки (выбранные на нижней панели навигации платформы), нажмите на разные значки, чтобы запустить разные методы.

Многим нравится следующее название

//版本1
function handle1(){

}
function handle2(){

}
//版本2
function handleA(){

}
function handleB(){

}
//版本3
function handleOne(){

}
function handleTwo(){

}

Такое имя, чужая функция, даже если это класс элемента. Такое наименование определенно усложняет последующее обслуживание. Это может даже привести к рефакторингу.

предлагаемая поза

function handleHome(){

}
function handleCollect(){

}

2-5 Формат именования

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

предмет, который нужно назвать Рекомендуемое имя
рисунок '-' '_' расколоть
class,id '-' расколоть
файл, переменная CamelCase
Временные переменные Начинается с '_', верблюжий регистр

2-6. Работа с китайским пиньинь

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

название значение
taobao Таобао
weibo Вейбо
zongzi Цзунцзы
pinyin пиньинь
Больше года назад я познакомился с учеником средней школы по имени -dengluDo. В то время я не знал, что это такое, но позже я попросил человека выяснить, что это была операция входа в систему, denglu был китайским пиньинь, а do был английским, поэтому он и был назван. На более позднем этапе, если он не заплачет, я проиграю.

2-7. Называние негласных правил

В некоторых случаях присвоение имени определенному объекту и использование определенного имени можно назвать негласным правилом. Самое четкое впечатление, что в названии кнопки либо все по буквам, либо пишешь btn. Я четко помню, что один из моих преподавателей сказал: программа написания а и бто тоже может нормально работать, и никто не скажет, что ты неправ, но как интервьюер, если я тебя не возьму, я скажу, что ты непрофессиональны.

предмет, который нужно назвать Рекомендуемое имя Демонстрация ошибок
кнопка btn but bto
задний план bg back background
шаблон tpl tem
Советы msg mes
Панель вкладок tab tit
Большая картинка сайта (рекламная картинка) banner ban
регистр register sign-in

3. Параметры

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

3-1.const входной параметр

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

3-2 Количество параметров управления

Количество параметров, личная рекомендация, больше 3-х, использовать объекты для инкапсуляции. Потому что чем больше параметров API, тем больше затраты памяти на использование этого API, и это также влияет на простоту использования.

Например следующий пример:

encryptStr: function (str, regArr, type, replacement) {
    var regtext = '',
        Reg = null,
        _type=type||0,
        replaceText = replacement || '*';
    //ecDo.encryptStr('18819322663',[3,5,3],0)
    //result:188*****663
    //repeatStr是在上面定义过的(字符串循环复制),大家注意哦
    if (regArr.length === 3 && type === 0) {
        regtext = '(\\w{' + regArr[0] + '})\\w{' + regArr[1] + '}(\\w{' + regArr[2] + '})'
        Reg = new RegExp(regtext);
        var replaceCount = this.repeatStr(replaceText, regArr[1]);
        return str.replace(Reg, '$1' + replaceCount + '$2')
    }
    //ecDo.encryptStr('asdasdasdaa',[3,5,3],1)
    //result:***asdas***
    else if (regArr.length === 3 && type === 1) {
        regtext = '\\w{' + regArr[0] + '}(\\w{' + regArr[1] + '})\\w{' + regArr[2] + '}'
        Reg = new RegExp(regtext);
        var replaceCount1 = this.repeatStr(replaceText, regArr[0]);
        var replaceCount2 = this.repeatStr(replaceText, regArr[2]);
        return str.replace(Reg, replaceCount1 + '$1' + replaceCount2)
    }
    //ecDo.encryptStr('1asd88465asdwqe3',[5],0)
    //result:*****8465asdwqe3
    else if (regArr.length === 1 && type === 0) {
        regtext = '(^\\w{' + regArr[0] + '})'
        Reg = new RegExp(regtext);
        var replaceCount = this.repeatStr(replaceText, regArr[0]);
        return str.replace(Reg, replaceCount)
    }
    //ecDo.encryptStr('1asd88465asdwqe3',[5],1,'+')
    //result:"1asd88465as+++++"
    else if (regArr.length === 1 && type === 1) {
        regtext = '(\\w{' + regArr[0] + '}$)'
        Reg = new RegExp(regtext);
        var replaceCount = this.repeatStr(replaceText, regArr[0]);
        return str.replace(Reg, replaceCount)
    }
}

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

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

encryptStr: function (obj) {
        var _default={
            type:0,
            replacement:'*'
        };
        for(var key in obj){
            _default[key]=obj[key];
        }
},

//调用方式
ecDo.encryptStr({str:'18819266335',regArr:[5],type:0,replacement:'-'});

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

ecDo.encryptStr('1asd88465asdwqe3',[5],'','+');

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

ecDo.encryptStr({str:'18819266335',regArr:[5],replacement:'-'});

3-3 Параметры с высокой предкорреляцией

Этого не должно быть, только одно значение: обязательные и важные параметры добавляются в начале, а необязательные параметры размещаются после.

Например следующий пример

/格式化处理字符串
//ecDo.formatText('1234asda567asd890')
//result:"12,34a,sda,567,asd,890"
//ecDo.formatText('1234asda567asd890',4,' ')
//result:"1 234a sda5 67as d890"
//ecDo.formatText('1234asda567asd890',4,'-')
//result:"1-234a-sda5-67as-d890"
formatText: function (str, size, delimiter) {
    var _size = size || 3, _delimiter = delimiter || ',';
    var regText = '\\B(?=(\\w{' + _size + '})+(?!\\w))';
    var reg = new RegExp(regText, 'g');
    return str.replace(reg, _delimiter);
},

Звоните все видят. Если бы API был разработан так

formatText: function (size, delimiter, str) {
    var _size = size || 3, _delimiter = delimiter || ',';
    var regText = '\\B(?=(\\w{' + _size + '})+(?!\\w))';
    var reg = new RegExp(regText, 'g');
    return str.replace(reg, _delimiter);
},

Он должен называться так, если API будет так написано, его очень вероятно будут критиковать!

ecDo.formatText('','','1234asda567asd890')

4. Функция

4-1. Поддержка пакетной обработки

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

<div class="div1"></div>
<div class="div1"></div>
<div id="div2"></div>

Существует API для этого API, похожее на css jQuery.

css: function (dom, json) {
    for (var attr in json) {
        dom.style[attr] = json[attr];
    }
}

Затем при стилизации этих div код выглядит следующим образом

var oDiv1 =document.querySelectorAll(".div1");
var oDiv2=document.querySelector("#div1");
ecDo.css(oDiv2,{'height':'100px','width':'100px','background':'#333'});
ecDo.css(oDiv1,{'height':'100px','width':'100px','background':'#09f'});

когда бежишь кecDo.css(oDiv1,{'height':'100px','width':'100px','background':'#09f'});Это вызовет ошибку, и все знают причину. В css API обрабатывается только один элемент, а набор элементов не обрабатывается.

Рекомендуемый способ — изменить CSS API для пакетной обработки набора элементов.

css: function (dom, json) {
    if (dom.length) {
        for (var i = 0; i < dom.length; i++) {
            for (var attr in json) {
                dom[i].style[attr] = json[attr];
            }
        }
    }
    else {
        for (var attr in json) {
            dom.style[attr] = json[attr];
        }
    }
},    
   

4-2 Полиморфизм

API-html, похожий на HTML-API jQuery.

Я сталкивался с методом обработки разработчика раньше: получение innerHTML элемента и установка innerHTML элемента разделены на два метода — getHtml, setHtml. Проблема в том, что стоимость памяти выше, чем у нативного innerHTML. Рекомендуется использовать один и тот же API для получения и установки.

html: function (dom) {
    if (arguments.length === 1) {
        return dom.innerHTML;
    } else if (arguments.length === 2) {
        dom.innerHTML = arguments[1];
    }
}

ecDo.html(oDiv);//获取
ecDo.html(oDiv,'守候');//设置

4-3 Масштабируемость

Расширяемость, рекомендуется придерживаться принципа открыто-закрыто. Открыт для расширения, закрыт для модификации. Например, $.fn и $.fn.extend() в jQuery.

Скажем простой пример - расчет прибавки к зарплате

var addMoney = (function () {
    //定义策略类
    var strategies = {
        A:function(money){
            return money + 2000;
        },
        B:function(money){
            return money + 1000;
        }
    };
    //暴露接口
    return {
        //根据等级和现工资,输入加薪后的工资
        compute:function(lv,money){
            return strategies[lv](money)
        }
    };
})();

//比如:等级为A,5000+2000
console.log(addMoney.compute('A',5000))//7000
//比如:等级为B,20000+1000
console.log(addMoney.compute('B',20000))//21000

Код выглядит нормально, но что, если в будущем потребуется повысить уровень C? Это должно изменить стратегии. Добавьте в него методы.
следующее

var strategies = {
    A:function(money){
        return money + 2000;
    },
    B:function(money){
        return money + 1000;
    },
    C:function(money){
        return money + 500;
    }
};

Это также легко реализовать.Что делать, если вы хотите повысить уровень S в будущем? Приходится менять стратегии. Еще одна проблема здесь заключается в том, что если добавленный уровень C нужен только в модуле A и не появляется в модуле B, то, когда модуль B ссылается на addMoney, также будет введен метод расчета уровня C, вызывающий неудобства. Трата необходимых ресурсов.
Рекомендуемый способ — настроить интерфейс, расширяющий стратегии.

var addMoney = (function () {
    //定义策略类
    let strategies = {
        A:function(money){
            return money + 2000;
        },
        B:function(money){
            return money + 1000;
        }
    };
    //暴露接口
    return {
        //根据等级和现工资,输入加薪后的工资
        compute:function(lv,money){
            return strategies[lv](money)
        },
        //扩展等级
        addRule:function(lv,fn){
            strategies[lv]=fn;
        }
    };
})();
//增加C等级的调用
addMoney.addRule('C',function(money){
    return money + 500;
});
console.log(addMoney.compute('C',20000))//20500    

4-4. Избегайте побочных эффектов

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

Как этого избежать? В основном следующие две привычки кодирования.

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

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

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

//不好做法
var myName='';
function setName(firstName,lastName){
    myName=firstName+lastName;
}
setName('守','侯');
//推荐做法
var myName='';
function setName(firstName,lastName){
    return firstName+lastName;
}
myName=setName('守','侯');


5. Нисходящая совместимость

Это предложение в основном состоит в том, чтобы принять во внимание предыдущее письмо. Возьмем пример выше!
Оригинальный способ передачи параметров такой

encryptStr: function (str, regArr, type, replacement) {};

Позже обновлено до этого

encryptStr: function (obj){}

В этом и проблема, в проекте этот API неизбежно используется по историческим причинам, и для передачи параметров используется первый метод. Теперь, когда API изменили, есть два решения: либо изменить метод API, используемый всем проектом, на второй метод передачи параметров, либо сделать интерфейс обратно совместимым и совместимым с предыдущим решением.

encryptStr: function (obj) {
    var _default={
        type:0,
        replacement:'*'
    };
    //如果还是以之前的方式调用函数,兼容性判断
    if(arguments.length>1){
        _default.str=arguments[0];
        _default.regArr=arguments[1];
        _default.type=arguments[2]||0;
        _default.replacement=arguments[3]||'*';
    }
    else{
        for(var key in obj){
            _default[key]=obj[key];
        }
    }
    //下面代码略
},
Если API готов к обновлению основной версии (например, обновление с 1.0.0 до 2.0.0, а не с 1.0.0 до 1.0.1 или с 1.0.0 до 1.1.0). Не будет совместимости с предыдущими версиями. Этот шаг можно пропустить, ведь кода совместимости может быть много.

6. Простой

Этот шаг можно назвать самым продвинутым шагом в разработке API, а также самым сложным шагом в разработке. Вот почему в этой статье есть слова «Дорога к простоте». Даже если API сложно реализовать, он кажется продвинутый, когда он прост в использовании API. Этот шаг также напрямую влияет на удобство использования API. Простые API не только просты в использовании, но и предлагают API, понятный с первого взгляда. Такой API легче понять, запомнить, отладить и изменить способ его использования.

Собственный API, такой как Date, some, map, find и другие функции обхода массива, Object.assign, Object.keys, Object.values ​​и т. д., предоставляемые es6.

Когда-то повелитель jQuery, теперь король реакции, тёмная лошадка vue. Есть много причин, по которым эти проекты следует приветствовать, но нельзя отрицать, что дизайн их API очень умный. Например: jQuery $, siblings, toogleClass, animate и т. д., cloneElement реакции, replaceProps и т. д., nextTick vue, set и т. д.

Хотя jQuery сейчас устарел, знания в нем все еще заслуживают изучения, такие как самые острые навыки написания js, шаблоны проектирования и дизайн API.

Я написал API, я также пишу API настолько простым, насколько это возможно, высшая сфера — позволить другим подметать документ, знать, как использовать API. Это цель, которую я преследую, но она все еще немного далека. Все видят меняencryptStrЭтот API знает (неловкий день здесь).

7. Резюме

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

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

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

Хотите узнать больше, обратите внимание на мой публичный аккаунт WeChat - Waiting Shuge