Like Objects in Node.js and Javascript. What's really important. “Functions in Node.js and JavaScript. What's really important” refers to the principles behind functions, which is really important to continue learning, improve your understanding of functions in programming, Node.js and in Javascript.
Before talking about functions in Node.js and JavaScript, it is worth remembering or defining what a function is in programming.
What are functions?
Functions are a very important element in any programming language. We know that the functional programming was even invented before any programming language based on the lambda calculation of Alonzo Church.
In the first programming languages, subroutines, procedures and functions were used. Subroutines, procedures and functions have in common that they group a set of operations with the purpose of reusing them many times and only writing them once.
Functions, unlike procedures and subroutines, are still used in modern programming languages, and are the smallest unit of code organization. They are used to define the behavior of objects, composing them with specific functionalities. Let's remember another post that the Objects are a group of functionalities that contribute to communication with other objects.
Without functions, an object wouldn't be of much use. Functions define the behavior of objects. And it also forms larger functions. In conclusion, the functions serve us for.
- Organize the code
- Reuse code
- It is used for the composition of objects, adding behaviors.
- It is used for the composition of more complicated functions
What are functions in Node.js and JavaScript?
In Node.js and JavaScript, and indeed in any environment where JavaScript is executed, functions are everything described in the previous section. And also They are objects.
- Since they are objects, they can be treated like any other value:
- They can be assigned to variables and properties of other objects
- Create them dynamically during the execution of the JavaScript code
- Have its properties and methods
- Be parameters for another function
- Be the return value of a function
- Additionally, the body of a function provides local scope to variables and parameters.
Although it is not the topic of this post, all the features listed make JavaScript can be used as a functional programming language.
How to create functions in Node.js and JavaScript?
The three recommended ways to create functions are as follows.
- Normal declaration
- Function as expression
- Arrow functions
Function declaration
This is the most common method, very similar in other programming languages. The reserved word is used functions
, followed by the function name, then a list of arguments in parentheses, which are separated by commas. This argument list is optional.
Finally the function body using braces { }
. The body of the function contains the statements you need.
functions name(argumento1, argumento2, ...argumentoN) {
// sentencias
}
Concrete example:
functions sumar(to, b) {
return to + b;
}
sumar(1, 2); // 3
To execute the function code it is necessary to invoke it. The invocation is made with a pair of parentheses and the necessary arguments inside, separated by commas. Just like the previous example.
A function always returns some value, even if it is not explicitly defined. If you do not define what a function returns, by default the return value will be undefined
.
functions sumarSinReturn(to, b) {
const resultado = to + b;
}
sumarSinReturn(1, 2); // undefined
If we execute the function, it returns undefined
because we don't explicitly tell it to return some value
Function in expression form
This way of creating functions is much more flexible, its definition can appear wherever an expression can be defined. That gives it the ability to be assigned to a variable or a property of an object.
Its syntax is the same as the declaration of a function that we saw previously, but when assigned to a variable or property, its name is optional.
functions [nombreOpcional](argumento1, argumento2, ...argumentoN) {
// sentencias
}
Next we will see some examples.
// Sin nombre, tambie conocida como funcion anonima
const sumar = functions(to, b) {
return to + b;
};
// Con nombre
const sumar = functions sumar(to, b) {
return to + b;
};
const calculadora = {
sumar: functions(to, b) {
return to + b;
}
};
const person = {
// como propiedad de un objeto
eat: functions() {
return 'Comiendo...';
}
};
Arrow functions
Arrow functions are the newest way to create functions, much more similar to mathematical functions in algebra. They feel very convenient because their syntax is much more reduced. They are an alternative to functions in the form of expressions, they are faster to write. However, it has many limitations compared to the other two ways of creating functions. Although if you use them for functional programming they are quite effective.
To be honest, it seems to me that if its use is not focused on functional programming, it does add more complexity to the use of functions in JavaScript, in itself the functions in Node.js and Javascript can be very different compared to other languages.
But well, let's look at its syntax.
argumento => expresión;
// Com mas de un arguento es necesario parentesis
(argumento1, argumentN) => expresión;
// Con varias lineas de sentencias, es necesario las llaves {}
argumento => {
// sentencias
};
// Con mas de un argumento y con varias lineas se sentencias
(argumento1, argumentoN) => {
// sentencias
};
// Sin argumentos es necesario los parentesis
() => expresión
When using expressions, it is not necessary to explicitly define the return
. The result of the expression is the return value.
const calcularCuadrado = to => to * to;
const sumar = (to, b) => to + b;
const greet = () => 'Hola';
// invocaciones
calcularCuadrado(5); // 25
sumar(1, 2); // 3
greet(); // 'Hola'
When we want the body of the function to have several lines of statements, curly braces are used. Furthermore, if we want the function to return some value, then we explicitly use the syntax of return
.
Examples.
const calcularCuadrado = to => {
const result = to * to;
return result;
};
const sumar = (a, b) = > {
const result = to + b;
return result;
};
// invocaciones
calcularCuadrado(5); // 25
sumar(1, 2); // 3
Nested or internal functions
A function can be defined inside another function, that is, we can dynamically create internal functions inside another main function and invoke them.
functions greet() {
functions saludarInterna() {
return 'Hola';
}
const saludo = saludarInterna();
console.log(saludo);
}
greet(); // 'Hola'
In the next section we will see other nested functions.
Local scope of functions
Functions in Node.js and JavaScript provide a scope of values, local to the body of the function, that is, what is defined in the body of the function can only be referenced within the function.
functions grandfather() {
const name = 'Jaime';
const last name = 'Cervantes'
functions father() {
const last name = 'Good day';
functions son() {
const last name = 'Pérez';
const nombreCompleto = `${name} ${last name}`;
console.log(nombreCompleto); // Jaime Pérez
}
son();
const nombreCompleto = `${name} ${last name}`;
console.log(nombreCompleto); // Jaime Buendía
}
father();
const nombreCompleto = `${name} ${last name}`;
console.log(nombreCompleto); // Jaime Cervantes
}
grandfather();
Internal functions can access the variables of their parent function (so to speak). In the previous example you can see that the function son
or you can refer to the constant name
of the function grandpa
either. This produces us Jaime Perez
. In the next section we explain it better
Closures or closures
Function nesting allows child functions to have their own local scope, hidden from parent functions. At the same time these internal functions have access to the values defined in the parent functions. This encapsulation of information and at the same time access to external information is called closure.
Let's continue with the example from the previous section, the functions grandfather
, father
and son
functions grandfather() {
const name = 'Jaime';
const last name = 'Cervantes'
functions father() {
const last name = 'Good day';
functions son() {
const last name = 'Pérez';
const nombreCompleto = `${name} ${last name}`;
console.log(nombreCompleto); // Jaime Pérez
}
son();
const nombreCompleto = `${name} ${last name}`;
console.log(nombreCompleto); // Jaime Buendía
}
father();
const nombreCompleto = `${name} ${last name}`;
console.log(nombreCompleto); // Jaime Cervantes
}
grandfather();
The result of the function invocation grandfather
is:
Jaime Pérez --> From son function Jaime Buendía --> From father function Jaime Cervantes --> From grandfather function
The more internal the function, the more scope it has to all the areas of the other “external parent” functions. Like the image below, it is as if the function scopes grandfather
and father
were within the scope of the function son
.
A function will always take the value of the variable that is closest to its own local scope. The variables within their own local scope are the most relevant. This allows variable and constant names to not collide between nested scopes.
The function son
, has access to the constants name
and last name
of the function grandfather
. You also have access to the constant last name
of the function father
. But the constant last name
within the function itself son
is closer than defined in father
and grandfather
, has greater relevance. So the full name that is printed to the console is Jaime Perez instead of Jaime Buendía or Jaime Cervantes.
The function father
if you have access to the constants name
and last name
of the function grandfather
. In its own sphere it has a constant last name
equal to Good day. As this value is closer, it does not take the last name of the function grandfather
which is further away. That is why in the console the full name that is printed is Jaime Buendía. Then the function father
You do NOT have access to the constant last name
of the function son
.
Finally it prints to the console Jaime Cervantes Velasco because the constants name
and last name
They are defined at the local level of the grandfather function. The grandfather function does NOT have access to constants last name
of its internal functions father
and son
.
OOP emerged from functions
Now that we've seen a little about nested functions and closures, we can talk about how object-oriented programming was discovered. This reflects the importance of functions in programming languages.
Ole Johan Dahl and Kristen Nygaard realized that the function call stack in ALGOL could be moved to a Heap. This allows variables declared by a function to exist even after the function finishes executing and returns some value.
In this way the function became the constructor of the class, the local variables became properties of the class instance, and the internal functions became its methods. And so in 1966 object-oriented programming was discovered.
We can implement this behavior using functions in Node.js and JavaScript and taking advantage of their ability to create closures.
functions createPerson(name, last name) {
functions greet() {
return `Hola soy ${name}...`;
}
functions eat() {
return 'Comiendo...';
}
functions getName() {
return `${name} ${last name}`;
}
const instancia = {};
instancia.greet = greet;
instancia.eat = eat;
instancia.getName = getName;
return instancia
}
const James = createPerson('Jaime', 'Cervantes');
James.eat(); // Comiendo...
James.greet(); // Hola soy Jaime
James.getName(); // Jaime Cervantes
The parameters name
and last name
, are within the local scope of the function createPerson
, so they work just like variables inside the function body. The inner functions continue to have access to those parameters even after the parent function returns its value, an object literal that is the instance of a person.
Then when the instance James
invokes its method getName
, this property refers to the internal function getName
of the function createPerson
. Due to internal function closure getName
, we have access to the parameters name
and last name
even long after the parent function createPerson
has returned its value.
Function Names in Node.js and Javascript
We have to be aware that programming and software development is a social activity, with a lot of communication. And the more efficient this communication is, the greater the success of the software. This allows us to save the time and financial resources of everyone involved. I'm talking about programmers and non-programmers, investors, clients and users.
One of the forms of communication between fellow programmers and often oneself in the future is through easy-to-understand code, and to contribute to this easy understanding we must choose the name of our functions very carefully.
Take into account the following recommendations. But keeping in mind that these are only examples, and when it comes to writing your real functions and with the proper context, you will most likely be able to come up with better function names than those shown here.
Spend enough time naming your role.
Just as important as naming the variables is the functions. Functions are the smallest units that allow us to define behaviors in applications. The time spent naming your functions is much less than the time you have to spend later on yourself and your colleagues trying to figure out what a function actually does. It's like organizing your room, the tidier it is, the faster you will find the things you need, the faster you will change, or the faster you will find your socks, etc.
The name must be very semantic, describe its objective
The name of a function should describe as clearly as possible what it does. It is important that be a verb because a function always performs one or more operations focused on a specific task.
For example, if a function returns the full name of a person, which of the following names fits best?
fullName()
getName();
getFullName()
The name that best describes the purpose of the function is getFullName
.
If the function returns a boolean, the function name must indicate that the result can be true or false. Just like the result of a logical condition. It's like asking a question whose possible answers can only be yes or no.
hasChildren(person) {
return Boolean(person.childre.length);
}
if (hasChildren(currentPerson)) {
// Haz algo
}
Yeah hasChildren
If it were a method, it would look like this.
if (currentPerson.hasChildren()) {
// Haz algo
}
You notice how the condition reads like a very understandable phrase. If currentPerson has children, then...
do something.
Avoid wrong assumptions
If the name describes things it doesn't actually do, then we should rename that function. For example, if a function forms the full name of a customer and returns that name. Which feature best prevents erroneous assumptions?
functions setClientName() {} // Se entiende que el nombre del cliente va a ser modificado
functions getFullClientName() {} // Aquí esta claro que solo consigue el nomnbre completo del cliente
setCustomerName
It tells us that the client's name will be changed, it is a bad name. So the name that best avoids erroneous assumptions is getFullClientName
. It does not say what forms the name, but it does say that it will return a full name. For practical purposes we are not interested in knowing how that full name is formed, just that it does not return them.
Agreements with programmers
It is very important to establish agreements for the appointment of functions. In the previous examples I have been using the prefix get
which indicates that I send to obtain something. But it would be confusing if some programmers used the word fetch
and others the word retrieve
, and others collect
either bring
.
Use the right context
It is important to understand the context of the function, in previous examples we used the function getFullClientName
, but depending on the context of the application, it might be better getFullUserName
either getFullEmployeeName
.
Although these names have to do with the context of the business or problem, there are also technical terms that programmers are already very accustomed to and should not be mixed with the problem domain.
For example, the observer design pattern contains methods like update
, subscribe
, publish
, notify
. If we are working with a magazine application that uses native cell phone notifications, SMS, and makes periodic publications. This can also create confusion, so you should name functions very carefully in such a way that you distinguish between functions or methods of the design pattern and others related to the business.
Function scope helps name length
The name of the functions can be long or short depending on the scope it has in the software. For example, a function that is used a lot in different files is worth keeping its name short. Because if many people use it, it is important that it is easy to write and pronounce.
On the other hand, if it is a function that is only used in a file, its name can be long, these types of functions are normally used internally by other functions with short names. So long name functions are a way to explain what the short name function does. This doesn't mean it can't be short, but if you need more words to better describe the feature, go ahead.
As an example, let's imagine a function that returns the total of your profits to the current date of your entire investment portfolio. Where the profits are the sum of the interest on your investments plus the contributions you have made to date.
// funcion corta, reutilizable en otros archivos o aplicaciones
functions getEarnings() {
return calculateEarnings();
}
// funciones con nombre más largo que describen a la funcion corta
functions calculateEarnings() {
const earnings = calculateCurrentTotalInterest();
const aditionals = calculateCurrentTotalAdditionalContributions();
return earnings + aditionals;
}
functions calculateCurrentTotalInterest() {}
functions calculateCurrentAdditionalContributions() {}
Don't worry so much about these examples, the goal is to give you an idea. In a future publication we will make a small application where we will see how to apply these recommendations.
Conclusions
Functions in Node.js and Javascript is a fairly broad topic, it is one of the best done things in JavaScript that reveal the power of the language. It is noted that Javascript is influenced by LISP and Scheme.
Likewise, let's not forget to name our functions correctly, they are the smallest units that allow the software to be organized into well-defined behaviors.
Functional programming is the first programming paradigm invented, hence the importance of functions, because it is a paradigm from which object-oriented programming took its bases.
Let's not forget that functions in Node.js and JavaScript are objects and therefore can be treated like any value.
We are still missing several important feature topics. These are addressed in this post. If you have any questions, do not hesitate to write them in the comments, we will be happy to help you!
If you want, as an exercise, you can translate all the examples into functions in the form of expression and arrow functions. Have fun!