This is the 31st day of my participation in the August More Text Challenge
First, the difference between function and method
- Functions: Functions are snippets of JavaScript code with names and arguments that can be defined multiple times at once.
- Method: When we write functions and objects together, the function becomes a method. For example, when a function assigns a value to an object, we call it a method.
How to write a function well
In JS, in addition to variables, the most used should be the function, function is the first citizen of Javascript.
2.1 Accurate naming
2.1.1 Function naming
The naming of functions should be clear, semantic and simple to summarize the functions of functions. Instead of shortening the function name by keeping the code short, it will not improve performance or efficiency. On the contrary, if a function name is not clear, it will not be understood by others.
Try to use verbs, such as getXxxxx and setXxxxx, in front of the verb, the semantics will be clearer.
2.1.2 Parameter Naming
With an emphasis on semantics, parameter naming makes it clear to the caller what to pass in and what to call. Of course, generic names like callback and fn are acceptable, and I usually know what to do and pass without looking at the comments.
2.2 Function Comments
/** * Time formatter function **@param { (Date | number) } date- time *@param { string } unit- Convert format */
export const timeFormat = (date: Date| number | string, unit: string) = > {
if(! date) {return ' '
}
if (typeof date === 'string') return date;
if (typeof date === 'number') {
date = new Date(date);
}
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();
if (unit === 'year') return `${year}`;
if (unit === 'month') return `${year}-${month}`;
if (unit === 'day') return `${year}-${month}-${day}`;
if (unit === 'hour') return `${year}-${month}-${day} ${hour}`;
if (unit === 'minute') return `${year}-${month}-${day} ${hour}:${minute}`;
if (unit === 'second') return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
}
Copy the code
2.2.1 Parameter Remarks
/** * Time formatter function **@param { (Date | number) } date- time *@param { string } unit- Convert format */
Copy the code
@ param {type} parameters – explanation: a type that is the type of parameter, such as string, number, when there are multiple parameter type, so to identify {(string | string [])}, said this parameter can be a string or an array of strings.
- Object properties: Each property of the object needs to be explained
/** * The function that assigns items to employees **@param {Object} employee- Project staff *@param {string} Employee.name - Name of the project employee *@param {string} Employee. department - The department of the project employee */
Project.prototype.assign = function(employee) {
// ...
};
Copy the code
- Optional parameters:
/** * Time formatter function **@param { (Date | number | string) } date- time *@param { string } [unit] - Convert format */
export const timeFormat = (date: Date| number | string, unit: string) = > {
// ...
}
Copy the code
- Default value:
/** * Time formatter function **@param { (Date | number) } date- time *@param { string } [unit = 'second'] - Convert format */
export const timeFormat = (date: Date| number | string, unit ='second') = > {
// ...
}
Copy the code
2.3 Function Parameters
2.3.1 Parameter Default Value
export const timeFormat = (date: Date, unit = 'second') = > {
// ...
}
Copy the code
2.3.2 Object Parameters
async function printer_proxy_print(
html_str: string,
file_path: string,
device: string | undefined,
orientation: number,
printer_mode: string,
width: number,
height: number,
scale: number,
from: number,
to: number,
left_offset: number,
top_offset: number,
pdf_tools: string | undefined,
begin_page = 1,
end_page = 1,
repeat_times = 1,
print_type: string
) {
// ...
}
Copy the code
You can give parameters default values, so you can pass only the first few necessary parameters, like this call.
async function printer_proxy_print(
html_str: string,
file_path: string,
device = 'pc',
orientation = 'xxx',
printer_mode = 'xxx',
width = 123,
height = 123,
scale = 123.from = 123,
to = 123,
left_offset = 123,
top_offset = 123,
pdf_tools = 123,
begin_page = 1,
end_page = 1,
repeat_times = 1,
print_type = 'base64'
) {
// ...
}
await printer_proxy_print(html_str, file_path);
Copy the code
The above method seems to work, but in fact, when I have a different parameter in the middle, I need to pass all the parameters before that parameter. That’s obviously not going to work. So when there are too many arguments, we need to pass them in object deconstruction mode.
async function printer_proxy_print({
html_str,
file_path,
device = 'pc',
orientation = 'xxx',
printer_mode = 'xxx',
width = 123,
height = 123,
scale = 123.from = 123,
to = 123,
left_offset = 123,
top_offset = 123,
pdf_tools = 123,
begin_page = 1,
end_page = 1,
repeat_times = 1,
print_type = 'base64'
}) {
// ...
}
await printer_proxy_print({html_str, file_path});
Copy the code
The nice thing about deconstruction is that I can pass whatever parameters I want, regardless of the order. But functions with so many parameters tend to have problems (case by case). This is the number of parameters mentioned below.
2.3.3 Number of Parameters
The fewer the parameters of a function, the better, the maximum should not be more than 3, more parameters often means more relations, logical cross relatively more up. When testing, it is often difficult to cover all conditions, and the probability of problems increases. Multiple parameters sometimes mean multiple functions, violating the principle of single function.
2.3.4 Parameter Type Defense
Before TS was developed, we didn’t know what the user was going to pass in, so it was easy to get type errors, or we wanted to be compatible, like the timeFormat function, we wanted the user to format the time object or format the timestamp. Then we need to do a defensive process.
if(! date) {return ' '
}
if (typeof date === 'string') return date;
if (typeof date === 'number') {
date = new Date(date);
}
Copy the code
It’s worth noting, though, that even if we use TS, we can avoid the argument type problem in most cases, but not always, because we sometimes accept the data returned by the interface.
We often say, never trust the user’s input, similarly, I do not trust the data returned by the interface, we can not guarantee that the backend will not error, the agreed parameter is array type, how empty, you give me a null?
And of course these situations sometimes involve trial and error, sometimes we can think of possibilities, don’t be lazy, put in type judgments.
2.4 Return of functions
2.4.1 Idempotent functions
What is idempotent? In simple terms, what is input and what is output is fixed. Input determines output, and no matter how many calls are made, as long as the input is the same, the result should remain the same.
function sum(a: number, b: number) {
return a + b;
}
Copy the code
Idempotent functions are maintainable and relatively easy to unit test.
Pure functions 2.4.2
Under the condition of idempotent, pure functions are also required to have no side effects.
const dog = {
name: 'puppy'.age: 2.weight: 30,}if(! dog.color) {console.log('has no color');
}
function addColor(dog) {
dog.color = 'white';
}
addColor(dog);
console.log(dog); // {name: "puppy", age: 2, weight: 30, color: "white"}
Copy the code
As you can see, the addColor function modifies the properties of the dog object, causing a side effect.
function addColor(dog) {
let copyDog = Object.assign({}, dog);
copyDog.color = 'white';
return copyDog;
}
Copy the code
In this way, the properties of the dog object are not modified, and the addColor function is pure.
2.4.3 return null
Null is a bit of a hassle to handle, requiring judgment, resulting in extra code that should either return an empty object, or an empty array, or throw an exception.