Funciones
Las funciones son uno de los bloques de construcción fundamentales en JavaScript. Una función en JavaScript es similar a un procedimiento — un conjunto de instrucciones que realiza una tarea o calcula un valor, pero para que un procedimiento califique como función, debe tomar alguna entrada y devolver una salida donde hay alguna relación obvia entre la entrada y la salida. Para usar una función, debes definirla en algún lugar del ámbito desde el que deseas llamarla.
Consulta también elcapítulo de referencia exhaustivo sobre funciones de JavaScript
para conocer los detalles.
Definir funciones
Declaración de función
Unadefinición de función (también denominadadeclaración de función oexpresión de función) consta de la palabra clavefunction
, seguida de:
- El nombre de la función.
- Una lista de parámetros de la función, entre paréntesis y separados por comas.
- Las declaraciones de JavaScript que definen la función, encerradas entre llaves,
{ ... }
.
Por ejemplo, el siguiente código define una función simple llamadasquare
("cuadrado"):
function square(number) { return number * number;}
La funciónsquare
toma un parámetro, llamadonumber
. La función consta de una declaración que dice devuelva el parámetro de la función (es decir,number
) multiplicado por sí mismo. La instrucciónreturn
especifica el valor devuelto por la función:
return number * number;
Los parámetros primitivos (como unnumber
) se pasan a las funcionespor valor; el valor se pasa a la función, pero si la función cambia el valor del parámetro,este cambio no se refleja globalmente ni en la función que llama.
Si pasas un objeto (es decir, un valor no primitivo, comoArray
o un objeto definido por el usuario) como parámetro y la función cambia las propiedades del objeto, ese cambio es visible fuera de la función, como se muestra en el siguiente ejemplo:
function myFunc(theObject) { theObject.make = 'Toyota';}[parcial]var mycar = { make: 'Honda', model: 'Accord', year: 1998 };var x, y;x = mycar.make; // x obtiene el valor "Honda"myFunc(mycar);y = mycar.make; // y obtiene el valor "Toyota" // (la propiedad make fue cambiada por la función)
Expresionesfunction
Si bien la declaración de función anterior sintácticamente es una declaración, las funciones también se pueden crear mediante unaexpresión function
.
Esta función puede seranónima; no tiene por qué tener un nombre. Por ejemplo, la funciónsquare
se podría haber definido como:
const square = function (number) { return number * number;};var x = square(4); // x obtiene el valor 16
Sin embargo,puedes proporcionar un nombre con una expresiónfunction
. Proporcionar un nombre permite que la función se refiera a sí misma y también facilita la identificación de la función en el seguimiento de la pila de un depurador:
const factorial = function fac(n) { return n < 2 ? 1 : n * fac(n - 1);};console.log(factorial(3));
Las expresionesfunction
son convenientes cuando se pasa una función como argumento a otra función. El siguiente ejemplo muestra una funciónmap
que debería recibir una función como primer argumento y un arreglo como segundo argumento.
function map(f, a) { let result = []; // Crea un nuevo arreglo let i; // Declara una variable for (i = 0; i != a.length; i++) result[i] = f(a[i]); return result;}
En el siguiente código, la función recibe una función definida por una expresión de función y la ejecuta por cada elemento del arreglo recibido como segundo argumento.
function map(f, a) { let result = []; // Crea un nuevo arreglo let i; // Declara una variable for (i = 0; i != a.length; i++) result[i] = f(a[i]); return result;}const f = function (x) { return x * x * x;};let numbers = [0, 1, 2, 5, 10];let cube = map(f, numbers);console.log(cube);
La función devuelve:[0, 1, 8, 125, 1000]
.
En JavaScript, una función se puede definir en función de una condición. Por ejemplo, la siguiente definición de función definemyFunc
solo sinum
es igual a0
:
var myFunc;if (num === 0) { myFunc = function (theObject) { theObject.make = "Toyota"; };}
Además de definir funciones como se describe aquí, también puedes usar el constructorFunction
para crear funciones a partir de una cadena en tiempo de ejecución, muy al estilo deeval()
.
Unmétodo es una función que es propiedad de un objeto. Obten más información sobre objetos y métodos enTrabajar con objetos
.
Llamar funciones
Definir una función no laejecuta. Definirla simplemente nombra la función y especifica qué hacer cuando se llama a la función.
Llamar a la función en realidad lleva a cabo las acciones especificadas con los parámetros indicados. Por ejemplo, si defines la funciónsquare
, podrías llamarla de la siguiente manera:
square(5);
La declaración anterior llama a la función con un argumento de5
. La función ejecuta sus declaraciones y devuelve el valor25
.
Las funciones deben estardentro del ámbito cuando se llaman, pero la declaración de la función se puede elevar (cuando aparece debajo de la llamada en el código), como en este ejemplo:
console.log(square(5));/* ... */function square(n) { return n * n;}
El ámbito de una función es la función en la que se declara (o el programa completo, si se declara en el nivel superior).
Nota:Esto solo trabaja cuando se define la función usando la sintaxis anterior (es decir,function funcName() {}
). El siguiente código no trabajará.Esto significa que la elevación de función solo trabaja condeclaraciones de función, no conexpresiones de función.
console.log(square) // square se eleva con un valor inicial undefined.console.log(square(5)) // Error de tipo no detectado: square no es una funciónconst square = function(n) {return n \* n;}
Los argumentos de una función no se limitan a cadenas y números. Puedes pasar objetos completos a una función. La funciónshow_props()
(definida enTrabajar con objetos
es un ejemplo de una función que toma un objeto como argumento.
Una función se puede llamar a sí misma. Por ejemplo, aquí hay una función que calcula factoriales de forma recursiva:
function factorial(n) { if (n === 0 || n === 1) return 1; else return n * factorial(n - 1);}
Luego, podrías calcular los factoriales de1
a5
de la siguiente manera:
var a, b, c, d, e;a = factorial(1); // a obtiene el valor 1b = factorial(2); // b obtiene el valor 2c = factorial(3); // c obtiene el valor 6d = factorial(4); // d obtiene el valor 24e = factorial(5); // e obtiene el valor 120
Hay otras formas de llamar funciones. A menudo hay casos en los que una función se tiene que llamar dinámicamente, o el número de argumentos de una función varía, o en los que el contexto de la llamada a la función se tiene que establecer en un determinado objeto específico en tiempo de ejecución.
Resulta que lasfunciones en sí mismas son objetos y, a su vez, estos objetos tienen métodos. (Consulta el objetoFunction
. Uno de estos, el métodoapply()
, se puede utilizar para lograr este objetivo.
Ámbito defunction
No se puede acceder a las variables definidas dentro de una función desde cualquier lugar fuera de la función, porque la variable se define solo en el ámbito de la función. Sin embargo, una función puede acceder a todas las variables y funciones definidas dentro del ámbito en el que está definida.
En otras palabras, una función definida en el ámbito global puede acceder a todas las variables definidas en el ámbito global. Una función definida dentro de otra función también puede acceder a todas las variables definidas en su función principal y a cualquier otra variable a la que tenga acceso la función principal.
// Las siguientes variables se definen en el ámbito globalvar num1 = 20, num2 = 3, name = "Chamahk";// Esta función está definida en el ámbito globalfunction multiply() { return num1 * num2;}multiply(); // Devuelve 60// Un ejemplo de función anidadafunction getScore() { var num1 = 2, num2 = 3; function add() { return name + " anotó " + (num1 + num2); } return add();}getScore(); // Devuelve "Chamahk anotó 5"
Ámbito y la pila de funciones
Recursión
Una función se puede referir y llamarse a sí misma. Hay tres formas de que una función se refiera a sí misma:
- El nombre de la función
arguments.callee
- Una variable dentro del ámbito que se refiere a la función
Por ejemplo, considera la siguiente definición de función:
var foo = function bar() { // las instrucciones van aquí};
Dentro del cuerpo de la función, todos los siguientes son equivalentes:
bar()
arguments.callee()
foo()
Una función que se llama a sí misma se conoce como unafunción recursiva. En cierto modo, la recursividad es análoga a un bucle. Ambas ejecutan el mismo código varias veces y ambas requieren una condición (para evitar un bucle infinito, o más bien, una recursividad infinita en este caso).
Por ejemplo, el siguiente bucle...
var x = 0;while (x < 10) { // "x < 10" es la condición del bucle // hacer cosas x++;}
...se puede convertir en una declaración de función recursiva, seguida de una llamada a esa función:
function loop(x) { if (x >= 10) // "x >= 10" es la condición de salida (equivalente a "!(x < 10)") return; // hacer cosas loop(x + 1); // la llamada recursiva}loop(0);
Sin embargo, algunos algoritmos no pueden ser simples bucles iterativos. Por ejemplo, obtener todos los nodos de una estructura de árbol (comoDOM) es más fácil a través de la recursividad:
function walkTree(node) { if (node == null) // return; // hacer algo con el nodo for (var i = 0; i < node.childNodes.length; i++) { walkTree(node.childNodes[i]); }}
En comparación con la funciónloop
, cada llamada recursiva en sí misma hace muchas llamadas recursivas aquí.
Es posible convertir cualquier algoritmo recursivo en uno no recursivo, pero la lógica suele ser mucho más compleja, y hacerlo requiere el uso de una pila.
De hecho, la recursividad en sí misma usa una pila: la pila de funciones. El comportamiento similar a una pila se puede ver en el siguiente ejemplo:
function foo(i) { if (i < 0) return; console.log("inicio: " + i); foo(i - 1); console.log("fin: " + i);}foo(3);// Produce:// inicio: 3// inicio: 2// inicio: 1// inicio: 0// fin: 0// fin: 1// fin: 2// fin: 3
Funciones anidadas y cierres
Puedes anidar una función dentro de otra función. La función anidada (interna) es privada de su función contenedora (externa).
También forma uncierre. Un cierre es una expresión (comúnmente, una función) que puede tener variables libres junto con un entorno que une esas variables (que "cierra" la expresión).
Dado que una función anidada es un cierre, significa que una función anidada puede "heredar" los argumentos y variables de su función contenedora. En otras palabras, la función interna contiene el ámbito de la función externa.
Para resumir:
Solo se puede acceder a la función interna desde declaraciones en la función externa.
La función interna forma un cierre: la función interna puede usar los argumentos y variables de la función externa, mientras que la función externa no puede usar los argumentos y variables de la función interna.
El siguiente ejemplo muestra funciones anidadas:
function addSquares(a, b) { function square(x) { return x * x; } return square(a) + square(b);}a = addSquares(2, 3); // devuelve 13b = addSquares(3, 4); // devuelve 25c = addSquares(4, 5); // devuelve 41
Dado que la función interna forma un cierre, puedes llamar a la función externa y especificar argumentos tanto para la función externa como para la interna:
function outside(x) { function inside(y) { return x + y; } return inside;}fn_inside = outside(3); // Piensa en ello como: dame una función que agregue 3 a lo que sea que le des// esoresult = fn_inside(5); // devuelve 8result1 = outside(3)(5); // devuelve 8
Preservación de variables
Observa cómo se conservax
cuando se devuelveinside
. Un cierre debe conservar los argumentos y variables en todos los ámbitos a los que hace referencia. Dado que cada llamada proporciona argumentos potencialmente diferentes, se crea un nuevo cierre para cada llamada aoutside
. La memoria se puede liberar solo cuando elinside
devuelto ya no es accesible.
Esto no es diferente de almacenar referencias en otros objetos, pero a menudo es menos obvio porque uno no establece las referencias directamente y no las puede inspeccionar.
Funciones multianidadas
Las funciones se pueden anidar de forma múltiple. Por ejemplo:
- Una función (
A
) contiene una función (B
), que a su vez contiene una función (C
). - Ambas funciones
B
yC
forman cierres aquí. Por tanto,B
puede acceder aA
yC
puede acceder aB
. - Además, dado que
C
puede acceder aB
que puede acceder aA
,C
también puede acceder aA
.
Por tanto, los cierres pueden contener múltiples ámbitos; contienen de forma recursiva el ámbito de las funciones que la contienen. Esto se llamaencadenamiento de alcance. (La razón por la que se llama "encadenamiento" se explica más adelante).
Considera el siguiente ejemplo:
function A(x) { function B(y) { function C(z) { console.log(x + y + z); } C(3); } B(2);}A(1); // registra 6 (1 + 2 + 3)
En este ejemplo,C
accede ay
deB
y ax
deA
.
Esto se puede hacer porque:
B
forma un cierre que incluye aA
(es decir,B
puede acceder a los argumentos y variables deA
).C
forma un cierre que incluye aB
.- Debido a que el cierre de
B
incluye aA
, el cierre deC
incluye aA
,C
puede acceder a los argumentosy variables deB
y deA
. En otras palabras,C
encadena los ámbitos deB
yA
,en ese orden.
Sin embargo, lo contrario no es cierto.A
no puede acceder aC
, porqueA
no puede acceder a ningún argumento o variable deB
, del queC
es una variable. Por lo tanto,C
permanece privado solo paraB
.
Conflictos de nombres
Cuando dos argumentos o variables en el ámbito de un cierre tienen el mismo nombre, hay unconflicto de nombres. Tiene más prioridad el ámbito anidado. Entonces, el ámbito más interno tiene la mayor prioridad, mientras que el ámbito más externo tiene la más baja. Esta es la cadena de ámbito. El primero de la cadena es el ámbito más interno y el último es el ámbito más externo. Considera lo siguiente:
function outside() { var x = 5; function inside(x) { return x * 2; } return inside;}outside()(10); // devuelve 20 en lugar de 10
El conflicto de nombre ocurre en la declaraciónreturn x
y está entre el parámetrox
deinside
y la variablex
deoutside
. La cadena de ámbito aquí es {inside
,outside
, objeto global}. Por lo tanto,x
deinside
tiene precedencia sobrex
deoutside
y20
(x
) deinside
se devuelve en lugar de10
(x
deoutside
).
Cierres
Los cierres son una de las características más poderosas de JavaScript. JavaScript permite el anidamiento de funciones y otorga a la función interna acceso completo a todas las variables y funciones definidas dentro de la función externa (y todas las demás variables y funciones a las que la función externa tiene acceso).
Sin embargo, la función externano tiene acceso a las variables y funciones definidas dentro de la función interna. Esto proporciona una especie de encapsulación para las variables de la función interna.
Además, dado que la función interna tiene acceso a el ámbito de la función externa, las variables y funciones definidas en la función externa vivirán más que la duración de la ejecución de la función externa, si la función interna logra sobrevivir más allá de la vida de la función externa. Se crea un cierre cuando la función interna de alguna manera se pone a disposición de cualquier ámbito fuera de la función externa.
var pet = function (name) { // La función externa define una variable llamada "name" var getName = function () { return name; // La función interna tiene acceso a la variable // "name" de la función externa }; return getName; // Devuelve la función interna, exponiéndola así a ámbitos externos};myPet = pet("Vivie");myPet(); // Devuelve "Vivie"
Puede ser mucho más complejo que el código anterior. Se puede devolver un objeto que contiene métodos para manipular las variables internas de la función externa.
var createPet = function (name) { var sex; return { setName: function (newName) { name = newName; }, getName: function () { return name; }, getSex: function () { return sex; }, setSex: function (newSex) { if ( typeof newSex === "string" && (newSex.toLowerCase() === "male" || newSex.toLowerCase() === "female") ) { sex = newSex; } }, };};var pet = createPet("Vivie");pet.getName(); // Viviepet.setName("Oliver");pet.setSex("male");pet.getSex(); // malepet.getName(); // Oliver
En el código anterior, la variablename
de la función externa es accesible para las funciones internas, y no hay otra forma de acceder a las variables internas excepto a través de las funciones internas. Las variables internas de las funciones internas actúan como almacenes seguros para los argumentos y variables externos. Contienen datos "persistentes" y "encapsulados" para que trabajen las funciones internas. Las funciones ni siquiera tienen que estar asignadas a una variable o tener un nombre.
var getCode = (function () { var apiCode = "0]Eal(eh&2"; // Un código que no queremos que los externos puedan modificar... return function () { return apiCode; };})();getCode(); // Devuelve el apiCode
Nota:¡Hay una serie de trampas a tener en cuenta al usar cierres!
Si una función encerrada define una variable con el mismo nombre que una variable en el ámbito externo, entonces no hay forma de hacer referencia a la variable en el ámbito externo nuevamente. (La variable de ámbito interno "anula" la externa, hasta que el programa sale de el ámbito interno).
var createPet = function (name) { // La función externa define una variable llamada "name". return { setName: function (name) { // La función envolvente también define una variable llamada "name". name = name; // ¿Cómo accedemos al "name" definido por la función externa? }, };};
Usar el objetoarguments
Elarguments
de una función se mantiene en un objeto similar a un arreglo. Dentro de una función, puedes abordar los argumentos que se le pasan de la siguiente manera:
arguments[i];
dondei
es el número ordinal del argumento, comenzando en0
. Entonces, el primer argumento que se pasa a una función seríaarguments[0]
. El número total de argumentos se indica mediantearguments.length
.
Usando el objetoarguments
, puedes llamar a una función con más argumentos de los que formalmente declara aceptar. Esto suele ser útil si no sabes de antemano cuántos argumentos se pasarán a la función. Puedes usararguments.length
para determinar el número de argumentos que realmente se pasan a la función, y luego acceder a cada argumento usando el objetoarguments
.
Por ejemplo, considera una función que concatena varias cadenas. El único argumento formal para la función es una cadena que especifica los caracteres que separan los elementos a concatenar. La función se define de la siguiente manera:
function myConcat(separator) { var result = ""; // inicia list var i; // itera a través de arguments for (i = 1; i < arguments.length; i++) { result += arguments[i] + separator; } return result;}
Puedes pasar cualquier número de argumentos a esta función, y concatena cada argumento en una "lista" de cadenas:
// devuelve "red, orange, blue, "myConcat(", ", "red", "orange", "blue");// devuelve "elephant; giraffe; lion; cheetah"myConcat("; ", "elephant", "giraffe", "lion", "cheetah");// devuelve "sage. basil. oregano. pepper. perejil. "myConcat(". ", "salvia", "albahaca", "orégano", "pimienta", "perejil");
Nota:La variablearguments
es "similar a un arreglo", pero no es un arreglo. Es similar a un arreglo en el sentido de que tiene un índice numerado y una propiedadlength
. Sin embargo,no posee todos los métodos de manipulación de arreglos.
Consulta el objetoFunction
en la referencia de JavaScript para obtener más información.
Parámetros de función
A partir de ECMAScript 2015, hay dos nuevos tipos de parámetros:parámetros predeterminados yparámetros resto.
Parámetros predeterminados
En JavaScript, los parámetros de las funciones están predeterminados enundefined
. Sin embargo, en algunas situaciones puede resultar útil establecer un valor predeterminado diferente. Esto es exactamente lo que hacen los parámetros predeterminados.
Sin parámetros predeterminados (preECMAScript 2015)
En el pasado, la estrategia general para establecer valores predeterminados era probar los valores de los parámetros en el cuerpo de la función y asignar un valor si eranundefined
.
En el siguiente ejemplo, si no se proporciona ningún valor parab
, su valor seríaundefined
al evaluara * b
, y una llamada amultiply
normalmente habría devueltoNaN
. Sin embargo, esto se evita con la segunda línea de este ejemplo:
function multiply(a, b) { b = typeof b !== "undefined" ? b : 1; return a * b;}multiply(5); // 5
Con parámetros predeterminados (posECMAScript 2015)
Conparámetros predeterminados, ya no es necesaria una verificación manual en el cuerpo de la función. Simplemente puedes poner1
como valor predeterminado parab
en el encabezado de la función:
function multiply(a, b = 1) { return a * b;}multiply(5); // 5
Para obtener más detalles, consultaparámetros predeterminados
en la referencia.
Parámetrosrest
La sintaxis delparámetro rest
nos permite representar un número indefinido de argumentos como un arreglo.
En el siguiente ejemplo, la funciónmultiply
usaparámetrosrest
para recopilar argumentos desde el segundo hasta el final. Luego, la función los multiplica por el primer argumento.
function multiply(multiplier, ...theArgs) { return theArgs.map((x) => multiplier * x);}var arr = multiply(2, 1, 2, 3);console.log(arr); // [2, 4, 6]
Funciones Flecha
Unaexpresión de función flecha
(anteriormente, y ahora conocida incorrectamente comofunción de flecha gruesa) tiene una sintaxis más corta en comparación con las expresiones de función y no tiene su propiothis
,arguments
,super
onew.target
. Las funciones flecha siempre son anónimas. Consulta también esta publicación del blog hacks.mozilla.org: "ES6 en profundidad: funciones flecha".
Dos factores influyeron en la introducción de las funciones flecha:funciones más cortas yno vinculantes dethis
.
Funciones más cortas
En algunos patrones funcionales, las funciones más cortas son bienvenidas. Compara:
var a = ["Hidrógeno", "Helio", "Litio", "Berilio"];var a2 = a.map(function (s) { return s.length;});console.log(a2); // logs [8, 6, 7, 9]var a3 = a.map((s) => s.length);console.log(a3); // logs [8, 6, 7, 9]
Sinthis
separado
Hasta las funciones flecha, cada nueva función definía su propio valorthis
(un nuevo objeto en el caso de un constructor, indefinido en llamadas a funciones enmodo estricto
, el objeto base si la función se llama como un "método de objeto", etc.). Esto resultó ser poco menos que ideal con un estilo de programación orientado a objetos.
function Person() { // El constructor Person() define `this` como él mismo. this.age = 0; setInterval(function growUp() { // En modo no estricto, la función growUp() define `this` // como el objeto global, que es diferente del `this` // definido por el constructor Person(). this.age++; }, 1000);}var p = new Person();
En ECMAScript 3/5, este problema se solucionó asignando el valor enthis
a una variable que se podría cerrar.
function Person() { var self = this; // Algunos eligen `that` en lugar de` self`. // Elige uno y se congruente. self.age = 0; setInterval(function growUp() { // La retrollamada se refiere a la variable `self` de la cual // el valor es el objeto esperado. self.age++; }, 1000);}
Alternativamente, podrías crear unafunción vinculada
para que el valorthis
adecuado se pasara a la funcióngrowUp()
.
Una función flecha no tiene su propiothis
se utiliza el valor dethis
del contexto de ejecución adjunto. Por lo tanto, en el siguiente código,this
dentro de la función que se pasa asetInterval
tiene el mismo valor quethis
en la función adjunta:
function Person() { this.age = 0; setInterval(() => { this.age++; // |this| propiamente se refiere al objeto person }, 1000);}var p = new Person();
Funciones predefinidas
JavaScript tiene integradas varias funciones de nivel superior:
eval()
El método
eval()
evalúa el código JavaScript representado como una cadena.uneval()
El método
uneval()
crea una representación de cadena del código fuente de unObject
.isFinite()
La función global
isFinite()
determina si el valor pasado es un número finito. Si es necesario, el parámetro, primero se convierte en un número.isNaN()
La función
isNaN()
determina si un valor esNaN
o no.Nota: La coerción dentro de la funciónisNaN
tieneinteresantes
reglas; también puedes querer usarNumber.isNaN()
, como se define en ECMAScript 2015, o puedes usartypeof
para determinar si el valor no es un número (NaN
).parseFloat()
La función
parseFloat()
procesa un argumento de cadena y devuelve un número de punto flotante.parseInt()
La función
parseInt()
procesa un argumento de cadena y devuelve un número entero de la base especificada (la base en los sistemas numéricos matemáticos).decodeURI()
La función
decodeURI()
decodifica un identificador uniforme de recursos (URI) creado previamente porencodeURI
o por una rutina similar.decodeURIComponent()
El método
decodeURIComponent()
decodifica un componente Identificador uniforme de recursos (URI) creado previamente porencodeURIComponent
o por un rutina similar.encodeURI()
El método
encodeURI()
codifica un identificador uniforme de recursos (URI) reemplazando cada instancia de ciertos caracteres por una, dos, tres o cuatro secuencias de escape que representan la codificación UTF-8 del caracter (solo habrá cuatro secuencias de escape para caracteres compuestos por dos caracteres "sustitutos").encodeURIComponent()
El método
encodeURIComponent()
codifica un componente Identificador uniforme de recursos (URI) reemplazando cada instancia de ciertos caracteres por una, dos, tres o cuatro secuencias de escape que representan la codificación UTF-8 del caracter (solo habrá cuatro secuencias de escape para caracteres compuestos por dos caracteres "sustitutos").escape()
El método obsoleto
escape()
calcula una nueva cadena en la que ciertos caracteres han sido reemplazados por una secuencia de escape hexadecimal. En su lugar usaencodeURI
oencodeURIComponent
.unescape()
El método obsoleto
unescape()
calcula una nueva cadena en la que las secuencias de escape hexadecimales se reemplazan con el caracter que representan. Las secuencias de escape se pueden introducir por medio de una función comoescape
. Debido a queunescape()
está en desuso, usadecodeURI()
odecodeURIComponent
en su lugar.