1. Introduction
For front-end development, you’re going to be dealing with apis, and you’re going to be thinking about how to design your own API. A good API is to code what good content is to everyone. A good API is not only better for users to understand, but also better for development and later maintenance. As for how to design an API, I’m going to make some suggestions of my own today. If you have any good ideas, welcome to point out.
Named after 2.
A good naming habit is the first step in efficient development. If the naming specification, for their own, file sorting has a great help, later modify the file, can quickly locate the file, naming specification, but also appears to be their own professional. For the team, if there is a unified standard naming, the handover can reduce a lot of learning and communication costs.
Here are a few tips on naming
2-1. Correct spelling
This should be the bottom line of naming, and it’s not uncommon to have misspellings of words that confuse you or your team. I have encountered a more profound situation
Chinese meaning | expect | The actual |
---|---|---|
The form | form | from |
To sign up | sign-up | sign-in |
adopt | adopt | adept |
content | content | contend |
test | test | text |
contact | contact | contract |
highly | height | heigth |
The width of the | width | widht |
mobile | mobile | moblie |
The label | tab | tap |
These words, if they are misspelled, at least the editor will warn them. But if you make a mistake, but the word is the correct word, you can make it big or small (for example, form, sign up, adopt, content, if the word is wrong and the meaning is changed but the word is correct, the editor will not warn you).
Tried to dig a pit more deep is: an activity, have signed up, have the function of sign in! The processing method is as follows
Get the registered user information: getSignUpUserList, reset the registered data: resetSignUpUser, submit the registration operation: signInDo
GetSignInUserList to obtain the information of the signed user, resetSignInUser to reset the form data of the signed user, and signUpDo to submit the signed user
When fixing a bug, I was completely confused, and you can understand why.
2-2. Pay attention to singular and plural numbers
Complex numbers are recommended for all functions that involve traversing, manipulating objects, arrays, and collections.
Different companies have different conventions for displaying plurals, but they need to be consistent, such as product listings
productList
. List is used here for complex numbers, and is not recommended anywhere else
products
That’s a complex number
2-3. Use accurate words
There are two main aspects of this
Wrong meaning of words
Notice means notice, notice, notice, notice, notice, notice, notice. For popover session messages, the word message is recommended. Notice should be used like ‘notice, notice, statement’ etc.
Incorrect use of words with positive and negative meanings
For example, the closeDialog method is used to close the popover, and the showDialog method is used to display the popover. A. show B. hide C. show D. show And close means close, and the opposite is open.
Often used antonyms (some with abbreviations)
in | out |
on | off |
prev | next |
show | hide |
close | open |
success | fail |
before | after |
begin | end |
2-4. Naming significance
This one, I was going to put in 2-2, because naming is a bottom line if it makes sense. But I put it here because it doesn’t happen much in functions, and more in ordinary variables (var n1,n2,n3;). . About naming, or suggest that we should have meaningful names, do not use meaningless names.
The most common situation is the naming aspect of ICONS.
For example, the following icon (selected from the bottom of a platform navigation bar), click on different ICONS to start different methods.
Many people like the following names
/ / version 1
function handle1(a){}function handle2(a){}/ / version 2
function handleA(a){}function handleB(a){}/ / version 3
function handleOne(a){}function handleTwo(a){}Copy the code
This name, other functions, even the element class. Such naming definitely increases the difficulty of maintenance in the later stage. It can even lead to refactoring.
Suggested posture
function handleHome(a){}function handleCollect(a){}Copy the code
2-5. Naming format
The API in this article is mainly for functions, but in this small section, there are also suggested naming methods for other targets.
Standby name object | The recommended name |
---|---|
The picture | ‘-‘, ‘_’ |
class,id | ‘-‘ division |
Files, variables | Hump named |
Temporary variable | Start with ‘_’ and name the hump |
2-6. Handle Chinese pinyin
For Chinese pinyin, it should be said that there is only one case, created by the Chinese, without English translation.
named | meaning |
---|---|
taobao | taobao |
zongzi | Glutinous Rice Wrapped in Bamboo Leaves |
pinyin | pinyin |
A little over a year ago, I came across a middle 2 named dengluDo. I didn’t know what it was at that time, but later I asked the person and found out that it was an operation to log in. Denglu is Chinese pinyin and DO is English. If he does not cry, I will lose.
2-7. Unspoken naming rules
In some cases, naming a particular object and using a particular name is an unspoken rule. The most memorable thing is to name the button either full or BTN. I clearly remember one of my teachers once said: “Write but, BTO program can run normally, no one said you were wrong, but I do not hire you as the interviewer, just say you are not professional.
Standby name object | The recommended name | Error model |
---|---|---|
button | btn | but bto |
background | bg | back background |
The template | tpl | tem |
Prompt information | msg | mes |
TAB bar | tab | tit |
Large view of the website (advertising campaign) | banner | ban |
registered | register | sign-in |
3. The parameters
For functions, parameters are the most frequently set by users, but also the most concerned part, reasonable design of function parameters, this step is very important, directly affect the use of the function.
3 to 1. The const parameter
As a rule, do not directly change the value of the input parameter. The original purpose of this rule is to address the problem of function side effects. If the parameter is a reference type of data, if you change the parameter within the function, the original data will be changed, often causing problems that are difficult to trace.
3-2. Control the number of parameters
The number of parameters, personally recommended, is more than three, encapsulated by objects. Because if the API has more parameters, the memory cost of using the API is higher, and the ease of use is affected.
Take the following example:
encryptStr: function (str, regArr, type, replacement) {
var regtext = ' ',
Reg = null,
_type=type||0,
replaceText = replacement || The '*';
/ / ecDo. EncryptStr (' 18819322663 ',,5,3 [3], 0)
/ / result: 188 * * * * * 663
//repeatStr is defined above (string loop copy)
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,5,3 [3], 1)
Asdas / / result: * * * * * *
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: * * * * * 8465 asdwqe3
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,'+')
/ / the result: "1 asd88465as + + + + +"
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)
}
}
Copy the code
If you look at the comments above, you can see what this code does, if you think about finding an argument, I have to remember not only what the four arguments do, but also the order of the arguments.
If you use objects to record parameters, you only need to remember the functions of the four parameters, not their sequence.
encryptStr: function (obj) {
var _default={
type:0,
replacement:The '*'
};
for(var key inobj){ _default[key]=obj[key]; }},// Call mode
ecDo.encryptStr({str:'18819266335',regArr:[5].type:0,replacement:The '-'});
Copy the code
The other nice thing about this is, for example, with the function type, I want to keep the default, so I don’t want to pass it on. The original plan, that’s how it’s delivered.
ecDo.encryptStr('1asd88465asdwqe3'[5].' '.'+');
Copy the code
This is sure to stir up a lot of neat developers, like me. If you use objects, it’s easy to avoid.
ecDo.encryptStr({str:'18819266335',regArr:[5],replacement:The '-'});
Copy the code
3-3. Parameters with high pre-correlation
This should not be possible, the same meaning: mandatory important parameters in front, can be omitted parameters after.
Take the following example
/ format handles strings//ecDo.formatText('1234asda567asd890')
/ / the result: "12 34 a, sda, 567, asd, 890"
//ecDo.formatText('1234asda567asd890',4,' ')
//result: "1 234a sda5 67as d890"
//ecDo.formatText('1234asda567asd890',4,'-')
/ / result: 1-234 - a - "the as - d890 sda5-67"
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);
},
Copy the code
You can see the call. If the API is designed this way
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);
},Copy the code
You have to call it like this, and if you write your API like this, you have a great chance of being criticized!
ecDo.formatText(' '.' '.'1234asda567asd890')
Copy the code
4. The role of
4-1. Batch processing is supported
In this example, the page has elements like this
<div class="div1"></div>
<div class="div1"></div>
<div id="div2"></div>Copy the code
There is an API similar to the jQuery CSS API.
css: function (dom, json) {
for (var attr injson) { dom.style[attr] = json[attr]; }}Copy the code
Then to style the divs, the code looks like this
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'});Copy the code
When running to ecDo. The CSS (oDiv1, {‘ height ‘:’ 100 px ‘, ‘width’, ‘100 px’, ‘background’ : ‘# 09 f}); It will give you an error, and you know why. CSS is an API that only deals with individual elements, not collections of elements.
The suggested approach is to change the CSS API to batch handle collections of elements.
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]; }}},Copy the code
4-2. Polymorphic processing
An APi-html of this API similar to jQuery
The innerHTML of the element and the innerHTML of the element are separated into two methods -getHtml and setHtml. The problem is that memory costs more than innerHTML. The suggested posture is to use the same API for fetching and setting.
html: function (dom) {
if (arguments.length === 1) {
return dom.innerHTML;
} else if (arguments.length === 2) {
dom.innerHTML = arguments[1];
}
}
ecDo.html(oDiv);/ / to get
ecDo.html(oDiv,'wait');/ / set
Copy the code
4-3. Scalability
Scalability is the recommendation to follow the open-closed principle. Open for extensions, closed for modifications. Such as $.fn and $.fn.extend() in jQuery.
Give a simple example – calculating a raise
var addMoney = (function () {
// Define the policy class
var strategies = {
A:function(money){
return money + 2000;
},
B:function(money){
return money + 1000; }};// Expose the interface
return {
// Enter the salary after the raise according to the level and current salary
compute:function(lv,money){
returnstrategies[lv](money) } }; }) ();// For example: level A, 5000+2000
console.log(addMoney.compute('A'.5000))/ / 7000
// For example: level B, 20000+1000
console.log(addMoney.compute('B'.20000))/ / 21000
Copy the code
The code looks fine, but what if you need to increase the C level later? Strategies have to be modified. Add methods in there. The following
var strategies = {
A:function(money){
return money + 2000;
},
B:function(money){
return money + 1000;
},
C:function(money){
return money + 500; }};Copy the code
That’s easy to implement. What if you want to increase the S-level later? You have to change your strategies. Another problem here is that, if the added C level is only needed in module A and will not appear in module B, then when module B references addMoney, the calculation method of C level will also be introduced, resulting in unnecessary resource waste. The suggested approach is to set up an interface that extends strategies.
var addMoney = (function () {
// Define the policy class
let strategies = {
A:function(money){
return money + 2000;
},
B:function(money){
return money + 1000; }};// Expose the interface
return {
// Enter the salary after the raise according to the level and current salary
compute:function(lv,money){
return strategies[lv](money)
},
// Extend the level
addRule:function(lv,fn){
strategies[lv]=fn;
}
};
})();
// Add c-level calls
addMoney.addRule('C'.function(money){
return money + 500;
});
console.log(addMoney.compute('C'.20000))/ / 20500Copy the code
4-4. Avoid side effects
Many of us have encountered the side effects of a function, such as modifying an external scope variable in a function, or a global variable, or modifying a reference type parameter in a function.
How to avoid it? There are two main coding habits.
1. You can use parameters in a function to perform operations, but cannot modify them. If modified, use a temporary variable to record the parameter (deep-copy is required for reference types). This avoids modifying parameters directly.
2. For variables outside the function, such as global variables. Functions can be accessed, but cannot be modified.
3. If you need to assign a value to a variable outside the function, do not operate inside the function. (This feels a bit wordy because assignment, which modifies the external variable, violates point 2).
// Bad practice
var myName=' ';
function setName(firstName,lastName){ myName=firstName+lastName; }
setName('keep'.'when');
// What are the recommended practices
var myName=' ';
function setName(firstName,lastName){ return firstName+lastName; }
myName=setName('keep'.'when');
Copy the code
5. Backward compatibility
This advice is mainly to accommodate the previous writing. Take the example above. This is how the original parameter is sent
encryptStr: function (str, regArr, type, replacement) {};Copy the code
Then it was upgraded to this
encryptStr: function (obj){}Copy the code
The problem is that a project, due to historical reasons, will inevitably use this API and use the first method of parameter passing. Now the API has been changed, and there are two solutions: either change the API method used in the whole project to the second parameter transmission method, or carry out downward compatibility for the interface, which is compatible with the previous scheme.
encryptStr: function (obj) {
var _default={
type:0.replacement:The '*'
};
// If the function is called in the same way as before, compatibility judgment
if(arguments.length>1){
_default.str=arguments[0];
_default.regArr=arguments[1];
_default.type=arguments[2] | |0;
_default.replacement=arguments[3] | |The '*';
}
else{
for(var key inobj){ _default[key]=obj[key]; }}// The following code is omitted
},Copy the code
If the API is ready for a major update (e.g. from 1.0.0 to 2.0.0, not 1.0.0 to 1.0.1, or 1.0.0 to 1.1.0). It is not intended to be compatible with previous versions. You can skip this step because there’s probably a lot of compatibility code.
6. Simple
This step is arguably the most advanced in API design, and also the most difficult to develop, which is why this article is labeled ‘minimalist’. Even though the API is difficult to implement, simple to use feels like a high-level API. This step also directly affects the usability of the API. Simple apis are not just easy to use, try an API that you can understand at a glance. Such apis are easier to understand, remember, debug, and change the way you use them.
Native API, such as Date, some, map, find and all array traversal functions, es6 provides object. assign, Object.keys, Object.values and so on.
Once the king of jQuery, now the king of React, dark horse Vue. These projects are applauded for many reasons, but there is no denying that their API design is clever. Such as jQuery $, siblings, toogleClass, animate, such as the react cloneElement, replaceProps, vue nextTick, set, etc.
JQuery for now, although it is out of date, but it is worth learning the knowledge, such as the use of incisive JS writing skills, design patterns, and API design.
I wrote my own API, I also write the API as simple as possible, the highest level is to let others glance at the document, know how to use the API. This is my pursuit of the goal, but now the distance is still a little far. Just look at the encryptStr API.
7. Summary
In my opinion, a good API will have an easy to understand name, a powerful function, and a simple way to call. There are only three conditions, but the combination of these three conditions is not so easy to achieve. A good API is a great help to you, your team, and your project.
Here are some personal suggestions for API design. If you have better ideas in the future, I will share them with you as soon as possible. If you have any ideas, welcome to point out.
— — — — — — — — — — — — — — — — — — — — — — — — — — — gorgeous line — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Want to know more, follow my wechat public number – waiting book pavilion