Functions, Methods and Tricks [PART 1] By albro
This post focuses specifically on writing clean functions. Remember that methods are actually functions inside an object and structurally there is no difference between methods and functions, so all topics covered in this post will be for both.
Defining and calling functions
To be able to write clean functions or methods, we must be familiar with its two different modes. Consider the following simple function:
function add(n1, n2) {
return n1 + n2;
}
This function definition is a javascript function and when we call it, we will have something like this:
add(5, 13)
This code is called "function call" or "function invocation" in English. When we talk about the cleanliness of functions, we mean both parts: Both defining the function and calling it!
Quantity in the number of parameters, quality in readability
To keep the function calling part clean, you should keep the number of parameters as low as possible. The more parameters you have in the function definition, the more values you have to pass when calling it, and the more unreadable the code becomes. The best case is that your functions have no parameters! For example, if we have a method called save()
on the user
object, there is no need to pass the parameter:
user.save()
This code is very simple and it will be very easy to call. Of course, you have to be realistic and you can't write all the code in such a way that no parameters are needed. The problem here is to reduce the number of these parameters as much as possible.
In the next step you may have a parameter:
log(message)
This function is very easy to understand and it is also simple. The next mode is two parameters:
point(10, 20)
Understanding this function is also acceptable because the number of parameters is not many, but it is a little more difficult than the previous ones. Why? Because now the order of the parameters will be important! Of course, to make a point, we can guess that we need X and Y points, so it is still not a problem for us to understand. What if we reach three parameters?
calc(5, 10, 'subtract')
This function takes three arguments: the first and second arguments are the numbers that must be entered into a type of mathematical operation, and the third argument specifies the type of this mathematical operation. As you can guess, understanding this function has become more complicated and requires it to be a waste of time and study. For example, it is currently not known how the subtraction operation is performed; Does 5 decrease from 10 (result of 5) or does 10 decrease from 5 (result of -5)? In this case, the order of the arguments is not clear at all and creates problems for us. If you can, avoid defining such functions because they will be problematic.
Finally, if you defined a function that had more than 3 arguments, you should know that you probably implemented the function incorrectly. I strongly suggest that you discard the definition of such functions. Note the following function call:
coords(10, 3, 9, 12)
This function is very confusing and strange and it is almost impossible to understand unless we go to the source code and read its definition. You might ask what if my function needs more data? For example, we have a function that needs 5 different data, how to solve this problem?
Reduce the number of parameters
There are different ways to reduce the number of parameters. In this section, I will examine several different modes. The first mode is to break the function into other functions or rewrite it in other paradigms. For example, consider the following function:
function saveUser(email, password) {
const user = {
id: Math.random().toString(),
email: email,
password: password,
};
db.insert("users", user);
}
saveUser("[email protected]", "mypassword");
This code takes the user's email and password and stores the user in the database. The problem here is that our function has two parameters, so we need to know the order of email and password. Although the above code is not bad at all, remembering the order of the parameters is considered a negative point. how? In the above function, we have created the user object and stored it in the database. We can do this operation using two functions so that this function stores only one user:
function saveUser(user) {
db.insert("users", user);
}
saveUser(newUser);
That is, leave the construction of the user
object to another function. Another and even better method we have is to use classes to get such code:
class User {
constructor(email, password) {
this.email = email;
this.password = password;
this.id = Math.random().toString();
}
save() {
db.insert("users", this);
}
}
const user = new User("[email protected]", "mypassword");
user.save();
As you can see, in this example, the save
method is called without any arguments, so it is much cleaner and better to read. Of course, there are other ways. For example, we can have a normal function and receive an object containing an email and password as an argument.
Of course, this depends on the status of your codes. For example, consider the following code:
function log(message) {
console.log(message);
}
log('Hi there!');
This code is responsible for logging a certain value and it does not have any problems in appearance. In my opinion, writing this code using classes is not an interesting task because the number of lines of code increases and we don't need to write complex codes for a simple task:
class Message {
constructor(message) {
this.message = message;
}
log() {
console.log(this.message);
}
}
const msg = new Message('Hi!');
msg.log();
As you can see in this code, both the trouble of defining the class and the trouble of using it is much more than a normal function.
As a general rule, it can be considered that if the functions are not specified when they are called, it means that it is possible to upgrade the codes. For example, the:
log('hi there', false);
Here it is clear that log
wants to log a specific value, so the first argument is easy to understand. Where does the second argument (false
) come from and what does it mean? To understand this code, we have to refer to the source code to understand what the second argument does:
function log(message, isError) {
if (isError) {
console.error(message);
} else {
console.log(message);
}
}
log("hello there", false);
Now we understand that the second argument has the task of detecting the error of the printed message, so that if our message is an error, we print it with the error
method, and otherwise we display it with the normal log
. Although it cannot be said that the code above is bad code, it can be said that there is room for improvement and we can still improve it completely. For example, the:
function log(message) {
console.log(message);
}
function logError(message) {
console.error(message);
}
log("hello there");
logError("something went wrong");
In this case, whatever function we call, it is clear what exactly it does and there is no need to look at the source code. It should be noted that this method also increases the speed of the system because we no longer need to write if
conditions to check different situations.
Another problem is the situations in which we face a large number of values and we cannot reduce them or break the function into smaller functions. Consider the following example:
class User {
constructor(name, age, email) {
this.name = name;
this.age = age;
this.email = email;
}
}
const user = new User("albro", 27, "[email protected]");
Each user has a specific name, age, and email, and we cannot break these values into smaller values, so we need to find a better way. I say again that the code above is not bad, but there is still room for improvement because the order of age, email, and name is not clear when calling it. I ask you to think for yourself and find a solution to this problem. I already mentioned the solution; Instead of passing the values individually, we can send them as a single object!
class User {
constructor(userData) {
this.name = userData.name;
this.age = userData.age;
this.email = userData.email;
}
}
const user = new User({ name:"albro", age: 27, email: "[email protected]" });
Now, if you look at this code, you will notice the big difference. In practice, both codes do the same thing and have no difference in terms of speed and optimality, but this code is much more readable.
I have prepared another example for you. The following method is responsible for comparing different values and reports to us that one value is smaller or larger than other values, etc.:
function compare(a, b, comparator) {
if (comparator === 'equal') {
return a === b;
} else if (comparator === 'not equal') {
return a !== b;
} else if (comparator === 'greater') {
return a > b;
} else if (comparator === 'smaller') {
return a < b;
}
}
const isSmaller = compare(3, 5, 'smaller');
const isEqual = compare(3, 5, 'equal');
This function is responsible for comparing two numbers, so we have no way to break it into smaller functions. The only solution that remains for us is to reduce the number of parameters of this function to determine exactly what the passed values are. For example, if we pass the numbers 3 and 5 above and smaller
as the third argument, how does the function perform the comparison? Does it compare 5 to 3 or does it compare 3 to 5? This issue has a great impact on the final result; For example, 5 is not smaller than 3, but 3 is smaller than 5.
Try to do it yourself and then compare your answer with the following example:
function compare(comparisonData) {
const { first, second, comparator } = comparisonData;
if (comparator === 'equal') {
return first === second;
} else if (comparator === 'not equal') {
return first !== second;
} else if (comparator === 'greater') {
return first > second;
} else if (comparator === 'smaller') {
return first < second;
}
}
const isSmaller = compare({ first: 3, second: 5, comparator: 'smaller' });
const isSmaller = compare({ comparator: 'equal', first: 3, second: 5 });
By doing this, we can easily understand which numbers are the first number and the second number and how the comparison is done.
Congratulations @albro! You have completed the following achievement on the Hive blockchain And have been rewarded with New badge(s)
Your next target is to reach 70 posts.
You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word
STOP
To support your work, I also upvoted your post!
Check out our last posts:
Congratulations!
✅ Good job. Your post has been appreciated and has received support from CHESS BROTHERS ♔ 💪
♟ We invite you to use our hashtag #chessbrothers and learn more about us.
♟♟ You can also reach us on our Discord server and promote your posts there.
♟♟♟ Consider joining our curation trail so we work as a team and you get rewards automatically.
♞♟ Check out our @chessbrotherspro account to learn about the curation process carried out daily by our team.
🥇 If you want to earn profits with your HP delegation and support our project, we invite you to join the Master Investor plan. Here you can learn how to do it.
Kindly
The CHESS BROTHERS team
Thanks for your contribution to the STEMsocial community. Feel free to join us on discord to get to know the rest of us!
Please consider delegating to the @stemsocial account (85% of the curation rewards are returned).
You may also include @stemsocial as a beneficiary of the rewards of this post to get a stronger support.
https://inleo.io/threads/albro/re-leothreads-qrpehewt
The rewards earned on this comment will go directly to the people ( albro ) sharing the post on LeoThreads,LikeTu,dBuzz.